mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-11-09 21:00:42 +02:00
This patch implements the code which is shared by all platforms for fullscreen transition. It adds two prefs for the duration of fullscreen transition. They can also be used to completely suppress the transition. In addition, this patch uses the newly added prefs to suppress the transition in all tests which use the DOM fullscreen. --HG-- extra : source : 54a8b3b7351af89049825598891fd3a1f98d18af
696 lines
21 KiB
JavaScript
696 lines
21 KiB
JavaScript
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
/* This content script contains code that requires a tab browser. */
|
|
|
|
let {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
|
|
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
|
Cu.import("resource://gre/modules/Services.jsm");
|
|
|
|
XPCOMUtils.defineLazyModuleGetter(this, "E10SUtils",
|
|
"resource:///modules/E10SUtils.jsm");
|
|
XPCOMUtils.defineLazyModuleGetter(this, "BrowserUtils",
|
|
"resource://gre/modules/BrowserUtils.jsm");
|
|
XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
|
|
"resource://gre/modules/PrivateBrowsingUtils.jsm");
|
|
XPCOMUtils.defineLazyModuleGetter(this, "AboutReader",
|
|
"resource://gre/modules/AboutReader.jsm");
|
|
XPCOMUtils.defineLazyModuleGetter(this, "ReaderMode",
|
|
"resource://gre/modules/ReaderMode.jsm");
|
|
XPCOMUtils.defineLazyGetter(this, "SimpleServiceDiscovery", function() {
|
|
let ssdp = Cu.import("resource://gre/modules/SimpleServiceDiscovery.jsm", {}).SimpleServiceDiscovery;
|
|
// Register targets
|
|
ssdp.registerDevice({
|
|
id: "roku:ecp",
|
|
target: "roku:ecp",
|
|
factory: function(aService) {
|
|
Cu.import("resource://gre/modules/RokuApp.jsm");
|
|
return new RokuApp(aService);
|
|
},
|
|
mirror: true,
|
|
types: ["video/mp4"],
|
|
extensions: ["mp4"]
|
|
});
|
|
return ssdp;
|
|
});
|
|
|
|
// TabChildGlobal
|
|
var global = this;
|
|
|
|
|
|
addMessageListener("Browser:HideSessionRestoreButton", function (message) {
|
|
// Hide session restore button on about:home
|
|
let doc = content.document;
|
|
let container;
|
|
if (doc.documentURI.toLowerCase() == "about:home" &&
|
|
(container = doc.getElementById("sessionRestoreContainer"))) {
|
|
container.hidden = true;
|
|
}
|
|
});
|
|
|
|
|
|
addMessageListener("Browser:Reload", function(message) {
|
|
/* First, we'll try to use the session history object to reload so
|
|
* that framesets are handled properly. If we're in a special
|
|
* window (such as view-source) that has no session history, fall
|
|
* back on using the web navigation's reload method.
|
|
*/
|
|
|
|
let webNav = docShell.QueryInterface(Ci.nsIWebNavigation);
|
|
try {
|
|
let sh = webNav.sessionHistory;
|
|
if (sh)
|
|
webNav = sh.QueryInterface(Ci.nsIWebNavigation);
|
|
} catch (e) {
|
|
}
|
|
|
|
let reloadFlags = message.data.flags;
|
|
let handlingUserInput;
|
|
try {
|
|
handlingUserInput = content.QueryInterface(Ci.nsIInterfaceRequestor)
|
|
.getInterface(Ci.nsIDOMWindowUtils)
|
|
.setHandlingUserInput(message.data.handlingUserInput);
|
|
webNav.reload(reloadFlags);
|
|
} catch (e) {
|
|
} finally {
|
|
handlingUserInput.destruct();
|
|
}
|
|
});
|
|
|
|
addMessageListener("MixedContent:ReenableProtection", function() {
|
|
docShell.mixedContentChannel = null;
|
|
});
|
|
|
|
addMessageListener("SecondScreen:tab-mirror", function(message) {
|
|
if (!Services.prefs.getBoolPref("browser.casting.enabled")) {
|
|
return;
|
|
}
|
|
let app = SimpleServiceDiscovery.findAppForService(message.data.service);
|
|
if (app) {
|
|
let width = content.innerWidth;
|
|
let height = content.innerHeight;
|
|
let viewport = {cssWidth: width, cssHeight: height, width: width, height: height};
|
|
app.mirror(function() {}, content, viewport, function() {}, content);
|
|
}
|
|
});
|
|
|
|
let AboutHomeListener = {
|
|
init: function(chromeGlobal) {
|
|
chromeGlobal.addEventListener('AboutHomeLoad', this, false, true);
|
|
},
|
|
|
|
get isAboutHome() {
|
|
return content.document.documentURI.toLowerCase() == "about:home";
|
|
},
|
|
|
|
handleEvent: function(aEvent) {
|
|
if (!this.isAboutHome) {
|
|
return;
|
|
}
|
|
switch (aEvent.type) {
|
|
case "AboutHomeLoad":
|
|
this.onPageLoad();
|
|
break;
|
|
case "AboutHomeSearchEvent":
|
|
this.onSearch(aEvent);
|
|
break;
|
|
case "AboutHomeSearchPanel":
|
|
this.onOpenSearchPanel(aEvent);
|
|
break;
|
|
case "click":
|
|
this.onClick(aEvent);
|
|
break;
|
|
case "pagehide":
|
|
this.onPageHide(aEvent);
|
|
break;
|
|
}
|
|
},
|
|
|
|
receiveMessage: function(aMessage) {
|
|
if (!this.isAboutHome) {
|
|
return;
|
|
}
|
|
switch (aMessage.name) {
|
|
case "AboutHome:Update":
|
|
this.onUpdate(aMessage.data);
|
|
break;
|
|
case "AboutHome:FocusInput":
|
|
this.onFocusInput();
|
|
break;
|
|
}
|
|
},
|
|
|
|
onUpdate: function(aData) {
|
|
let doc = content.document;
|
|
if (aData.showRestoreLastSession && !PrivateBrowsingUtils.isContentWindowPrivate(content))
|
|
doc.getElementById("launcher").setAttribute("session", "true");
|
|
|
|
// Inject search engine and snippets URL.
|
|
let docElt = doc.documentElement;
|
|
// set the following attributes BEFORE searchEngineName, which triggers to
|
|
// show the snippets when it's set.
|
|
docElt.setAttribute("snippetsURL", aData.snippetsURL);
|
|
if (aData.showKnowYourRights)
|
|
docElt.setAttribute("showKnowYourRights", "true");
|
|
docElt.setAttribute("snippetsVersion", aData.snippetsVersion);
|
|
docElt.setAttribute("searchEngineName", aData.defaultEngineName);
|
|
},
|
|
|
|
onPageLoad: function() {
|
|
let doc = content.document;
|
|
if (doc.documentElement.hasAttribute("hasBrowserHandlers")) {
|
|
return;
|
|
}
|
|
|
|
doc.documentElement.setAttribute("hasBrowserHandlers", "true");
|
|
addMessageListener("AboutHome:Update", this);
|
|
addMessageListener("AboutHome:FocusInput", this);
|
|
addEventListener("click", this, true);
|
|
addEventListener("pagehide", this, true);
|
|
|
|
if (!Services.prefs.getBoolPref("browser.search.showOneOffButtons")) {
|
|
doc.documentElement.setAttribute("searchUIConfiguration", "oldsearchui");
|
|
}
|
|
|
|
sendAsyncMessage("AboutHome:RequestUpdate");
|
|
doc.addEventListener("AboutHomeSearchEvent", this, true, true);
|
|
doc.addEventListener("AboutHomeSearchPanel", this, true, true);
|
|
},
|
|
|
|
onClick: function(aEvent) {
|
|
if (!aEvent.isTrusted || // Don't trust synthetic events
|
|
aEvent.button == 2 || aEvent.target.localName != "button") {
|
|
return;
|
|
}
|
|
|
|
let originalTarget = aEvent.originalTarget;
|
|
let ownerDoc = originalTarget.ownerDocument;
|
|
if (ownerDoc.documentURI != "about:home") {
|
|
// This shouldn't happen, but we're being defensive.
|
|
return;
|
|
}
|
|
|
|
let elmId = originalTarget.getAttribute("id");
|
|
|
|
switch (elmId) {
|
|
case "restorePreviousSession":
|
|
sendAsyncMessage("AboutHome:RestorePreviousSession");
|
|
ownerDoc.getElementById("launcher").removeAttribute("session");
|
|
break;
|
|
|
|
case "downloads":
|
|
sendAsyncMessage("AboutHome:Downloads");
|
|
break;
|
|
|
|
case "bookmarks":
|
|
sendAsyncMessage("AboutHome:Bookmarks");
|
|
break;
|
|
|
|
case "history":
|
|
sendAsyncMessage("AboutHome:History");
|
|
break;
|
|
|
|
case "apps":
|
|
sendAsyncMessage("AboutHome:Apps");
|
|
break;
|
|
|
|
case "addons":
|
|
sendAsyncMessage("AboutHome:Addons");
|
|
break;
|
|
|
|
case "sync":
|
|
sendAsyncMessage("AboutHome:Sync");
|
|
break;
|
|
|
|
case "settings":
|
|
sendAsyncMessage("AboutHome:Settings");
|
|
break;
|
|
|
|
case "searchIcon":
|
|
sendAsyncMessage("AboutHome:OpenSearchPanel", null, { anchor: originalTarget });
|
|
break;
|
|
}
|
|
},
|
|
|
|
onPageHide: function(aEvent) {
|
|
if (aEvent.target.defaultView.frameElement) {
|
|
return;
|
|
}
|
|
removeMessageListener("AboutHome:Update", this);
|
|
removeEventListener("click", this, true);
|
|
removeEventListener("pagehide", this, true);
|
|
if (aEvent.target.documentElement) {
|
|
aEvent.target.documentElement.removeAttribute("hasBrowserHandlers");
|
|
}
|
|
},
|
|
|
|
onSearch: function(aEvent) {
|
|
sendAsyncMessage("AboutHome:Search", { searchData: aEvent.detail });
|
|
},
|
|
|
|
onOpenSearchPanel: function(aEvent) {
|
|
sendAsyncMessage("AboutHome:OpenSearchPanel");
|
|
},
|
|
|
|
onFocusInput: function () {
|
|
let searchInput = content.document.getElementById("searchText");
|
|
if (searchInput) {
|
|
searchInput.focus();
|
|
}
|
|
},
|
|
};
|
|
AboutHomeListener.init(this);
|
|
|
|
let AboutPrivateBrowsingListener = {
|
|
init(chromeGlobal) {
|
|
chromeGlobal.addEventListener("AboutPrivateBrowsingOpenWindow", this,
|
|
false, true);
|
|
},
|
|
|
|
get isAboutPrivateBrowsing() {
|
|
return content.document.documentURI.toLowerCase() == "about:privatebrowsing";
|
|
},
|
|
|
|
handleEvent(aEvent) {
|
|
if (!this.isAboutPrivateBrowsing) {
|
|
return;
|
|
}
|
|
switch (aEvent.type) {
|
|
case "AboutPrivateBrowsingOpenWindow":
|
|
sendAsyncMessage("AboutPrivateBrowsing:OpenPrivateWindow");
|
|
break;
|
|
}
|
|
},
|
|
};
|
|
AboutPrivateBrowsingListener.init(this);
|
|
|
|
let AboutReaderListener = {
|
|
|
|
_articlePromise: null,
|
|
|
|
init: function() {
|
|
addEventListener("AboutReaderContentLoaded", this, false, true);
|
|
addEventListener("DOMContentLoaded", this, false);
|
|
addEventListener("pageshow", this, false);
|
|
addEventListener("pagehide", this, false);
|
|
addMessageListener("Reader:ParseDocument", this);
|
|
addMessageListener("Reader:PushState", this);
|
|
},
|
|
|
|
receiveMessage: function(message) {
|
|
switch (message.name) {
|
|
case "Reader:ParseDocument":
|
|
this._articlePromise = ReaderMode.parseDocument(content.document).catch(Cu.reportError);
|
|
content.document.location = "about:reader?url=" + encodeURIComponent(message.data.url);
|
|
break;
|
|
|
|
case "Reader:PushState":
|
|
this.updateReaderButton(!!(message.data && message.data.isArticle));
|
|
break;
|
|
}
|
|
},
|
|
|
|
get isAboutReader() {
|
|
return content.document.documentURI.startsWith("about:reader");
|
|
},
|
|
|
|
handleEvent: function(aEvent) {
|
|
if (aEvent.originalTarget.defaultView != content) {
|
|
return;
|
|
}
|
|
|
|
switch (aEvent.type) {
|
|
case "AboutReaderContentLoaded":
|
|
if (!this.isAboutReader) {
|
|
return;
|
|
}
|
|
|
|
if (content.document.body) {
|
|
// Update the toolbar icon to show the "reader active" icon.
|
|
sendAsyncMessage("Reader:UpdateReaderButton");
|
|
new AboutReader(global, content, this._articlePromise);
|
|
this._articlePromise = null;
|
|
}
|
|
break;
|
|
|
|
case "pagehide":
|
|
this.cancelPotentialPendingReadabilityCheck();
|
|
sendAsyncMessage("Reader:UpdateReaderButton", { isArticle: false });
|
|
break;
|
|
|
|
case "pageshow":
|
|
// If a page is loaded from the bfcache, we won't get a "DOMContentLoaded"
|
|
// event, so we need to rely on "pageshow" in this case.
|
|
if (aEvent.persisted) {
|
|
this.updateReaderButton();
|
|
}
|
|
break;
|
|
case "DOMContentLoaded":
|
|
this.updateReaderButton();
|
|
break;
|
|
|
|
}
|
|
},
|
|
|
|
/**
|
|
* NB: this function will update the state of the reader button asynchronously
|
|
* after the next mozAfterPaint call (assuming reader mode is enabled and
|
|
* this is a suitable document). Calling it on things which won't be
|
|
* painted is not going to work.
|
|
*/
|
|
updateReaderButton: function(forceNonArticle) {
|
|
if (!ReaderMode.isEnabledForParseOnLoad || this.isAboutReader ||
|
|
!(content.document instanceof content.HTMLDocument) ||
|
|
content.document.mozSyntheticDocument) {
|
|
return;
|
|
}
|
|
|
|
this.scheduleReadabilityCheckPostPaint(forceNonArticle);
|
|
},
|
|
|
|
cancelPotentialPendingReadabilityCheck: function() {
|
|
if (this._pendingReadabilityCheck) {
|
|
removeEventListener("MozAfterPaint", this._pendingReadabilityCheck);
|
|
delete this._pendingReadabilityCheck;
|
|
}
|
|
},
|
|
|
|
scheduleReadabilityCheckPostPaint: function(forceNonArticle) {
|
|
if (this._pendingReadabilityCheck) {
|
|
// We need to stop this check before we re-add one because we don't know
|
|
// if forceNonArticle was true or false last time.
|
|
this.cancelPotentialPendingReadabilityCheck();
|
|
}
|
|
this._pendingReadabilityCheck = this.onPaintWhenWaitedFor.bind(this, forceNonArticle);
|
|
addEventListener("MozAfterPaint", this._pendingReadabilityCheck);
|
|
},
|
|
|
|
onPaintWhenWaitedFor: function(forceNonArticle) {
|
|
this.cancelPotentialPendingReadabilityCheck();
|
|
// Only send updates when there are articles; there's no point updating with
|
|
// |false| all the time.
|
|
if (ReaderMode.isProbablyReaderable(content.document)) {
|
|
sendAsyncMessage("Reader:UpdateReaderButton", { isArticle: true });
|
|
} else if (forceNonArticle) {
|
|
sendAsyncMessage("Reader:UpdateReaderButton", { isArticle: false });
|
|
}
|
|
},
|
|
};
|
|
AboutReaderListener.init();
|
|
|
|
|
|
let ContentSearchMediator = {
|
|
|
|
whitelist: new Set([
|
|
"about:home",
|
|
"about:newtab",
|
|
]),
|
|
|
|
init: function (chromeGlobal) {
|
|
chromeGlobal.addEventListener("ContentSearchClient", this, true, true);
|
|
addMessageListener("ContentSearch", this);
|
|
},
|
|
|
|
handleEvent: function (event) {
|
|
if (this._contentWhitelisted) {
|
|
this._sendMsg(event.detail.type, event.detail.data);
|
|
}
|
|
},
|
|
|
|
receiveMessage: function (msg) {
|
|
if (msg.data.type == "AddToWhitelist") {
|
|
for (let uri of msg.data.data) {
|
|
this.whitelist.add(uri);
|
|
}
|
|
this._sendMsg("AddToWhitelistAck");
|
|
return;
|
|
}
|
|
if (this._contentWhitelisted) {
|
|
this._fireEvent(msg.data.type, msg.data.data);
|
|
}
|
|
},
|
|
|
|
get _contentWhitelisted() {
|
|
return this.whitelist.has(content.document.documentURI);
|
|
},
|
|
|
|
_sendMsg: function (type, data=null) {
|
|
sendAsyncMessage("ContentSearch", {
|
|
type: type,
|
|
data: data,
|
|
});
|
|
},
|
|
|
|
_fireEvent: function (type, data=null) {
|
|
let event = Cu.cloneInto({
|
|
detail: {
|
|
type: type,
|
|
data: data,
|
|
},
|
|
}, content);
|
|
content.dispatchEvent(new content.CustomEvent("ContentSearchService",
|
|
event));
|
|
},
|
|
};
|
|
ContentSearchMediator.init(this);
|
|
|
|
let PageStyleHandler = {
|
|
init: function() {
|
|
addMessageListener("PageStyle:Switch", this);
|
|
addMessageListener("PageStyle:Disable", this);
|
|
|
|
// Send a CPOW to the parent so that it can synchronously request
|
|
// the list of style sheets.
|
|
sendSyncMessage("PageStyle:SetSyncHandler", {}, {syncHandler: this});
|
|
},
|
|
|
|
get markupDocumentViewer() {
|
|
return docShell.contentViewer;
|
|
},
|
|
|
|
// Called synchronously via CPOW from the parent.
|
|
getStyleSheetInfo: function() {
|
|
let styleSheets = this._filterStyleSheets(this.getAllStyleSheets());
|
|
return {
|
|
styleSheets: styleSheets,
|
|
authorStyleDisabled: this.markupDocumentViewer.authorStyleDisabled,
|
|
preferredStyleSheetSet: content.document.preferredStyleSheetSet
|
|
};
|
|
},
|
|
|
|
// Called synchronously via CPOW from the parent.
|
|
getAllStyleSheets: function(frameset = content) {
|
|
let selfSheets = Array.slice(frameset.document.styleSheets);
|
|
let subSheets = Array.map(frameset.frames, frame => this.getAllStyleSheets(frame));
|
|
return selfSheets.concat(...subSheets);
|
|
},
|
|
|
|
receiveMessage: function(msg) {
|
|
switch (msg.name) {
|
|
case "PageStyle:Switch":
|
|
this.markupDocumentViewer.authorStyleDisabled = false;
|
|
this._stylesheetSwitchAll(content, msg.data.title);
|
|
break;
|
|
|
|
case "PageStyle:Disable":
|
|
this.markupDocumentViewer.authorStyleDisabled = true;
|
|
break;
|
|
}
|
|
},
|
|
|
|
_stylesheetSwitchAll: function (frameset, title) {
|
|
if (!title || this._stylesheetInFrame(frameset, title)) {
|
|
this._stylesheetSwitchFrame(frameset, title);
|
|
}
|
|
|
|
for (let i = 0; i < frameset.frames.length; i++) {
|
|
// Recurse into sub-frames.
|
|
this._stylesheetSwitchAll(frameset.frames[i], title);
|
|
}
|
|
},
|
|
|
|
_stylesheetSwitchFrame: function (frame, title) {
|
|
var docStyleSheets = frame.document.styleSheets;
|
|
|
|
for (let i = 0; i < docStyleSheets.length; ++i) {
|
|
let docStyleSheet = docStyleSheets[i];
|
|
if (docStyleSheet.title) {
|
|
docStyleSheet.disabled = (docStyleSheet.title != title);
|
|
} else if (docStyleSheet.disabled) {
|
|
docStyleSheet.disabled = false;
|
|
}
|
|
}
|
|
},
|
|
|
|
_stylesheetInFrame: function (frame, title) {
|
|
return Array.some(frame.document.styleSheets, (styleSheet) => styleSheet.title == title);
|
|
},
|
|
|
|
_filterStyleSheets: function(styleSheets) {
|
|
let result = [];
|
|
|
|
for (let currentStyleSheet of styleSheets) {
|
|
if (!currentStyleSheet.title)
|
|
continue;
|
|
|
|
// Skip any stylesheets that don't match the screen media type.
|
|
if (currentStyleSheet.media.length > 0) {
|
|
let mediaQueryList = currentStyleSheet.media.mediaText;
|
|
if (!content.matchMedia(mediaQueryList).matches) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
result.push({title: currentStyleSheet.title,
|
|
disabled: currentStyleSheet.disabled});
|
|
}
|
|
|
|
return result;
|
|
},
|
|
};
|
|
PageStyleHandler.init();
|
|
|
|
// Keep a reference to the translation content handler to avoid it it being GC'ed.
|
|
let trHandler = null;
|
|
if (Services.prefs.getBoolPref("browser.translation.detectLanguage")) {
|
|
Cu.import("resource:///modules/translation/TranslationContentHandler.jsm");
|
|
trHandler = new TranslationContentHandler(global, docShell);
|
|
}
|
|
|
|
function gKeywordURIFixup(fixupInfo) {
|
|
fixupInfo.QueryInterface(Ci.nsIURIFixupInfo);
|
|
|
|
// Ignore info from other docshells
|
|
let parent = fixupInfo.consumer.QueryInterface(Ci.nsIDocShellTreeItem).sameTypeRootTreeItem;
|
|
if (parent != docShell)
|
|
return;
|
|
|
|
let data = {};
|
|
for (let f of Object.keys(fixupInfo)) {
|
|
if (f == "consumer" || typeof fixupInfo[f] == "function")
|
|
continue;
|
|
|
|
if (fixupInfo[f] && fixupInfo[f] instanceof Ci.nsIURI) {
|
|
data[f] = fixupInfo[f].spec;
|
|
} else {
|
|
data[f] = fixupInfo[f];
|
|
}
|
|
}
|
|
|
|
sendAsyncMessage("Browser:URIFixup", data);
|
|
}
|
|
Services.obs.addObserver(gKeywordURIFixup, "keyword-uri-fixup", false);
|
|
addEventListener("unload", () => {
|
|
Services.obs.removeObserver(gKeywordURIFixup, "keyword-uri-fixup");
|
|
}, false);
|
|
|
|
addMessageListener("Browser:AppTab", function(message) {
|
|
if (docShell) {
|
|
docShell.isAppTab = message.data.isAppTab;
|
|
}
|
|
});
|
|
|
|
let WebBrowserChrome = {
|
|
onBeforeLinkTraversal: function(originalTarget, linkURI, linkNode, isAppTab) {
|
|
return BrowserUtils.onBeforeLinkTraversal(originalTarget, linkURI, linkNode, isAppTab);
|
|
},
|
|
|
|
// Check whether this URI should load in the current process
|
|
shouldLoadURI: function(aDocShell, aURI, aReferrer) {
|
|
if (!E10SUtils.shouldLoadURI(aDocShell, aURI, aReferrer)) {
|
|
E10SUtils.redirectLoad(aDocShell, aURI, aReferrer);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
},
|
|
};
|
|
|
|
if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT) {
|
|
let tabchild = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
|
|
.getInterface(Ci.nsITabChild);
|
|
tabchild.webBrowserChrome = WebBrowserChrome;
|
|
}
|
|
|
|
|
|
let DOMFullscreenHandler = {
|
|
_fullscreenDoc: null,
|
|
|
|
init: function() {
|
|
addMessageListener("DOMFullscreen:Entered", this);
|
|
addMessageListener("DOMFullscreen:Approved", this);
|
|
addMessageListener("DOMFullscreen:CleanUp", this);
|
|
addEventListener("MozDOMFullscreen:Request", this);
|
|
addEventListener("MozDOMFullscreen:Entered", this);
|
|
addEventListener("MozDOMFullscreen:NewOrigin", this);
|
|
addEventListener("MozDOMFullscreen:Exit", this);
|
|
addEventListener("MozDOMFullscreen:Exited", this);
|
|
},
|
|
|
|
get _windowUtils() {
|
|
return content.QueryInterface(Ci.nsIInterfaceRequestor)
|
|
.getInterface(Ci.nsIDOMWindowUtils);
|
|
},
|
|
|
|
receiveMessage: function(aMessage) {
|
|
switch(aMessage.name) {
|
|
case "DOMFullscreen:Entered": {
|
|
if (!this._windowUtils.handleFullscreenRequests() &&
|
|
!content.document.mozFullScreen) {
|
|
// If we don't actually have any pending fullscreen request
|
|
// to handle, neither we have been in fullscreen, tell the
|
|
// parent to just exit.
|
|
sendAsyncMessage("DOMFullscreen:Exit");
|
|
}
|
|
break;
|
|
}
|
|
case "DOMFullscreen:Approved": {
|
|
if (this._fullscreenDoc) {
|
|
Services.obs.notifyObservers(this._fullscreenDoc,
|
|
"fullscreen-approved",
|
|
"");
|
|
}
|
|
break;
|
|
}
|
|
case "DOMFullscreen:CleanUp": {
|
|
this._windowUtils.exitFullscreen();
|
|
this._fullscreenDoc = null;
|
|
break;
|
|
}
|
|
}
|
|
},
|
|
|
|
handleEvent: function(aEvent) {
|
|
switch (aEvent.type) {
|
|
case "MozDOMFullscreen:Request": {
|
|
sendAsyncMessage("DOMFullscreen:Request");
|
|
break;
|
|
}
|
|
case "MozDOMFullscreen:NewOrigin": {
|
|
this._fullscreenDoc = aEvent.target;
|
|
sendAsyncMessage("DOMFullscreen:NewOrigin", {
|
|
originNoSuffix: this._fullscreenDoc.nodePrincipal.originNoSuffix,
|
|
});
|
|
break;
|
|
}
|
|
case "MozDOMFullscreen:Exit": {
|
|
sendAsyncMessage("DOMFullscreen:Exit");
|
|
break;
|
|
}
|
|
case "MozDOMFullscreen:Entered":
|
|
case "MozDOMFullscreen:Exited": {
|
|
addEventListener("MozAfterPaint", this);
|
|
break;
|
|
}
|
|
case "MozAfterPaint": {
|
|
removeEventListener("MozAfterPaint", this);
|
|
sendAsyncMessage("DOMFullscreen:Painted");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
DOMFullscreenHandler.init();
|