mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-03 12:35:58 +00:00
Bug 1315105 - Part 2: Implement <link rel=prerender> behind a pref, r=smaug
MozReview-Commit-ID: ARET98o1FTU --HG-- extra : rebase_source : fd549baa1a4a180db1ca6701191f081033811d0f
This commit is contained in:
parent
3244cf77dd
commit
0fa642800b
@ -607,6 +607,97 @@ addMessageListener("Browser:AppTab", function(message) {
|
||||
}
|
||||
});
|
||||
|
||||
let PrerenderContentHandler = {
|
||||
init() {
|
||||
this._pending = [];
|
||||
this._idMonotonic = 0;
|
||||
this._initialized = true;
|
||||
addMessageListener("Prerender:Canceled", this);
|
||||
addMessageListener("Prerender:Swapped", this);
|
||||
},
|
||||
|
||||
get initialized() {
|
||||
return !!this._initialized;
|
||||
},
|
||||
|
||||
receiveMessage(aMessage) {
|
||||
switch (aMessage.name) {
|
||||
case "Prerender:Canceled": {
|
||||
for (let i = 0; i < this._pending.length; ++i) {
|
||||
if (this._pending[i].id === aMessage.data.id) {
|
||||
if (this._pending[i].failure) {
|
||||
this._pending[i].failure.run();
|
||||
}
|
||||
// Remove the item from the array
|
||||
this._pending.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "Prerender:Swapped": {
|
||||
for (let i = 0; i < this._pending.length; ++i) {
|
||||
if (this._pending[i].id === aMessage.data.id) {
|
||||
if (this._pending[i].success) {
|
||||
this._pending[i].success.run();
|
||||
}
|
||||
// Remove the item from the array
|
||||
this._pending.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
startPrerenderingDocument(aHref, aReferrer) {
|
||||
// XXX: Make this constant a pref
|
||||
if (this._pending.length >= 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
let id = ++this._idMonotonic;
|
||||
sendAsyncMessage("Prerender:Request", {
|
||||
href: aHref.spec,
|
||||
referrer: aReferrer ? aReferrer.spec : null,
|
||||
id: id,
|
||||
});
|
||||
|
||||
this._pending.push({
|
||||
href: aHref,
|
||||
referrer: aReferrer,
|
||||
id: id,
|
||||
success: null,
|
||||
failure: null,
|
||||
});
|
||||
},
|
||||
|
||||
shouldSwitchToPrerenderedDocument(aHref, aReferrer, aSuccess, aFailure) {
|
||||
// Check if we think there is a prerendering document pending for the given
|
||||
// href and referrer. If we think there is one, we will send a message to
|
||||
// the parent process asking it to do a swap, and hook up the success and
|
||||
// failure listeners.
|
||||
for (let i = 0; i < this._pending.length; ++i) {
|
||||
let p = this._pending[i];
|
||||
if (p.href.equals(aHref) && p.referrer.equals(aReferrer)) {
|
||||
p.success = aSuccess;
|
||||
p.failure = aFailure;
|
||||
sendAsyncMessage("Prerender:Swap", {id: p.id});
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT) {
|
||||
// We only want to initialize the PrerenderContentHandler in the content
|
||||
// process. Outside of the content process, this should be unused.
|
||||
PrerenderContentHandler.init();
|
||||
}
|
||||
|
||||
var WebBrowserChrome = {
|
||||
onBeforeLinkTraversal: function(originalTarget, linkURI, linkNode, isAppTab) {
|
||||
return BrowserUtils.onBeforeLinkTraversal(originalTarget, linkURI, linkNode, isAppTab);
|
||||
@ -630,6 +721,20 @@ var WebBrowserChrome = {
|
||||
reloadInFreshProcess: function(aDocShell, aURI, aReferrer) {
|
||||
E10SUtils.redirectLoad(aDocShell, aURI, aReferrer, true);
|
||||
return true;
|
||||
},
|
||||
|
||||
startPrerenderingDocument: function(aHref, aReferrer) {
|
||||
if (PrerenderContentHandler.initialized) {
|
||||
PrerenderContentHandler.startPrerenderingDocument(aHref, aReferrer);
|
||||
}
|
||||
},
|
||||
|
||||
shouldSwitchToPrerenderedDocument: function(aHref, aReferrer, aSuccess, aFailure) {
|
||||
if (PrerenderContentHandler.initialized) {
|
||||
return PrerenderContentHandler.shouldSwitchToPrerenderedDocument(
|
||||
aHref, aReferrer, aSuccess, aFailure);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1500,6 +1500,7 @@
|
||||
<parameter name="aPostData"/>
|
||||
<parameter name="aLoadInBackground"/>
|
||||
<parameter name="aAllowThirdPartyFixup"/>
|
||||
<parameter name="aIsPrerendered"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
var aReferrerPolicy;
|
||||
@ -1535,6 +1536,7 @@
|
||||
aRelatedBrowser = params.relatedBrowser;
|
||||
aOriginPrincipal = params.originPrincipal;
|
||||
aOpener = params.opener;
|
||||
aIsPrerendered = params.isPrerendered;
|
||||
}
|
||||
|
||||
var bgLoad = (aLoadInBackground != null) ? aLoadInBackground :
|
||||
@ -1557,7 +1559,8 @@
|
||||
userContextId: aUserContextId,
|
||||
originPrincipal: aOriginPrincipal,
|
||||
relatedBrowser: aRelatedBrowser,
|
||||
opener: aOpener });
|
||||
opener: aOpener,
|
||||
isPrerendered: aIsPrerendered });
|
||||
if (!bgLoad)
|
||||
this.selectedTab = tab;
|
||||
|
||||
@ -1935,7 +1938,7 @@
|
||||
<![CDATA[
|
||||
// Supported parameters:
|
||||
// userContextId, remote, remoteType, isPreloadBrowser,
|
||||
// uriIsAboutBlank, permanentKey
|
||||
// uriIsAboutBlank, permanentKey, isPrerendered
|
||||
|
||||
const NS_XUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
|
||||
@ -1947,6 +1950,10 @@
|
||||
b.setAttribute("contextmenu", this.getAttribute("contentcontextmenu"));
|
||||
b.setAttribute("tooltip", this.getAttribute("contenttooltip"));
|
||||
|
||||
if (aParams.isPrerendered) {
|
||||
b.setAttribute("prerendered", "true");
|
||||
}
|
||||
|
||||
if (aParams.userContextId) {
|
||||
b.setAttribute("usercontextid", aParams.userContextId);
|
||||
}
|
||||
@ -2035,7 +2042,7 @@
|
||||
"use strict";
|
||||
|
||||
// Supported parameters:
|
||||
// forceNotRemote, preferredRemoteType, userContextId
|
||||
// forceNotRemote, preferredRemoteType, userContextId, isPrerendered
|
||||
|
||||
let uriIsAboutBlank = !aURI || aURI == "about:blank";
|
||||
|
||||
@ -2068,7 +2075,8 @@
|
||||
uriIsAboutBlank: uriIsAboutBlank,
|
||||
userContextId: aParams.userContextId,
|
||||
relatedBrowser: aParams.relatedBrowser,
|
||||
opener: aParams.opener});
|
||||
opener: aParams.opener,
|
||||
isPrerendered: aParams.isPrerendered});
|
||||
}
|
||||
|
||||
let notificationbox = this.getNotificationBox(browser);
|
||||
@ -2128,6 +2136,7 @@
|
||||
<parameter name="aPostData"/>
|
||||
<parameter name="aOwner"/>
|
||||
<parameter name="aAllowThirdPartyFixup"/>
|
||||
<parameter name="aIsPrerendered"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
"use strict";
|
||||
@ -2170,6 +2179,7 @@
|
||||
aOriginPrincipal = params.originPrincipal;
|
||||
aDisallowInheritPrincipal = params.disallowInheritPrincipal;
|
||||
aOpener = params.opener;
|
||||
aIsPrerendered = params.isPrerendered;
|
||||
}
|
||||
|
||||
// if we're adding tabs, we're past interrupt mode, ditch the owner
|
||||
@ -2187,6 +2197,10 @@
|
||||
t.setAttribute("label", aURI);
|
||||
}
|
||||
|
||||
if (aIsPrerendered) {
|
||||
t.setAttribute("hidden", "true");
|
||||
}
|
||||
|
||||
if (aUserContextId) {
|
||||
t.setAttribute("usercontextid", aUserContextId);
|
||||
ContextualIdentityService.setTabStyle(t);
|
||||
@ -2239,6 +2253,7 @@
|
||||
userContextId: aUserContextId,
|
||||
relatedBrowser: aRelatedBrowser,
|
||||
opener: aOpener,
|
||||
isPrerendered: aIsPrerendered,
|
||||
};
|
||||
let { usingPreloadedContent } = this._linkBrowserToTab(t, aURI, browserParams);
|
||||
let b = t.linkedBrowser;
|
||||
@ -4790,6 +4805,74 @@
|
||||
break;
|
||||
}
|
||||
|
||||
case "Prerender:Request": {
|
||||
let sendCancelPrerendering = () => {
|
||||
browser.frameloader.messageManager.
|
||||
sendAsyncMessage("Prerender:Canceled", { id: data.id });
|
||||
};
|
||||
|
||||
let tab = this.getTabForBrowser(browser);
|
||||
if (!tab) {
|
||||
// No tab?
|
||||
sendCancelPrerendering();
|
||||
break;
|
||||
}
|
||||
|
||||
if (tab.hidden) {
|
||||
// Skip prerender on hidden tab.
|
||||
sendCancelPrerendering();
|
||||
break;
|
||||
}
|
||||
|
||||
if (browser.canGoForward) {
|
||||
// Skip prerender on history navigation as we don't support it
|
||||
// yet. Remove this check once bug 1323650 is implemented.
|
||||
sendCancelPrerendering();
|
||||
break;
|
||||
}
|
||||
|
||||
if (!data.href) {
|
||||
// If we don't have data.href, loadOneTab will load about:blank
|
||||
// which is meaningless for prerendering.
|
||||
sendCancelPrerendering();
|
||||
break;
|
||||
}
|
||||
|
||||
let groupedSHistory = browser.frameLoader.ensureGroupedSHistory();
|
||||
|
||||
let newTab = this.loadOneTab(data.href, {
|
||||
referrerURI: (data.referrer ? makeURI(data.referrer) : null),
|
||||
referrerPolicy: Ci.nsIHttpChannel.REFERRER_POLICY_DEFAULT,
|
||||
postData: null,
|
||||
allowThirdPartyFixup: true,
|
||||
relatedToCurrent: true,
|
||||
isPrerendered: true,
|
||||
});
|
||||
let partialSHistory = newTab.linkedBrowser.frameLoader.partialSessionHistory;
|
||||
groupedSHistory.addPrerenderingPartialSHistory(partialSHistory, data.id);
|
||||
break;
|
||||
}
|
||||
|
||||
case "Prerender:Cancel": {
|
||||
let groupedSHistory = browser.frameLoader.groupedSessionHistory;
|
||||
if (groupedSHistory) {
|
||||
groupedSHistory.cancelPrerendering(data.id);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case "Prerender:Swap": {
|
||||
let frameloader = browser.frameLoader;
|
||||
let groupedSHistory = browser.frameLoader.groupedSessionHistory;
|
||||
if (groupedSHistory) {
|
||||
groupedSHistory.activatePrerendering(data.id).then(
|
||||
() => frameloader.messageManager.sendAsyncMessage("Prerender:Swapped", data),
|
||||
() => frameloader.messageManager.sendAsyncMessage("Prerender:Canceled", data),
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return undefined;
|
||||
]]></body>
|
||||
@ -4922,6 +5005,11 @@
|
||||
this._findAsYouType = Services.prefs.getBoolPref("accessibility.typeaheadfind");
|
||||
Services.prefs.addObserver("accessibility.typeaheadfind", this, false);
|
||||
messageManager.addMessageListener("Findbar:Keypress", this);
|
||||
|
||||
// Add listeners for prerender messages
|
||||
messageManager.addMessageListener("Prerender:Request", this);
|
||||
messageManager.addMessageListener("Prerender:Cancel", this);
|
||||
messageManager.addMessageListener("Prerender:Swap", this);
|
||||
]]>
|
||||
</constructor>
|
||||
|
||||
|
@ -1575,6 +1575,7 @@ nsDocShell::LoadURI(nsIURI* aURI,
|
||||
srcdoc,
|
||||
sourceDocShell,
|
||||
baseURI,
|
||||
false,
|
||||
nullptr, // No nsIDocShell
|
||||
nullptr); // No nsIRequest
|
||||
}
|
||||
@ -5367,8 +5368,8 @@ nsDocShell::LoadErrorPage(nsIURI* aURI, const char16_t* aURL,
|
||||
nsContentUtils::GetSystemPrincipal(), nullptr,
|
||||
INTERNAL_LOAD_FLAGS_NONE, EmptyString(),
|
||||
nullptr, NullString(), nullptr, nullptr, LOAD_ERROR_PAGE,
|
||||
nullptr, true, NullString(), this, nullptr, nullptr,
|
||||
nullptr);
|
||||
nullptr, true, NullString(), this, nullptr, false,
|
||||
nullptr, nullptr);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -5460,6 +5461,7 @@ nsDocShell::Reload(uint32_t aReloadFlags)
|
||||
srcdoc, // srcdoc argument for iframe
|
||||
this, // For reloads we are the source
|
||||
baseURI,
|
||||
false,
|
||||
nullptr, // No nsIDocShell
|
||||
nullptr); // No nsIRequest
|
||||
}
|
||||
@ -7956,7 +7958,8 @@ nsDocShell::EnsureContentViewer()
|
||||
nsresult
|
||||
nsDocShell::CreateAboutBlankContentViewer(nsIPrincipal* aPrincipal,
|
||||
nsIURI* aBaseURI,
|
||||
bool aTryToSaveOldPresentation)
|
||||
bool aTryToSaveOldPresentation,
|
||||
bool aCheckPermitUnload)
|
||||
{
|
||||
nsCOMPtr<nsIDocument> blankDoc;
|
||||
nsCOMPtr<nsIContentViewer> viewer;
|
||||
@ -7989,31 +7992,32 @@ nsDocShell::CreateAboutBlankContentViewer(nsIPrincipal* aPrincipal,
|
||||
bool hadTiming = mTiming;
|
||||
bool toBeReset = MaybeInitTiming();
|
||||
if (mContentViewer) {
|
||||
// We've got a content viewer already. Make sure the user
|
||||
// permits us to discard the current document and replace it
|
||||
// with about:blank. And also ensure we fire the unload events
|
||||
// in the current document.
|
||||
if (aCheckPermitUnload) {
|
||||
// We've got a content viewer already. Make sure the user
|
||||
// permits us to discard the current document and replace it
|
||||
// with about:blank. And also ensure we fire the unload events
|
||||
// in the current document.
|
||||
|
||||
// Unload gets fired first for
|
||||
// document loaded from the session history.
|
||||
mTiming->NotifyBeforeUnload();
|
||||
// Unload gets fired first for
|
||||
// document loaded from the session history.
|
||||
mTiming->NotifyBeforeUnload();
|
||||
|
||||
bool okToUnload;
|
||||
rv = mContentViewer->PermitUnload(&okToUnload);
|
||||
bool okToUnload;
|
||||
rv = mContentViewer->PermitUnload(&okToUnload);
|
||||
|
||||
if (NS_SUCCEEDED(rv) && !okToUnload) {
|
||||
// The user chose not to unload the page, interrupt the load.
|
||||
MaybeResetInitTiming(toBeReset);
|
||||
return NS_ERROR_FAILURE;
|
||||
if (NS_SUCCEEDED(rv) && !okToUnload) {
|
||||
// The user chose not to unload the page, interrupt the load.
|
||||
MaybeResetInitTiming(toBeReset);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
if (mTiming) {
|
||||
mTiming->NotifyUnloadAccepted(mCurrentURI);
|
||||
}
|
||||
}
|
||||
|
||||
mSavingOldViewer = aTryToSaveOldPresentation &&
|
||||
CanSavePresentation(LOAD_NORMAL, nullptr, nullptr);
|
||||
|
||||
if (mTiming) {
|
||||
mTiming->NotifyUnloadAccepted(mCurrentURI);
|
||||
}
|
||||
|
||||
// Make sure to blow away our mLoadingURI just in case. No loads
|
||||
// from inside this pagehide.
|
||||
mLoadingURI = nullptr;
|
||||
@ -8097,6 +8101,12 @@ nsDocShell::CreateAboutBlankContentViewer(nsIPrincipal* aPrincipal)
|
||||
return CreateAboutBlankContentViewer(aPrincipal, nullptr);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocShell::ForceCreateAboutBlankContentViewer(nsIPrincipal* aPrincipal)
|
||||
{
|
||||
return CreateAboutBlankContentViewer(aPrincipal, nullptr, true, false);
|
||||
}
|
||||
|
||||
bool
|
||||
nsDocShell::CanSavePresentation(uint32_t aLoadType,
|
||||
nsIRequest* aNewRequest,
|
||||
@ -9578,7 +9588,7 @@ public:
|
||||
nsIInputStream* aHeadersData, uint32_t aLoadType,
|
||||
nsISHEntry* aSHEntry, bool aFirstParty,
|
||||
const nsAString& aSrcdoc, nsIDocShell* aSourceDocShell,
|
||||
nsIURI* aBaseURI)
|
||||
nsIURI* aBaseURI, bool aCheckForPrerender)
|
||||
: mSrcdoc(aSrcdoc)
|
||||
, mDocShell(aDocShell)
|
||||
, mURI(aURI)
|
||||
@ -9596,6 +9606,7 @@ public:
|
||||
, mFirstParty(aFirstParty)
|
||||
, mSourceDocShell(aSourceDocShell)
|
||||
, mBaseURI(aBaseURI)
|
||||
, mCheckForPrerender(aCheckForPrerender)
|
||||
{
|
||||
// Make sure to keep null things null as needed
|
||||
if (aTypeHint) {
|
||||
@ -9615,7 +9626,7 @@ public:
|
||||
NullString(), mPostData, mHeadersData,
|
||||
mLoadType, mSHEntry, mFirstParty,
|
||||
mSrcdoc, mSourceDocShell, mBaseURI,
|
||||
nullptr, nullptr);
|
||||
mCheckForPrerender, nullptr, nullptr);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -9640,6 +9651,7 @@ private:
|
||||
bool mFirstParty;
|
||||
nsCOMPtr<nsIDocShell> mSourceDocShell;
|
||||
nsCOMPtr<nsIURI> mBaseURI;
|
||||
bool mCheckForPrerender;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -9712,6 +9724,7 @@ nsDocShell::InternalLoad(nsIURI* aURI,
|
||||
const nsAString& aSrcdoc,
|
||||
nsIDocShell* aSourceDocShell,
|
||||
nsIURI* aBaseURI,
|
||||
bool aCheckForPrerender,
|
||||
nsIDocShell** aDocShell,
|
||||
nsIRequest** aRequest)
|
||||
{
|
||||
@ -10071,6 +10084,7 @@ nsDocShell::InternalLoad(nsIURI* aURI,
|
||||
aSrcdoc,
|
||||
aSourceDocShell,
|
||||
aBaseURI,
|
||||
aCheckForPrerender,
|
||||
aDocShell,
|
||||
aRequest);
|
||||
if (rv == NS_ERROR_NO_CONTENT) {
|
||||
@ -10141,7 +10155,7 @@ nsDocShell::InternalLoad(nsIURI* aURI,
|
||||
aTriggeringPrincipal, principalToInherit,
|
||||
aFlags, aTypeHint, aPostData, aHeadersData,
|
||||
aLoadType, aSHEntry, aFirstParty, aSrcdoc,
|
||||
aSourceDocShell, aBaseURI);
|
||||
aSourceDocShell, aBaseURI, false);
|
||||
return NS_DispatchToCurrentThread(ev);
|
||||
}
|
||||
|
||||
@ -10528,6 +10542,25 @@ nsDocShell::InternalLoad(nsIURI* aURI,
|
||||
mTiming->NotifyUnloadAccepted(mCurrentURI);
|
||||
}
|
||||
|
||||
if (browserChrome3 && aCheckForPrerender) {
|
||||
nsCOMPtr<nsIRunnable> ev =
|
||||
new InternalLoadEvent(this, aURI, aOriginalURI, aLoadReplace,
|
||||
aReferrer, aReferrerPolicy,
|
||||
aTriggeringPrincipal, principalToInherit,
|
||||
aFlags, aTypeHint, aPostData, aHeadersData,
|
||||
aLoadType, aSHEntry, aFirstParty, aSrcdoc,
|
||||
aSourceDocShell, aBaseURI, false);
|
||||
// We don't need any success handler since in that case
|
||||
// OnPartialSessionHistoryDeactive would be called, and it would ensure
|
||||
// docshell loads about:blank.
|
||||
bool shouldSwitch = false;
|
||||
rv = browserChrome3->ShouldSwitchToPrerenderedDocument(
|
||||
aURI, mCurrentURI, nullptr, ev, &shouldSwitch);
|
||||
if (NS_SUCCEEDED(rv) && shouldSwitch) {
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// Whenever a top-level browsing context is navigated, the user agent MUST
|
||||
// lock the orientation of the document to the document's default
|
||||
// orientation. We don't explicitly check for a top-level browsing context
|
||||
@ -12531,6 +12564,7 @@ nsDocShell::LoadHistoryEntry(nsISHEntry* aEntry, uint32_t aLoadType)
|
||||
srcdoc,
|
||||
nullptr, // Source docshell, see comment above
|
||||
baseURI,
|
||||
false,
|
||||
nullptr, // No nsIDocShell
|
||||
nullptr); // No nsIRequest
|
||||
return rv;
|
||||
@ -14036,6 +14070,7 @@ nsDocShell::OnLinkClickSync(nsIContent* aContent,
|
||||
NullString(), // No srcdoc
|
||||
this, // We are the source
|
||||
nullptr, // baseURI not needed
|
||||
true, // Check for prerendered doc
|
||||
aDocShell, // DocShell out-param
|
||||
aRequest); // Request out-param
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
@ -14702,6 +14737,14 @@ nsDocShell::GetCommandManager()
|
||||
return mCommandManager;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocShell::GetIsProcessLocked(bool* aIsLocked)
|
||||
{
|
||||
MOZ_ASSERT(aIsLocked);
|
||||
*aIsLocked = GetProcessLockReason() != PROCESS_LOCK_NONE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocShell::GetProcessLockReason(uint32_t* aReason)
|
||||
{
|
||||
|
@ -331,7 +331,8 @@ protected:
|
||||
// passed in, the about:blank principal will end up being used.
|
||||
nsresult CreateAboutBlankContentViewer(nsIPrincipal* aPrincipal,
|
||||
nsIURI* aBaseURI,
|
||||
bool aTryToSaveOldPresentation = true);
|
||||
bool aTryToSaveOldPresentation = true,
|
||||
bool aCheckPermitUnload = true);
|
||||
nsresult CreateContentViewer(const nsACString& aContentType,
|
||||
nsIRequest* aRequest,
|
||||
nsIStreamListener** aContentHandler);
|
||||
|
@ -187,10 +187,11 @@ interface nsIDocShell : nsIDocShellTreeItem
|
||||
in nsIInputStream aHeadersStream,
|
||||
in unsigned long aLoadFlags,
|
||||
in nsISHEntry aSHEntry,
|
||||
in boolean firstParty,
|
||||
in boolean aFirstParty,
|
||||
in AString aSrcdoc,
|
||||
in nsIDocShell aSourceDocShell,
|
||||
in nsIURI aBaseURI,
|
||||
in boolean aCheckForPrerender,
|
||||
out nsIDocShell aDocShell,
|
||||
out nsIRequest aRequest);
|
||||
|
||||
@ -673,6 +674,13 @@ interface nsIDocShell : nsIDocShellTreeItem
|
||||
*/
|
||||
void createAboutBlankContentViewer(in nsIPrincipal aPrincipal);
|
||||
|
||||
/**
|
||||
* Like createAboutBlankContentViewer, but don't check for permit unload.
|
||||
* Only used by special session history operation.
|
||||
* @param aPrincipal the principal to use for the new document.
|
||||
*/
|
||||
[noscript] void forceCreateAboutBlankContentViewer(in nsIPrincipal aPrincipal);
|
||||
|
||||
/**
|
||||
* Upon getting, returns the canonical encoding label of the document
|
||||
* currently loaded into this docshell.
|
||||
@ -1107,7 +1115,12 @@ interface nsIDocShell : nsIDocShellTreeItem
|
||||
* A DocShell is locked to the current process if it would be
|
||||
* content-observable for a process switch to occur before performing a
|
||||
* navigation load. It is important to ensure that a DocShell is not process
|
||||
* locked before perfoming process changing loads.
|
||||
* locked before performing process changing loads.
|
||||
*/
|
||||
[infallible] readonly attribute boolean isProcessLocked;
|
||||
/**
|
||||
* Return PROCESS_LOCK_NONE if docShell is not locked to current process,
|
||||
* otherwise return the reason why process is locked.
|
||||
*/
|
||||
[infallible] readonly attribute unsigned long processLockReason;
|
||||
/**
|
||||
|
@ -510,7 +510,10 @@ nsSHistory::OnPartialSessionHistoryDeactive()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (NS_FAILED(mRootDocShell->CreateAboutBlankContentViewer(nullptr))) {
|
||||
// At this point we've swapped out to an invisble tab, and can not prompt here.
|
||||
// The check should have been done in nsDocShell::InternalLoad, so we'd
|
||||
// just force docshell to load about:blank.
|
||||
if (NS_FAILED(mRootDocShell->ForceCreateAboutBlankContentViewer(nullptr))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
|
@ -225,7 +225,16 @@ GroupedSHistory::PurgePartialHistories(uint32_t aLastPartialIndexToKeep)
|
||||
|
||||
/* static */ bool
|
||||
GroupedSHistory::GroupedHistoryEnabled() {
|
||||
return Preferences::GetBool("browser.groupedhistory.enabled", false);
|
||||
static bool sGroupedSHistoryEnabled = false;
|
||||
static bool sGroupedSHistoryPrefCached = false;
|
||||
if (!sGroupedSHistoryPrefCached) {
|
||||
sGroupedSHistoryPrefCached = true;
|
||||
Preferences::AddBoolVarCache(&sGroupedSHistoryEnabled,
|
||||
"browser.groupedhistory.enabled",
|
||||
false);
|
||||
}
|
||||
|
||||
return sGroupedSHistoryEnabled;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -85,7 +85,7 @@ Link::CancelDNSPrefetch(nsWrapperCache::FlagsType aDeferredFlag,
|
||||
}
|
||||
|
||||
void
|
||||
Link::TryDNSPrefetchPreconnectOrPrefetch()
|
||||
Link::TryDNSPrefetchPreconnectOrPrefetchOrPrerender()
|
||||
{
|
||||
MOZ_ASSERT(mElement->IsInComposedDoc());
|
||||
if (!ElementHasHref()) {
|
||||
@ -128,6 +128,14 @@ Link::TryDNSPrefetchPreconnectOrPrefetch()
|
||||
}
|
||||
}
|
||||
|
||||
if (linkTypes & nsStyleLinkElement::ePRERENDER) {
|
||||
nsCOMPtr<nsIURI> uri(GetURI());
|
||||
if (uri && mElement->OwnerDoc()) {
|
||||
mElement->OwnerDoc()->PrerenderHref(uri);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (linkTypes & nsStyleLinkElement::eDNS_PREFETCH) {
|
||||
if (nsHTMLDNSPrefetch::IsAllowed(mElement->OwnerDoc())) {
|
||||
nsHTMLDNSPrefetch::PrefetchLow(this);
|
||||
|
@ -123,7 +123,7 @@ public:
|
||||
nsWrapperCache::FlagsType aRequestedFlag);
|
||||
|
||||
// This is called by HTMLLinkElement.
|
||||
void TryDNSPrefetchPreconnectOrPrefetch();
|
||||
void TryDNSPrefetchPreconnectOrPrefetchOrPrerender();
|
||||
void CancelPrefetch();
|
||||
|
||||
protected:
|
||||
|
@ -716,6 +716,14 @@ nsContentSink::ProcessLink(const nsSubstring& aAnchor, const nsSubstring& aHref,
|
||||
PrefetchHref(aHref, mDocument, hasPrefetch);
|
||||
}
|
||||
|
||||
if (linkTypes & nsStyleLinkElement::ePRERENDER) {
|
||||
nsCOMPtr<nsIURI> href;
|
||||
nsresult rv = NS_NewURI(getter_AddRefs(href), aHref);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mDocument->PrerenderHref(href);
|
||||
}
|
||||
}
|
||||
|
||||
if (!aHref.IsEmpty() && (linkTypes & nsStyleLinkElement::eDNS_PREFETCH)) {
|
||||
PrefetchDNS(aHref);
|
||||
}
|
||||
|
@ -2918,6 +2918,73 @@ nsIDocument::IsScriptTracking(const nsACString& aURL) const
|
||||
return mTrackingScripts.Contains(aURL);
|
||||
}
|
||||
|
||||
bool
|
||||
nsIDocument::PrerenderHref(nsIURI* aHref)
|
||||
{
|
||||
MOZ_ASSERT(aHref);
|
||||
|
||||
static bool sPrerenderEnabled = false;
|
||||
static bool sPrerenderPrefCached = false;
|
||||
if (!sPrerenderPrefCached) {
|
||||
sPrerenderPrefCached = true;
|
||||
Preferences::AddBoolVarCache(&sPrerenderEnabled,
|
||||
"dom.linkPrerender.enabled",
|
||||
false);
|
||||
}
|
||||
|
||||
// Check if prerender is enabled
|
||||
if (!sPrerenderEnabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> referrer = GetDocumentURI();
|
||||
bool urisMatch = false;
|
||||
aHref->EqualsExceptRef(referrer, &urisMatch);
|
||||
if (urisMatch) {
|
||||
// Prerender current document isn't quite meaningful, and we may not be able
|
||||
// to load it out of process.
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocShell> docShell = GetDocShell();
|
||||
nsCOMPtr<nsIWebNavigation> webNav = do_QueryInterface(docShell);
|
||||
NS_ENSURE_TRUE(webNav, false);
|
||||
|
||||
bool canGoForward = false;
|
||||
nsresult rv = webNav->GetCanGoForward(&canGoForward);
|
||||
if (NS_FAILED(rv) || canGoForward) {
|
||||
// Skip prerender on history navigation as we don't support it yet.
|
||||
// Remove this check once bug 1323650 is implemented.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the document is in prerender state. We don't prerender in a
|
||||
// prerendered document.
|
||||
if (docShell->GetIsPrerendered()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Adopting an out-of-process prerendered document is conceptually similar to
|
||||
// switching dochshell's process, since it's the same browsing context from
|
||||
// other browsing contexts' perspective. If we're locked in current process,
|
||||
// we can not prerender out-of-process.
|
||||
if (docShell->GetIsProcessLocked()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TabChild* tabChild = TabChild::GetFrom(docShell);
|
||||
NS_ENSURE_TRUE(tabChild, false);
|
||||
|
||||
nsCOMPtr<nsIWebBrowserChrome3> wbc3;
|
||||
tabChild->GetWebBrowserChrome(getter_AddRefs(wbc3));
|
||||
NS_ENSURE_TRUE(wbc3, false);
|
||||
|
||||
rv = wbc3->StartPrerenderingDocument(aHref, referrer);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocument::GetApplicationCache(nsIApplicationCache **aApplicationCache)
|
||||
{
|
||||
|
@ -2881,6 +2881,8 @@ public:
|
||||
void NoteScriptTrackingStatus(const nsACString& aURL, bool isTracking);
|
||||
bool IsScriptTracking(const nsACString& aURL) const;
|
||||
|
||||
bool PrerenderHref(nsIURI* aHref);
|
||||
|
||||
protected:
|
||||
bool GetUseCounter(mozilla::UseCounter aUseCounter)
|
||||
{
|
||||
|
@ -162,7 +162,9 @@ static uint32_t ToLinkMask(const nsAString& aLink, nsIPrincipal* aPrincipal)
|
||||
return nsStyleLinkElement::eHTMLIMPORT;
|
||||
else if (aLink.EqualsLiteral("preconnect"))
|
||||
return nsStyleLinkElement::ePRECONNECT;
|
||||
else
|
||||
else if (aLink.EqualsLiteral("prerender"))
|
||||
return nsStyleLinkElement::ePRERENDER;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -63,7 +63,8 @@ public:
|
||||
eNEXT = 0x00000008,
|
||||
eALTERNATE = 0x00000010,
|
||||
eHTMLIMPORT = 0x00000020,
|
||||
ePRECONNECT = 0x00000040
|
||||
ePRECONNECT = 0x00000040,
|
||||
ePRERENDER = 0x00000080
|
||||
};
|
||||
|
||||
// The return value is a bitwise or of 0 or more RelValues.
|
||||
|
@ -169,7 +169,7 @@ HTMLLinkElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
}
|
||||
|
||||
if (IsInComposedDoc()) {
|
||||
TryDNSPrefetchPreconnectOrPrefetch();
|
||||
TryDNSPrefetchPreconnectOrPrefetchOrPrerender();
|
||||
}
|
||||
|
||||
void (HTMLLinkElement::*update)() = &HTMLLinkElement::UpdateStyleSheetInternal;
|
||||
@ -389,7 +389,7 @@ HTMLLinkElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
|
||||
if ((aName == nsGkAtoms::rel || aName == nsGkAtoms::href) &&
|
||||
IsInComposedDoc()) {
|
||||
TryDNSPrefetchPreconnectOrPrefetch();
|
||||
TryDNSPrefetchPreconnectOrPrefetchOrPrerender();
|
||||
}
|
||||
|
||||
UpdateStyleSheetInternal(nullptr, nullptr,
|
||||
|
@ -108,8 +108,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1069772
|
||||
|
||||
function makePrerenderedBrowserActive(browser) {
|
||||
let promise = waitForVisibilityChange(browser);
|
||||
browser.setAttribute('prerendered', false);
|
||||
browser.makePrerenderedBrowserActive();
|
||||
browser.removeAttribute('prerendered');
|
||||
browser.frameLoader.makePrerenderedLoaderActive();
|
||||
return promise.then(() => browser);
|
||||
}
|
||||
|
||||
|
@ -71,7 +71,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1271240
|
||||
}
|
||||
|
||||
function makePrerenderedBrowserActive(browser) {
|
||||
browser.makePrerenderedBrowserActive();
|
||||
browser.frameLoader.makePrerenderedLoaderActive();
|
||||
return browser;
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
interface nsIDocShell;
|
||||
interface nsIInputStream;
|
||||
interface nsIRunnable;
|
||||
|
||||
/**
|
||||
* nsIWebBrowserChrome3 is an extension to nsIWebBrowserChrome2.
|
||||
@ -60,4 +61,36 @@ interface nsIWebBrowserChrome3 : nsIWebBrowserChrome2
|
||||
bool reloadInFreshProcess(in nsIDocShell aDocShell,
|
||||
in nsIURI aURI,
|
||||
in nsIURI aReferrer);
|
||||
|
||||
/**
|
||||
* Tell the browser to start prerendering the given document. This prerendering
|
||||
* _must_ be for the toplevel document.
|
||||
*
|
||||
* @param aHref The URI to begin prerendering
|
||||
* @param aReferrer The URI of the document requesting the prerender.
|
||||
*/
|
||||
void startPrerenderingDocument(in nsIURI aHref, in nsIURI aReferrer);
|
||||
|
||||
/**
|
||||
* Check if there's a prerendered document which matches given URI /
|
||||
* referrer, and try to switch to the prerendered document immediately if
|
||||
* there is.
|
||||
*
|
||||
* @param aHref
|
||||
* The URI which is being loaded.
|
||||
* @param aReferrer
|
||||
* The referrer for the current load.
|
||||
* @param aSuccess
|
||||
* (Optional) a runnable which will be run if the swap is successful.
|
||||
* @param aFailure
|
||||
* (Optional) a runnable which will be run if the swap is not
|
||||
* successful. Note it's not invoked if the function returns false.
|
||||
*
|
||||
* @return True if there is a matched prerendered document to swap with,
|
||||
* false otherwise.
|
||||
*/
|
||||
bool shouldSwitchToPrerenderedDocument(in nsIURI aHref,
|
||||
in nsIURI aReferrer,
|
||||
in nsIRunnable aSuccess,
|
||||
in nsIRunnable aFailure);
|
||||
};
|
||||
|
@ -307,17 +307,6 @@
|
||||
</body>
|
||||
</method>
|
||||
|
||||
<method name="makePrerenderedBrowserActive">
|
||||
<body>
|
||||
<![CDATA[
|
||||
let frameLoader = this.QueryInterface(Components.interfaces.nsIFrameLoaderOwner).frameLoader;
|
||||
if (frameLoader) {
|
||||
frameLoader.makePrerenderedLoaderActive();
|
||||
}
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
||||
<property name="imageDocument"
|
||||
readonly="true">
|
||||
<getter>
|
||||
|
@ -423,6 +423,24 @@ NS_IMETHODIMP nsContentTreeOwner::ReloadInFreshProcess(nsIDocShell* aDocShell,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsContentTreeOwner::StartPrerenderingDocument(nsIURI* aHref,
|
||||
nsIURI* aReferrer)
|
||||
{
|
||||
NS_WARNING("Cannot prerender a document in the parent process");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsContentTreeOwner::ShouldSwitchToPrerenderedDocument(nsIURI* aHref,
|
||||
nsIURI* aReferrer,
|
||||
nsIRunnable* aSuccess,
|
||||
nsIRunnable* aFailure,
|
||||
bool* aRetval)
|
||||
{
|
||||
NS_WARNING("Cannot switch to prerendered document in the parent process");
|
||||
*aRetval = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
// nsContentTreeOwner::nsIWebBrowserChrome2
|
||||
//*****************************************************************************
|
||||
|
Loading…
x
Reference in New Issue
Block a user