mirror of
https://github.com/Feodor2/Mypal68.git
synced 2025-06-19 15:25:50 -04:00
68.14.4 bugfix version
This commit is contained in:
parent
48cfaacdb7
commit
1b3a309103
@ -6,6 +6,7 @@
|
||||
#include "mozilla/dom/AccessibleNodeBinding.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "mozilla/dom/DOMStringList.h"
|
||||
#include "mozilla/StaticPrefs_accessibility.h"
|
||||
#include "nsIPersistentProperties2.h"
|
||||
#include "nsISimpleEnumerator.h"
|
||||
|
||||
@ -18,15 +19,8 @@ using namespace mozilla::a11y;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
bool AccessibleNode::IsAOMEnabled(JSContext* aCx, JSObject* /*unused*/) {
|
||||
static bool sPrefCached = false;
|
||||
static bool sPrefCacheValue = false;
|
||||
|
||||
if (!sPrefCached) {
|
||||
sPrefCached = true;
|
||||
Preferences::AddBoolVarCache(&sPrefCacheValue, "accessibility.AOM.enabled");
|
||||
}
|
||||
|
||||
return nsContentUtils::IsSystemCaller(aCx) || sPrefCacheValue;
|
||||
return nsContentUtils::IsSystemCaller(aCx) ||
|
||||
StaticPrefs::accessibility_AOM_enabled();
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(AccessibleNode, mRelationProperties,
|
||||
|
@ -534,7 +534,7 @@ class ContextMenuChild extends ActorChild {
|
||||
// The same-origin check will be done in nsContextMenu.openLinkInTab.
|
||||
let parentAllowsMixedContent = !!this.docShell.mixedContentChannel;
|
||||
|
||||
let disableSetDesktopBackground = null;
|
||||
let disableSetDesktopBg = null;
|
||||
|
||||
// Media related cache info parent needs for saving
|
||||
let contentType = null;
|
||||
@ -544,7 +544,7 @@ class ContextMenuChild extends ActorChild {
|
||||
aEvent.composedTarget instanceof Ci.nsIImageLoadingContent &&
|
||||
aEvent.composedTarget.currentURI
|
||||
) {
|
||||
disableSetDesktopBackground = this._disableSetDesktopBackground(
|
||||
disableSetDesktopBg = this._disableSetDesktopBackground(
|
||||
aEvent.composedTarget
|
||||
);
|
||||
|
||||
@ -590,7 +590,6 @@ class ContextMenuChild extends ActorChild {
|
||||
Ci.nsIReferrerInfo
|
||||
);
|
||||
referrerInfo.initWithElement(aEvent.composedTarget);
|
||||
referrerInfo = E10SUtils.serializeReferrerInfo(referrerInfo);
|
||||
|
||||
// In the case "onLink" we may have to send link referrerInfo to use in
|
||||
// _openLinkInParameters
|
||||
@ -607,33 +606,40 @@ class ContextMenuChild extends ActorChild {
|
||||
this._cleanContext();
|
||||
}
|
||||
|
||||
editFlags = SpellCheckHelper.isEditable(
|
||||
aEvent.composedTarget,
|
||||
this.content
|
||||
);
|
||||
let isRemote =
|
||||
Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT;
|
||||
|
||||
if (editFlags & SpellCheckHelper.SPELLCHECKABLE) {
|
||||
spellInfo = InlineSpellCheckerContent.initContextMenu(
|
||||
aEvent,
|
||||
editFlags,
|
||||
this
|
||||
if (isRemote) {
|
||||
editFlags = SpellCheckHelper.isEditable(
|
||||
aEvent.composedTarget,
|
||||
this.content
|
||||
);
|
||||
|
||||
if (editFlags & SpellCheckHelper.SPELLCHECKABLE) {
|
||||
spellInfo = InlineSpellCheckerContent.initContextMenu(
|
||||
aEvent,
|
||||
editFlags,
|
||||
this.mm
|
||||
);
|
||||
}
|
||||
|
||||
// Set the event target first as the copy image command needs it to
|
||||
// determine what was context-clicked on. Then, update the state of the
|
||||
// commands on the context menu.
|
||||
this.docShell.contentViewer
|
||||
.QueryInterface(Ci.nsIContentViewerEdit)
|
||||
.setCommandNode(aEvent.composedTarget);
|
||||
aEvent.composedTarget.ownerGlobal.updateCommands("contentcontextmenu");
|
||||
|
||||
customMenuItems = PageMenuChild.build(aEvent.composedTarget);
|
||||
principal = doc.nodePrincipal;
|
||||
}
|
||||
|
||||
// Set the event target first as the copy image command needs it to
|
||||
// determine what was context-clicked on. Then, update the state of the
|
||||
// commands on the context menu.
|
||||
this.docShell.contentViewer
|
||||
.QueryInterface(Ci.nsIContentViewerEdit)
|
||||
.setCommandNode(aEvent.composedTarget);
|
||||
aEvent.composedTarget.ownerGlobal.updateCommands("contentcontextmenu");
|
||||
|
||||
principal = doc.nodePrincipal;
|
||||
|
||||
let data = {
|
||||
context,
|
||||
charSet,
|
||||
baseURI,
|
||||
isRemote,
|
||||
referrerInfo,
|
||||
editFlags,
|
||||
principal,
|
||||
@ -647,22 +653,26 @@ class ContextMenuChild extends ActorChild {
|
||||
contentDisposition,
|
||||
frameOuterWindowID,
|
||||
popupNodeSelectors,
|
||||
disableSetDesktopBackground,
|
||||
disableSetDesktopBg,
|
||||
parentAllowsMixedContent,
|
||||
};
|
||||
|
||||
if (context.inFrame && !context.inSrcdocFrame) {
|
||||
data.frameReferrerInfo = E10SUtils.serializeReferrerInfo(
|
||||
doc.referrerInfo
|
||||
);
|
||||
}
|
||||
|
||||
if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT) {
|
||||
data.customMenuItems = PageMenuChild.build(aEvent.composedTarget);
|
||||
if (isRemote) {
|
||||
data.frameReferrerInfo = E10SUtils.serializeReferrerInfo(
|
||||
doc.referrerInfo
|
||||
);
|
||||
} else {
|
||||
data.frameReferrerInfo = doc.referrerInfo;
|
||||
}
|
||||
}
|
||||
|
||||
if (linkReferrerInfo) {
|
||||
data.linkReferrerInfo = E10SUtils.serializeReferrerInfo(linkReferrerInfo);
|
||||
if (isRemote) {
|
||||
data.linkReferrerInfo = E10SUtils.serializeReferrerInfo(linkReferrerInfo);
|
||||
} else {
|
||||
data.linkReferrerInfo = linkReferrerInfo;
|
||||
}
|
||||
}
|
||||
|
||||
Services.obs.notifyObservers(
|
||||
@ -670,14 +680,24 @@ class ContextMenuChild extends ActorChild {
|
||||
"on-prepare-contextmenu"
|
||||
);
|
||||
|
||||
// In the event that the content is running in the parent process, we don't
|
||||
// actually want the contextmenu events to reach the parent - we'll dispatch
|
||||
// a new contextmenu event after the async message has reached the parent
|
||||
// instead.
|
||||
aEvent.preventDefault();
|
||||
aEvent.stopPropagation();
|
||||
if (isRemote) {
|
||||
data.referrerInfo = E10SUtils.serializeReferrerInfo(data.referrerInfo);
|
||||
if (data.frameReferrerInfo) {
|
||||
data.frameReferrerInfo =
|
||||
E10SUtils.serializeReferrerInfo(data.frameReferrerInfo);
|
||||
}
|
||||
|
||||
this.mm.sendAsyncMessage("contextmenu", data);
|
||||
this.mm.sendAsyncMessage("contextmenu", data);
|
||||
} else {
|
||||
let browser = this.docShell.chromeEventHandler;
|
||||
let mainWin = browser.ownerGlobal;
|
||||
|
||||
data.documentURIObject = doc.documentURIObject;
|
||||
data.disableSetDesktopBackground = data.disableSetDesktopBg;
|
||||
delete data.disableSetDesktopBg;
|
||||
|
||||
mainWin.setContextMenuContentData(data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -958,9 +958,9 @@ class PluginChild extends ActorChild {
|
||||
plugins: [...this.pluginData.values()],
|
||||
showNow,
|
||||
location,
|
||||
principal,
|
||||
},
|
||||
null,
|
||||
principal
|
||||
);
|
||||
}
|
||||
|
||||
@ -1221,10 +1221,5 @@ class PluginChild extends ActorChild {
|
||||
messageString,
|
||||
pluginID,
|
||||
});
|
||||
|
||||
// Remove the notification when the page is reloaded.
|
||||
doc.defaultView.top.addEventListener("unload", event => {
|
||||
this.hideNotificationBar("plugin-crashed");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -141,12 +141,6 @@ pref("extensions.update.interval", 86400); // Check for updates to Extensions a
|
||||
|
||||
pref("lightweightThemes.getMoreURL", "data:text/plain,");
|
||||
|
||||
#if defined(MOZ_WIDEVINE_EME)
|
||||
pref("browser.eme.ui.enabled", true);
|
||||
#else
|
||||
pref("browser.eme.ui.enabled", false);
|
||||
#endif
|
||||
|
||||
pref("keyword.enabled", false);
|
||||
pref("browser.fixup.domainwhitelist.localhost", true);
|
||||
|
||||
@ -676,9 +670,6 @@ pref("plugin.defaultXpi.state", 2);
|
||||
pref("plugin.state.flash", 1);
|
||||
#endif
|
||||
|
||||
// Enables the download and use of the flash blocklists.
|
||||
pref("plugins.flashBlock.enabled", true);
|
||||
|
||||
// Prefer HTML5 video over Flash content, and don't
|
||||
// load plugin instances with no src declared.
|
||||
// These prefs are documented in details on all.js.
|
||||
@ -938,14 +929,6 @@ pref("browser.bookmarks.editDialog.showForNewBookmarks", true);
|
||||
// bookmarking dialog
|
||||
pref("browser.bookmarks.editDialog.firstEditField", "namePicker");
|
||||
|
||||
pref("dom.ipc.plugins.flash.disable-protected-mode", false);
|
||||
|
||||
// Feature-disable the protected-mode auto-flip
|
||||
pref("browser.flash-protected-mode-flip.enable", false);
|
||||
|
||||
// Whether we've already flipped protected mode automatically
|
||||
pref("browser.flash-protected-mode-flip.done", false);
|
||||
|
||||
pref("dom.ipc.shims.enabledWarnings", false);
|
||||
|
||||
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
|
||||
@ -1156,7 +1139,6 @@ pref("services.sync.prefs.sync.extensions.activeThemeID", true);
|
||||
pref("services.sync.prefs.sync.intl.accept_languages", true);
|
||||
pref("services.sync.prefs.sync.layout.spellcheckDefault", true);
|
||||
pref("services.sync.prefs.sync.media.autoplay.default", true);
|
||||
pref("services.sync.prefs.sync.media.eme.enabled", true);
|
||||
pref("services.sync.prefs.sync.network.cookie.cookieBehavior", true);
|
||||
pref("services.sync.prefs.sync.network.cookie.lifetimePolicy", true);
|
||||
pref("services.sync.prefs.sync.network.cookie.thirdparty.sessionOnly", true);
|
||||
@ -1389,11 +1371,6 @@ pref("media.gmp.trial-create.enabled", true);
|
||||
// to enable the CDM if its disabled; it's as if the keysystem is completely
|
||||
// unsupported.
|
||||
|
||||
#ifdef MOZ_WIDEVINE_EME
|
||||
pref("media.gmp-widevinecdm.visible", true);
|
||||
pref("media.gmp-widevinecdm.enabled", true);
|
||||
#endif
|
||||
|
||||
pref("media.gmp-gmpopenh264.visible", true);
|
||||
pref("media.gmp-gmpopenh264.enabled", true);
|
||||
|
||||
|
@ -448,11 +448,3 @@
|
||||
hidden="true"
|
||||
label="&inspectA11YContextMenu.label;"
|
||||
oncommand="gContextMenu.inspectA11Y();"/>
|
||||
<menuseparator id="context-media-eme-separator" hidden="true"/>
|
||||
<menuitem id="context-media-eme-learnmore"
|
||||
class="menuitem-iconic"
|
||||
hidden="true"
|
||||
label="&emeLearnMoreContextMenu.label;"
|
||||
accesskey="&emeLearnMoreContextMenu.accesskey;"
|
||||
oncommand="gContextMenu.drmLearnMore(event);"
|
||||
onclick="checkForMiddleClick(this, event);"/>
|
||||
|
@ -4,211 +4,6 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
var gEMEHandler = {
|
||||
get uiEnabled() {
|
||||
let emeUIEnabled = Services.prefs.getBoolPref("browser.eme.ui.enabled");
|
||||
// Force-disable on WinXP:
|
||||
if (navigator.platform.toLowerCase().startsWith("win")) {
|
||||
emeUIEnabled =
|
||||
emeUIEnabled && parseFloat(Services.sysinfo.get("version")) >= 6;
|
||||
}
|
||||
return emeUIEnabled;
|
||||
},
|
||||
ensureEMEEnabled(browser, keySystem) {
|
||||
Services.prefs.setBoolPref("media.eme.enabled", true);
|
||||
if (
|
||||
keySystem &&
|
||||
keySystem == "com.widevine.alpha" &&
|
||||
Services.prefs.getPrefType("media.gmp-widevinecdm.enabled") &&
|
||||
!Services.prefs.getBoolPref("media.gmp-widevinecdm.enabled")
|
||||
) {
|
||||
Services.prefs.setBoolPref("media.gmp-widevinecdm.enabled", true);
|
||||
}
|
||||
browser.reload();
|
||||
},
|
||||
isKeySystemVisible(keySystem) {
|
||||
if (!keySystem) {
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
keySystem == "com.widevine.alpha" &&
|
||||
Services.prefs.getPrefType("media.gmp-widevinecdm.visible")
|
||||
) {
|
||||
return Services.prefs.getBoolPref("media.gmp-widevinecdm.visible");
|
||||
}
|
||||
return true;
|
||||
},
|
||||
getEMEDisabledFragment(msgId) {
|
||||
let mainMessage = gNavigatorBundle.getString(
|
||||
"emeNotifications.drmContentDisabled.message"
|
||||
);
|
||||
let text = gNavigatorBundle.getString(
|
||||
"emeNotifications.drmContentDisabled.learnMoreLabel"
|
||||
);
|
||||
let baseURL = Services.urlFormatter.formatURLPref("app.support.baseURL");
|
||||
let link = document.createXULElement("label", { is: "text-link" });
|
||||
link.setAttribute("href", baseURL + "drm-content");
|
||||
link.textContent = text;
|
||||
return BrowserUtils.getLocalizedFragment(document, mainMessage, link);
|
||||
},
|
||||
getMessageWithBrandName(notificationId) {
|
||||
let msgId = "emeNotifications." + notificationId + ".message";
|
||||
return gNavigatorBundle.getFormattedString(msgId, [this._brandShortName]);
|
||||
},
|
||||
receiveMessage({ target: browser, data: data }) {
|
||||
let parsedData;
|
||||
try {
|
||||
parsedData = JSON.parse(data);
|
||||
} catch (ex) {
|
||||
Cu.reportError("Malformed EME video message with data: " + data);
|
||||
return;
|
||||
}
|
||||
let { status: status, keySystem: keySystem } = parsedData;
|
||||
// Don't need to show if disabled or keysystem not visible.
|
||||
if (!this.uiEnabled || !this.isKeySystemVisible(keySystem)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let notificationId;
|
||||
let buttonCallback;
|
||||
// Notification message can be either a string or a DOM fragment.
|
||||
let notificationMessage;
|
||||
switch (status) {
|
||||
case "available":
|
||||
case "cdm-created":
|
||||
// Only show the chain icon for proprietary CDMs. Clearkey is not one.
|
||||
if (keySystem != "org.w3.clearkey") {
|
||||
this.showPopupNotificationForSuccess(browser, keySystem);
|
||||
}
|
||||
// ... and bail!
|
||||
return;
|
||||
|
||||
case "api-disabled":
|
||||
case "cdm-disabled":
|
||||
notificationId = "drmContentDisabled";
|
||||
buttonCallback = gEMEHandler.ensureEMEEnabled.bind(
|
||||
gEMEHandler,
|
||||
browser,
|
||||
keySystem
|
||||
);
|
||||
notificationMessage = this.getEMEDisabledFragment();
|
||||
break;
|
||||
|
||||
case "cdm-not-installed":
|
||||
notificationId = "drmContentCDMInstalling";
|
||||
notificationMessage = this.getMessageWithBrandName(notificationId);
|
||||
break;
|
||||
|
||||
case "cdm-not-supported":
|
||||
// Not to pop up user-level notification because they cannot do anything
|
||||
// about it.
|
||||
return;
|
||||
default:
|
||||
Cu.reportError(
|
||||
new Error(
|
||||
"Unknown message ('" +
|
||||
status +
|
||||
"') dealing with EME key request: " +
|
||||
data
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Now actually create the notification
|
||||
|
||||
let box = gBrowser.getNotificationBox(browser);
|
||||
if (box.getNotificationWithValue(notificationId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let buttons = [];
|
||||
if (buttonCallback) {
|
||||
let msgPrefix = "emeNotifications." + notificationId + ".";
|
||||
let btnLabelId = msgPrefix + "button.label";
|
||||
let btnAccessKeyId = msgPrefix + "button.accesskey";
|
||||
buttons.push({
|
||||
label: gNavigatorBundle.getString(btnLabelId),
|
||||
accessKey: gNavigatorBundle.getString(btnAccessKeyId),
|
||||
callback: buttonCallback,
|
||||
});
|
||||
}
|
||||
|
||||
let iconURL = "chrome://browser/skin/drm-icon.svg";
|
||||
box.appendNotification(
|
||||
notificationMessage,
|
||||
notificationId,
|
||||
iconURL,
|
||||
box.PRIORITY_WARNING_MEDIUM,
|
||||
buttons
|
||||
);
|
||||
},
|
||||
showPopupNotificationForSuccess(browser, keySystem) {
|
||||
// We're playing EME content! Remove any "we can't play because..." messages.
|
||||
var box = gBrowser.getNotificationBox(browser);
|
||||
["drmContentDisabled", "drmContentCDMInstalling"].forEach(function(value) {
|
||||
var notification = box.getNotificationWithValue(value);
|
||||
if (notification) {
|
||||
box.removeNotification(notification);
|
||||
}
|
||||
});
|
||||
|
||||
// Don't bother creating it if it's already there:
|
||||
if (PopupNotifications.getNotification("drmContentPlaying", browser)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let msgPrefix = "emeNotifications.drmContentPlaying.";
|
||||
let msgId = msgPrefix + "message2";
|
||||
let btnLabelId = msgPrefix + "button.label";
|
||||
let btnAccessKeyId = msgPrefix + "button.accesskey";
|
||||
|
||||
let message = gNavigatorBundle.getFormattedString(msgId, [
|
||||
this._brandShortName,
|
||||
]);
|
||||
let anchorId = "eme-notification-icon";
|
||||
let firstPlayPref = "browser.eme.ui.firstContentShown";
|
||||
if (
|
||||
!Services.prefs.getPrefType(firstPlayPref) ||
|
||||
!Services.prefs.getBoolPref(firstPlayPref)
|
||||
) {
|
||||
document.getElementById(anchorId).setAttribute("firstplay", "true");
|
||||
Services.prefs.setBoolPref(firstPlayPref, true);
|
||||
} else {
|
||||
document.getElementById(anchorId).removeAttribute("firstplay");
|
||||
}
|
||||
|
||||
let mainAction = {
|
||||
label: gNavigatorBundle.getString(btnLabelId),
|
||||
accessKey: gNavigatorBundle.getString(btnAccessKeyId),
|
||||
callback() {
|
||||
openPreferences("general-drm");
|
||||
},
|
||||
dismiss: true,
|
||||
};
|
||||
let options = {
|
||||
dismissed: true,
|
||||
eventCallback: aTopic => aTopic == "swapping",
|
||||
learnMoreURL:
|
||||
Services.urlFormatter.formatURLPref("app.support.baseURL") +
|
||||
"drm-content",
|
||||
};
|
||||
PopupNotifications.show(
|
||||
browser,
|
||||
"drmContentPlaying",
|
||||
message,
|
||||
anchorId,
|
||||
mainAction,
|
||||
null,
|
||||
options
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
XPCOMUtils.defineLazyGetter(gEMEHandler, "_brandShortName", function() {
|
||||
return document.getElementById("bundle_brand").getString("brandShortName");
|
||||
});
|
||||
|
||||
const TELEMETRY_DDSTAT_SHOWN = 0;
|
||||
const TELEMETRY_DDSTAT_SHOWN_FIRST = 1;
|
||||
const TELEMETRY_DDSTAT_CLICKED = 2;
|
||||
@ -425,13 +220,7 @@ let gDecoderDoctorHandler = {
|
||||
window
|
||||
.getGroupMessageManager("browsers")
|
||||
.addMessageListener("DecoderDoctor:Notification", gDecoderDoctorHandler);
|
||||
window
|
||||
.getGroupMessageManager("browsers")
|
||||
.addMessageListener("EMEVideo:ContentMediaKeysRequest", gEMEHandler);
|
||||
window.addEventListener("unload", function() {
|
||||
window
|
||||
.getGroupMessageManager("browsers")
|
||||
.removeMessageListener("EMEVideo:ContentMediaKeysRequest", gEMEHandler);
|
||||
window
|
||||
.getGroupMessageManager("browsers")
|
||||
.removeMessageListener("DecoderDoctor:Notification", gDecoderDoctorHandler);
|
||||
|
@ -41,7 +41,7 @@ var gPluginHandler = {
|
||||
msg.target,
|
||||
msg.data.plugins,
|
||||
msg.data.showNow,
|
||||
msg.principal,
|
||||
msg.data.principal,
|
||||
msg.data.location
|
||||
);
|
||||
break;
|
||||
@ -244,15 +244,6 @@ var gPluginHandler = {
|
||||
},
|
||||
|
||||
showClickToPlayNotification(browser, plugins, showNow, principal, location) {
|
||||
// It is possible that we've received a message from the frame script to show
|
||||
// a click to play notification for a principal that no longer matches the one
|
||||
// that the browser's content now has assigned (ie, the browser has browsed away
|
||||
// after the message was sent, but before the message was received). In that case,
|
||||
// we should just ignore the message.
|
||||
if (!principal.equals(browser.contentPrincipal)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Data URIs, when linked to from some page, inherit the principal of that
|
||||
// page. That means that we also need to compare the actual locations to
|
||||
// ensure we aren't getting a message from a Data URI that we're no longer
|
||||
|
@ -35,7 +35,6 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
LightweightThemeConsumer:
|
||||
"resource://gre/modules/LightweightThemeConsumer.jsm",
|
||||
Log: "resource://gre/modules/Log.jsm",
|
||||
LoginHelper: "resource://gre/modules/LoginHelper.jsm",
|
||||
LoginManagerParent: "resource://gre/modules/LoginManagerParent.jsm",
|
||||
MigrationUtils: "resource:///modules/MigrationUtils.jsm",
|
||||
NetUtil: "resource://gre/modules/NetUtil.jsm",
|
||||
@ -182,7 +181,7 @@ XPCOMUtils.defineLazyScriptGetter(
|
||||
);
|
||||
XPCOMUtils.defineLazyScriptGetter(
|
||||
this,
|
||||
["openContextMenu", "nsContextMenu"],
|
||||
["setContextMenuContentData", "openContextMenu", "nsContextMenu"],
|
||||
"chrome://browser/content/nsContextMenu.js"
|
||||
);
|
||||
XPCOMUtils.defineLazyScriptGetter(
|
||||
@ -6587,16 +6586,6 @@ nsBrowserAccess.prototype = {
|
||||
aTriggeringPrincipal,
|
||||
aCsp
|
||||
) {
|
||||
// This function should only ever be called if we're opening a URI
|
||||
// from a non-remote browser window (via nsContentTreeOwner).
|
||||
if (aOpener && Cu.isCrossProcessWrapper(aOpener)) {
|
||||
Cu.reportError(
|
||||
"nsBrowserAccess.openURI was passed a CPOW for aOpener. " +
|
||||
"openURI should only ever be called from non-remote browsers."
|
||||
);
|
||||
throw Cr.NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
var newWindow = null;
|
||||
var isExternal = !!(aFlags & Ci.nsIBrowserDOMWindow.OPEN_EXTERNAL);
|
||||
|
||||
|
@ -871,8 +871,6 @@
|
||||
tooltiptext="&urlbar.translateNotificationAnchor.tooltip;"/>
|
||||
<image id="translated-notification-icon" class="notification-anchor-icon translation-icon in-use" role="button"
|
||||
tooltiptext="&urlbar.translatedNotificationAnchor.tooltip;"/>
|
||||
<image id="eme-notification-icon" class="notification-anchor-icon drm-icon" role="button"
|
||||
tooltiptext="&urlbar.emeNotificationAnchor.tooltip;"/>
|
||||
<image id="persistent-storage-notification-icon" class="notification-anchor-icon persistent-storage-icon" role="button"
|
||||
tooltiptext="&urlbar.persistentStorageNotificationAnchor.tooltip;"/>
|
||||
<image id="midi-notification-icon" class="notification-anchor-icon midi-icon" role="button"
|
||||
|
@ -2,6 +2,18 @@
|
||||
* 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/. */
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
LoginHelper: "resource://gre/modules/LoginHelper.jsm",
|
||||
LoginManagerContextMenu: "resource://gre/modules/LoginManagerContextMenu.jsm",
|
||||
DevToolsShim: "chrome://devtools-startup/content/DevToolsShim.jsm",
|
||||
});
|
||||
|
||||
var gContextMenuContentData = null;
|
||||
|
||||
function setContextMenuContentData(data) {
|
||||
gContextMenuContentData = data;
|
||||
}
|
||||
|
||||
function openContextMenu(aMessage) {
|
||||
let data = aMessage.data;
|
||||
let browser = aMessage.target;
|
||||
@ -29,8 +41,9 @@ function openContextMenu(aMessage) {
|
||||
}
|
||||
}
|
||||
|
||||
nsContextMenu.contentData = {
|
||||
gContextMenuContentData = {
|
||||
context: data.context,
|
||||
isRemote: data.isRemote,
|
||||
popupNodeSelectors: data.popupNodeSelectors,
|
||||
browser,
|
||||
editFlags: data.editFlags,
|
||||
@ -47,7 +60,7 @@ function openContextMenu(aMessage) {
|
||||
contentDisposition: data.contentDisposition,
|
||||
frameOuterWindowID: data.frameOuterWindowID,
|
||||
selectionInfo: data.selectionInfo,
|
||||
disableSetDesktopBackground: data.disableSetDesktopBackground,
|
||||
disableSetDesktopBackground: data.disableSetDesktopBg,
|
||||
loginFillInfo: data.loginFillInfo,
|
||||
parentAllowsMixedContent: data.parentAllowsMixedContent,
|
||||
userContextId: data.userContextId,
|
||||
@ -55,7 +68,7 @@ function openContextMenu(aMessage) {
|
||||
};
|
||||
|
||||
let popup = browser.ownerDocument.getElementById("contentAreaContextMenu");
|
||||
let context = nsContextMenu.contentData.context;
|
||||
let context = gContextMenuContentData.context;
|
||||
|
||||
// We don't have access to the original event here, as that happened in
|
||||
// another process. Therefore we synthesize a new MouseEvent to propagate the
|
||||
@ -83,8 +96,14 @@ function openContextMenu(aMessage) {
|
||||
popup.openPopupAtScreen(newEvent.screenX, newEvent.screenY, true, newEvent);
|
||||
}
|
||||
|
||||
class nsContextMenu {
|
||||
constructor(aXulMenu, aIsShift) {
|
||||
function nsContextMenu(aXulMenu, aIsShift) {
|
||||
this.shouldDisplay = true;
|
||||
this.initMenu(aXulMenu, aIsShift);
|
||||
}
|
||||
|
||||
// Prototype for nsContextMenu "class."
|
||||
nsContextMenu.prototype = {
|
||||
initMenu: function CM_initMenu(aXulMenu, aIsShift) {
|
||||
// Get contextual info.
|
||||
this.setContext();
|
||||
|
||||
@ -95,11 +114,18 @@ class nsContextMenu {
|
||||
this.hasPageMenu = false;
|
||||
this.isContentSelected = !this.selectionInfo.docSelectionIsCollapsed;
|
||||
if (!aIsShift) {
|
||||
this.hasPageMenu = PageMenuParent.addToPopup(
|
||||
this.contentData.customMenuItems,
|
||||
this.browser,
|
||||
aXulMenu
|
||||
);
|
||||
if (this.isRemote) {
|
||||
this.hasPageMenu = PageMenuParent.addToPopup(
|
||||
gContextMenuContentData.customMenuItems,
|
||||
this.browser,
|
||||
aXulMenu
|
||||
);
|
||||
} else {
|
||||
this.hasPageMenu = PageMenuParent.buildAndAddToPopup(
|
||||
this.target,
|
||||
aXulMenu
|
||||
);
|
||||
}
|
||||
|
||||
let tab =
|
||||
gBrowser && gBrowser.getTabForBrowser
|
||||
@ -123,7 +149,9 @@ class nsContextMenu {
|
||||
onSpellcheckable: this.onSpellcheckable,
|
||||
onPassword: this.onPassword,
|
||||
srcUrl: this.mediaURL,
|
||||
frameUrl: this.contentData ? this.contentData.docLocation : undefined,
|
||||
frameUrl: gContextMenuContentData
|
||||
? gContextMenuContentData.docLocation
|
||||
: undefined,
|
||||
pageUrl: this.browser ? this.browser.currentURI.spec : undefined,
|
||||
linkText: this.linkTextStr,
|
||||
linkUrl: this.linkURL,
|
||||
@ -132,8 +160,8 @@ class nsContextMenu {
|
||||
: undefined,
|
||||
frameId: this.frameOuterWindowID,
|
||||
webExtBrowserType: this.webExtBrowserType,
|
||||
webExtContextData: this.contentData
|
||||
? this.contentData.webExtContextData
|
||||
webExtContextData: gContextMenuContentData
|
||||
? gContextMenuContentData.webExtContextData
|
||||
: undefined,
|
||||
};
|
||||
subject.wrappedJSObject = subject;
|
||||
@ -163,15 +191,16 @@ class nsContextMenu {
|
||||
|
||||
// Initialize (disable/remove) menu items.
|
||||
this.initItems();
|
||||
}
|
||||
},
|
||||
|
||||
setContext() {
|
||||
let context = Object.create(null);
|
||||
this.isRemote = false;
|
||||
|
||||
if (nsContextMenu.contentData) {
|
||||
this.contentData = nsContextMenu.contentData;
|
||||
context = this.contentData.context;
|
||||
nsContextMenu.contentData = null;
|
||||
if (gContextMenuContentData) {
|
||||
context = gContextMenuContentData.context;
|
||||
gContextMenuContentData.context = null;
|
||||
this.isRemote = gContextMenuContentData.isRemote;
|
||||
}
|
||||
|
||||
this.shouldDisplay = context.shouldDisplay;
|
||||
@ -222,7 +251,7 @@ class nsContextMenu {
|
||||
this.onTextInput = context.onTextInput;
|
||||
this.onVideo = context.onVideo;
|
||||
|
||||
this.target = context.target;
|
||||
this.target = this.isRemote ? context.target : document.popupNode;
|
||||
this.targetIdentifier = context.targetIdentifier;
|
||||
|
||||
this.principal = context.principal;
|
||||
@ -236,14 +265,19 @@ class nsContextMenu {
|
||||
|
||||
this.csp = E10SUtils.deserializeCSP(context.csp);
|
||||
|
||||
// Remember the CSS selectors corresponding to clicked node. this.contentData
|
||||
// Remember the CSS selectors corresponding to clicked node. gContextMenuContentData
|
||||
// can be null if the menu was triggered by tests in which case use an empty array.
|
||||
this.targetSelectors = this.contentData
|
||||
? this.contentData.popupNodeSelectors
|
||||
this.targetSelectors = gContextMenuContentData
|
||||
? gContextMenuContentData.popupNodeSelectors
|
||||
: [];
|
||||
|
||||
this.browser = this.contentData.browser;
|
||||
this.selectionInfo = this.contentData.selectionInfo;
|
||||
if (this.isRemote) {
|
||||
this.browser = gContextMenuContentData.browser;
|
||||
this.selectionInfo = gContextMenuContentData.selectionInfo;
|
||||
} else {
|
||||
this.browser = this.ownerDoc.defaultView.docShell.chromeEventHandler;
|
||||
this.selectionInfo = BrowserUtils.getSelectionDetails(window);
|
||||
}
|
||||
|
||||
const { gBrowser } = this.browser.ownerGlobal;
|
||||
|
||||
@ -259,39 +293,59 @@ class nsContextMenu {
|
||||
: false;
|
||||
|
||||
if (context.shouldInitInlineSpellCheckerUINoChildren) {
|
||||
InlineSpellCheckerUI.initFromRemote(this.contentData.spellInfo);
|
||||
if (this.isRemote) {
|
||||
InlineSpellCheckerUI.initFromRemote(gContextMenuContentData.spellInfo);
|
||||
} else {
|
||||
InlineSpellCheckerUI.init(this.target.editor);
|
||||
InlineSpellCheckerUI.initFromEvent(
|
||||
document.popupRangeParent,
|
||||
document.popupRangeOffset
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (context.shouldInitInlineSpellCheckerUIWithChildren) {
|
||||
InlineSpellCheckerUI.initFromRemote(this.contentData.spellInfo);
|
||||
if (this.isRemote) {
|
||||
InlineSpellCheckerUI.initFromRemote(gContextMenuContentData.spellInfo);
|
||||
} else {
|
||||
var targetWin = this.ownerDoc.defaultView;
|
||||
var { editingSession } = targetWin.docShell;
|
||||
|
||||
InlineSpellCheckerUI.init(editingSession.getEditorForWindow(targetWin));
|
||||
InlineSpellCheckerUI.initFromEvent(
|
||||
document.popupRangeParent,
|
||||
document.popupRangeOffset
|
||||
);
|
||||
}
|
||||
|
||||
let canSpell = InlineSpellCheckerUI.canSpellCheck && this.canSpellCheck;
|
||||
this.showItem("spell-check-enabled", canSpell);
|
||||
this.showItem("spell-separator", canSpell);
|
||||
}
|
||||
} // setContext
|
||||
}, // setContext
|
||||
|
||||
hiding() {
|
||||
hiding: function CM_hiding() {
|
||||
if (this.browser && this.browser.messageManager) {
|
||||
this.browser.messageManager.sendAsyncMessage("ContextMenu:Hiding");
|
||||
}
|
||||
|
||||
this.contentData = null;
|
||||
gContextMenuContentData = null;
|
||||
InlineSpellCheckerUI.clearSuggestionsFromMenu();
|
||||
InlineSpellCheckerUI.clearDictionaryListFromMenu();
|
||||
InlineSpellCheckerUI.uninit();
|
||||
if (
|
||||
Cu.isModuleLoaded("resource://gre/modules/LoginManagerContextMenu.jsm")
|
||||
) {
|
||||
nsContextMenu.LoginManagerContextMenu.clearLoginsFromMenu(document);
|
||||
LoginManagerContextMenu.clearLoginsFromMenu(document);
|
||||
}
|
||||
|
||||
// This handler self-deletes, only run it if it is still there:
|
||||
if (this._onPopupHiding) {
|
||||
this._onPopupHiding();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
initItems() {
|
||||
initItems: function CM_initItems() {
|
||||
this.initPageMenuSeparator();
|
||||
this.initOpenItems();
|
||||
this.initNavigationItems();
|
||||
@ -305,13 +359,13 @@ class nsContextMenu {
|
||||
this.initClickToPlayItems();
|
||||
this.initPasswordManagerItems();
|
||||
this.initSyncItems();
|
||||
}
|
||||
},
|
||||
|
||||
initPageMenuSeparator() {
|
||||
initPageMenuSeparator: function CM_initPageMenuSeparator() {
|
||||
this.showItem("page-menu-separator", this.hasPageMenu);
|
||||
}
|
||||
},
|
||||
|
||||
initOpenItems() {
|
||||
initOpenItems: function CM_initOpenItems() {
|
||||
var isMailtoInternal = false;
|
||||
if (this.onMailtoLink) {
|
||||
var mailtoHandler = Cc[
|
||||
@ -342,14 +396,17 @@ class nsContextMenu {
|
||||
}
|
||||
|
||||
var inContainer = false;
|
||||
if (this.contentData.userContextId) {
|
||||
if (gContextMenuContentData.userContextId) {
|
||||
inContainer = true;
|
||||
var item = document.getElementById("context-openlinkincontainertab");
|
||||
|
||||
item.setAttribute("data-usercontextid", this.contentData.userContextId);
|
||||
item.setAttribute(
|
||||
"data-usercontextid",
|
||||
gContextMenuContentData.userContextId
|
||||
);
|
||||
|
||||
var label = ContextualIdentityService.getUserContextLabel(
|
||||
this.contentData.userContextId
|
||||
gContextMenuContentData.userContextId
|
||||
);
|
||||
item.setAttribute(
|
||||
"label",
|
||||
@ -379,9 +436,9 @@ class nsContextMenu {
|
||||
);
|
||||
this.showItem("context-openlinkincurrent", this.onPlainTextLink);
|
||||
this.showItem("context-sep-open", shouldShow);
|
||||
}
|
||||
},
|
||||
|
||||
initNavigationItems() {
|
||||
initNavigationItems: function CM_initNavigationItems() {
|
||||
var shouldShow =
|
||||
!(
|
||||
this.isContentSelected ||
|
||||
@ -405,9 +462,9 @@ class nsContextMenu {
|
||||
|
||||
this.showItem("context-reload", stopReloadItem == "reload");
|
||||
this.showItem("context-stop", stopReloadItem == "stop");
|
||||
}
|
||||
},
|
||||
|
||||
initLeaveDOMFullScreenItems() {
|
||||
initLeaveDOMFullScreenItems: function CM_initLeaveFullScreenItem() {
|
||||
// only show the option if the user is in DOM fullscreen
|
||||
var shouldShow = this.target.ownerDocument.fullscreen;
|
||||
this.showItem("context-leave-dom-fullscreen", shouldShow);
|
||||
@ -416,9 +473,9 @@ class nsContextMenu {
|
||||
if (shouldShow) {
|
||||
this.showItem("context-media-sep-commands", true);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
initSaveItems() {
|
||||
initSaveItems: function CM_initSaveItems() {
|
||||
var shouldShow = !(
|
||||
this.onTextInput ||
|
||||
this.onLink ||
|
||||
@ -458,9 +515,9 @@ class nsContextMenu {
|
||||
"disabled",
|
||||
!this.mediaURL || mediaIsBlob
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
initViewItems() {
|
||||
initViewItems: function CM_initViewItems() {
|
||||
// View source is always OK, unless in directory listing.
|
||||
this.showItem(
|
||||
"context-viewpartialsource-selection",
|
||||
@ -529,9 +586,8 @@ class nsContextMenu {
|
||||
);
|
||||
|
||||
if (haveSetDesktopBackground && this.onLoadedImage) {
|
||||
document.getElementById(
|
||||
"context-setDesktopBackground"
|
||||
).disabled = this.contentData.disableSetDesktopBackground;
|
||||
document.getElementById("context-setDesktopBackground").disabled =
|
||||
gContextMenuContentData.disableSetDesktopBackground;
|
||||
}
|
||||
|
||||
// Reload image depends on an image that's not fully loaded
|
||||
@ -578,9 +634,9 @@ class nsContextMenu {
|
||||
"context-viewimagedesc",
|
||||
this.onImage && this.imageDescURL !== ""
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
initMiscItems() {
|
||||
initMiscItems: function CM_initMiscItems() {
|
||||
// Use "Bookmark This Link" if on a link.
|
||||
let bookmarkPage = document.getElementById("context-bookmarkpage");
|
||||
this.showItem(
|
||||
@ -651,7 +707,7 @@ class nsContextMenu {
|
||||
"context-bidi-page-direction-toggle",
|
||||
!this.onTextInput && top.gBidiUI
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
initSpellingItems() {
|
||||
var canSpell =
|
||||
@ -706,7 +762,7 @@ class nsContextMenu {
|
||||
} else {
|
||||
this.showItem("spell-add-dictionaries-main", false);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
initClipboardItems() {
|
||||
// Copy depends on whether there is selected text.
|
||||
@ -767,7 +823,7 @@ class nsContextMenu {
|
||||
"context-sep-copyimage",
|
||||
this.onImage || this.onVideo || this.onAudio
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
initMediaPlayerItems() {
|
||||
var onMedia = this.onVideo || this.onAudio;
|
||||
@ -809,8 +865,6 @@ class nsContextMenu {
|
||||
!this.target.ownerDocument.fullscreen;
|
||||
this.showItem("context-video-pictureinpicture", shouldDisplay);
|
||||
}
|
||||
this.showItem("context-media-eme-learnmore", this.onDRMMedia);
|
||||
this.showItem("context-media-eme-separator", this.onDRMMedia);
|
||||
|
||||
// Disable them when there isn't a valid media source loaded.
|
||||
if (onMedia) {
|
||||
@ -878,17 +932,18 @@ class nsContextMenu {
|
||||
}
|
||||
}
|
||||
this.showItem("context-media-sep-commands", onMedia);
|
||||
}
|
||||
},
|
||||
|
||||
initClickToPlayItems() {
|
||||
this.showItem("context-ctp-play", this.onCTPPlugin);
|
||||
this.showItem("context-ctp-hide", this.onCTPPlugin);
|
||||
this.showItem("context-sep-ctp", this.onCTPPlugin);
|
||||
}
|
||||
},
|
||||
|
||||
initPasswordManagerItems() {
|
||||
let loginFillInfo = this.contentData && this.contentData.loginFillInfo;
|
||||
let documentURI = this.contentData.documentURIObject;
|
||||
let loginFillInfo =
|
||||
gContextMenuContentData && gContextMenuContentData.loginFillInfo;
|
||||
let documentURI = gContextMenuContentData.documentURIObject;
|
||||
|
||||
// If we could not find a password field we
|
||||
// don't want to show the form fill option.
|
||||
@ -932,7 +987,7 @@ class nsContextMenu {
|
||||
}
|
||||
|
||||
let formOrigin = LoginHelper.getLoginOrigin(documentURI.spec);
|
||||
let fragment = nsContextMenu.LoginManagerContextMenu.addLoginsToMenu(
|
||||
let fragment = LoginManagerContextMenu.addLoginsToMenu(
|
||||
this.targetIdentifier,
|
||||
this.browser,
|
||||
formOrigin
|
||||
@ -960,61 +1015,59 @@ class nsContextMenu {
|
||||
let popup = document.getElementById("fill-login-popup");
|
||||
let insertBeforeElement = document.getElementById("fill-login-no-logins");
|
||||
popup.insertBefore(fragment, insertBeforeElement);
|
||||
}
|
||||
},
|
||||
|
||||
initSyncItems() {
|
||||
gSync.updateContentContextMenu(this);
|
||||
}
|
||||
},
|
||||
|
||||
openPasswordManager() {
|
||||
LoginHelper.openPasswordManager(window, {
|
||||
filterString: this.contentData.documentURIObject.host,
|
||||
filterString: gContextMenuContentData.documentURIObject.host,
|
||||
entryPoint: "contextmenu",
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
fillGeneratedPassword() {
|
||||
nsContextMenu.LoginManagerContextMenu.fillGeneratedPassword(
|
||||
this.targetIdentifier,
|
||||
this.contentData.documentURIObject,
|
||||
this.browser
|
||||
);
|
||||
}
|
||||
LoginManagerContextMenu.fillGeneratedPassword(this.targetIdentifier,
|
||||
gContextMenuContentData.documentURIObject,
|
||||
this.browser);
|
||||
},
|
||||
|
||||
inspectNode() {
|
||||
return nsContextMenu.DevToolsShim.inspectNode(
|
||||
gBrowser.selectedTab,
|
||||
this.targetSelectors
|
||||
);
|
||||
}
|
||||
return DevToolsShim.inspectNode(gBrowser.selectedTab, this.targetSelectors);
|
||||
},
|
||||
|
||||
inspectA11Y() {
|
||||
return nsContextMenu.DevToolsShim.inspectA11Y(
|
||||
gBrowser.selectedTab,
|
||||
this.targetSelectors
|
||||
);
|
||||
}
|
||||
return DevToolsShim.inspectA11Y(gBrowser.selectedTab, this.targetSelectors);
|
||||
},
|
||||
|
||||
_openLinkInParameters(extra) {
|
||||
let params = {
|
||||
charset: this.contentData.charSet,
|
||||
charset: gContextMenuContentData.charSet,
|
||||
originPrincipal: this.principal,
|
||||
triggeringPrincipal: this.principal,
|
||||
csp: this.csp,
|
||||
frameOuterWindowID: this.contentData.frameOuterWindowID,
|
||||
frameOuterWindowID: gContextMenuContentData.frameOuterWindowID,
|
||||
};
|
||||
for (let p in extra) {
|
||||
params[p] = extra[p];
|
||||
}
|
||||
|
||||
if (!this.isRemote) {
|
||||
// Propagate the frameOuterWindowID value saved when
|
||||
// the context menu has been opened.
|
||||
params.frameOuterWindowID = this.frameOuterWindowID;
|
||||
}
|
||||
|
||||
let referrerInfo = this.onLink
|
||||
? this.contentData.linkReferrerInfo
|
||||
: this.contentData.referrerInfo;
|
||||
? gContextMenuContentData.linkReferrerInfo
|
||||
: gContextMenuContentData.referrerInfo;
|
||||
// If we want to change userContextId, we must be sure that we don't
|
||||
// propagate the referrer.
|
||||
if (
|
||||
("userContextId" in params &&
|
||||
params.userContextId != this.contentData.userContextId) ||
|
||||
params.userContextId != gContextMenuContentData.userContextId) ||
|
||||
this.onPlainTextLink
|
||||
) {
|
||||
referrerInfo = new ReferrerInfo(
|
||||
@ -1026,12 +1079,12 @@ class nsContextMenu {
|
||||
|
||||
params.referrerInfo = referrerInfo;
|
||||
return params;
|
||||
}
|
||||
},
|
||||
|
||||
// Open linked-to URL in a new window.
|
||||
openLink() {
|
||||
openLinkIn(this.linkURL, "window", this._openLinkInParameters());
|
||||
}
|
||||
},
|
||||
|
||||
// Open linked-to URL in a new private window.
|
||||
openLinkInPrivateWindow() {
|
||||
@ -1040,18 +1093,18 @@ class nsContextMenu {
|
||||
"window",
|
||||
this._openLinkInParameters({ private: true })
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
// Open linked-to URL in a new tab.
|
||||
openLinkInTab(event) {
|
||||
let referrerURI = this.contentData.documentURIObject;
|
||||
let referrerURI = gContextMenuContentData.documentURIObject;
|
||||
|
||||
// if its parent allows mixed content and the referring URI passes
|
||||
// a same origin check with the target URI, we can preserve the users
|
||||
// decision of disabling MCB on a page for it's child tabs.
|
||||
let persistAllowMixedContentInChildTab = false;
|
||||
|
||||
if (this.contentData.parentAllowsMixedContent) {
|
||||
if (gContextMenuContentData.parentAllowsMixedContent) {
|
||||
const sm = Services.scriptSecurityManager;
|
||||
try {
|
||||
let targetURI = this.linkURI;
|
||||
@ -1068,22 +1121,22 @@ class nsContextMenu {
|
||||
};
|
||||
|
||||
openLinkIn(this.linkURL, "tab", this._openLinkInParameters(params));
|
||||
}
|
||||
},
|
||||
|
||||
// open URL in current tab
|
||||
openLinkInCurrent() {
|
||||
openLinkIn(this.linkURL, "current", this._openLinkInParameters());
|
||||
}
|
||||
},
|
||||
|
||||
// Open frame in a new tab.
|
||||
openFrameInTab() {
|
||||
openLinkIn(this.contentData.docLocation, "tab", {
|
||||
charset: this.contentData.charSet,
|
||||
openLinkIn(gContextMenuContentData.docLocation, "tab", {
|
||||
charset: gContextMenuContentData.charSet,
|
||||
triggeringPrincipal: this.browser.contentPrincipal,
|
||||
csp: this.browser.csp,
|
||||
referrerInfo: this.contentData.frameReferrerInfo,
|
||||
referrerInfo: gContextMenuContentData.frameReferrerInfo,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// Reload clicked-in frame.
|
||||
reloadFrame(aEvent) {
|
||||
@ -1093,30 +1146,30 @@ class nsContextMenu {
|
||||
null,
|
||||
{ target: this.target, forceReload }
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
// Open clicked-in frame in its own window.
|
||||
openFrame() {
|
||||
openLinkIn(this.contentData.docLocation, "window", {
|
||||
charset: this.contentData.charSet,
|
||||
openLinkIn(gContextMenuContentData.docLocation, "window", {
|
||||
charset: gContextMenuContentData.charSet,
|
||||
triggeringPrincipal: this.browser.contentPrincipal,
|
||||
csp: this.browser.csp,
|
||||
referrerInfo: this.contentData.frameReferrerInfo,
|
||||
referrerInfo: gContextMenuContentData.frameReferrerInfo,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// Open clicked-in frame in the same window.
|
||||
showOnlyThisFrame() {
|
||||
urlSecurityCheck(
|
||||
this.contentData.docLocation,
|
||||
gContextMenuContentData.docLocation,
|
||||
this.browser.contentPrincipal,
|
||||
Ci.nsIScriptSecurityManager.DISALLOW_SCRIPT
|
||||
);
|
||||
openWebLinkIn(this.contentData.docLocation, "current", {
|
||||
referrerInfo: this.contentData.frameReferrerInfo,
|
||||
openWebLinkIn(gContextMenuContentData.docLocation, "current", {
|
||||
referrerInfo: gContextMenuContentData.frameReferrerInfo,
|
||||
triggeringPrincipal: this.browser.contentPrincipal,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// View Partial Source
|
||||
viewPartialSource() {
|
||||
@ -1149,36 +1202,36 @@ class nsContextMenu {
|
||||
};
|
||||
|
||||
top.gViewSourceUtils.viewPartialSourceInBrowser(browser, openSelectionFn);
|
||||
}
|
||||
},
|
||||
|
||||
// Open new "view source" window with the frame's URL.
|
||||
viewFrameSource() {
|
||||
BrowserViewSourceOfDocument({
|
||||
browser: this.browser,
|
||||
URL: this.contentData.docLocation,
|
||||
URL: gContextMenuContentData.docLocation,
|
||||
outerWindowID: this.frameOuterWindowID,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
viewInfo() {
|
||||
BrowserPageInfo(
|
||||
this.contentData.docLocation,
|
||||
gContextMenuContentData.docLocation,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
this.browser
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
viewImageInfo() {
|
||||
BrowserPageInfo(
|
||||
this.contentData.docLocation,
|
||||
gContextMenuContentData.docLocation,
|
||||
"mediaTab",
|
||||
this.imageInfo,
|
||||
null,
|
||||
this.browser
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
viewImageDesc(e) {
|
||||
urlSecurityCheck(
|
||||
@ -1187,21 +1240,21 @@ class nsContextMenu {
|
||||
Ci.nsIScriptSecurityManager.DISALLOW_SCRIPT
|
||||
);
|
||||
openUILink(this.imageDescURL, e, {
|
||||
referrerInfo: this.contentData.referrerInfo,
|
||||
referrerInfo: gContextMenuContentData.referrerInfo,
|
||||
triggeringPrincipal: this.principal,
|
||||
csp: this.csp,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
viewFrameInfo() {
|
||||
BrowserPageInfo(
|
||||
this.contentData.docLocation,
|
||||
gContextMenuContentData.docLocation,
|
||||
null,
|
||||
null,
|
||||
this.frameOuterWindowID,
|
||||
this.browser
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
reloadImage() {
|
||||
urlSecurityCheck(
|
||||
@ -1215,7 +1268,7 @@ class nsContextMenu {
|
||||
null,
|
||||
{ target: this.target }
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
_canvasToBlobURL(target) {
|
||||
let mm = this.browser.messageManager;
|
||||
@ -1231,11 +1284,11 @@ class nsContextMenu {
|
||||
};
|
||||
mm.addMessageListener("ContextMenu:Canvas:ToBlobURL:Result", onMessage);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// Change current window to the URL of the image, video, or audio.
|
||||
viewMedia(e) {
|
||||
let referrerInfo = this.contentData.referrerInfo;
|
||||
let referrerInfo = gContextMenuContentData.referrerInfo;
|
||||
let systemPrincipal = Services.scriptSecurityManager.getSystemPrincipal();
|
||||
if (this.onCanvas) {
|
||||
this._canvasToBlobURL(this.target).then(function(blobURL) {
|
||||
@ -1257,7 +1310,7 @@ class nsContextMenu {
|
||||
csp: this.csp,
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
saveVideoFrameAsImage() {
|
||||
let mm = this.browser.messageManager;
|
||||
@ -1286,7 +1339,7 @@ class nsContextMenu {
|
||||
);
|
||||
|
||||
// Cache this because we fetch the data async
|
||||
let referrerInfo = this.contentData.referrerInfo;
|
||||
let referrerInfo = gContextMenuContentData.referrerInfo;
|
||||
|
||||
let onMessage = message => {
|
||||
mm.removeMessageListener(
|
||||
@ -1316,11 +1369,11 @@ class nsContextMenu {
|
||||
"ContextMenu:SaveVideoFrameAsImage:Result",
|
||||
onMessage
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
leaveDOMFullScreen() {
|
||||
document.exitFullscreen();
|
||||
}
|
||||
},
|
||||
|
||||
// Change current window to the URL of the background image.
|
||||
viewBGImage(e) {
|
||||
@ -1331,11 +1384,11 @@ class nsContextMenu {
|
||||
);
|
||||
|
||||
openUILink(this.bgImageURL, e, {
|
||||
referrerInfo: this.contentData.referrerInfo,
|
||||
referrerInfo: gContextMenuContentData.referrerInfo,
|
||||
triggeringPrincipal: this.principal,
|
||||
csp: this.csp,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
setDesktopBackground() {
|
||||
let mm = this.browser.messageManager;
|
||||
@ -1402,12 +1455,12 @@ class nsContextMenu {
|
||||
"ContextMenu:SetAsDesktopBackground:Result",
|
||||
onMessage
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
// Save URL of clicked-on frame.
|
||||
saveFrame() {
|
||||
saveBrowser(this.browser, false, this.frameOuterWindowID);
|
||||
}
|
||||
},
|
||||
|
||||
// Helper function to wait for appropriate MIME-type headers and
|
||||
// then prompt the user with a file picker
|
||||
@ -1567,7 +1620,7 @@ class nsContextMenu {
|
||||
channel.loadFlags |= flags;
|
||||
|
||||
if (channel instanceof Ci.nsIHttpChannel) {
|
||||
channel.referrerInfo = E10SUtils.deserializeReferrerInfo(referrerInfo);
|
||||
channel.referrerInfo = referrerInfo;
|
||||
if (channel instanceof Ci.nsIHttpChannelInternal) {
|
||||
channel.forceAllowThirdPartyCookie = true;
|
||||
}
|
||||
@ -1586,15 +1639,17 @@ class nsContextMenu {
|
||||
|
||||
// kick off the channel with our proxy object as the listener
|
||||
channel.asyncOpen(new saveAsListener(this.principal));
|
||||
}
|
||||
},
|
||||
|
||||
// Save URL of clicked-on link.
|
||||
saveLink() {
|
||||
let referrerInfo = this.onLink
|
||||
? this.contentData.linkReferrerInfo
|
||||
: this.contentData.referrerInfo;
|
||||
? gContextMenuContentData.linkReferrerInfo
|
||||
: gContextMenuContentData.referrerInfo;
|
||||
|
||||
let isContentWindowPrivate = this.ownerDoc.isPrivate;
|
||||
let isContentWindowPrivate = this.isRemote
|
||||
? this.ownerDoc.isPrivate
|
||||
: undefined;
|
||||
this.saveHelper(
|
||||
this.linkURL,
|
||||
this.linkTextStr,
|
||||
@ -1606,20 +1661,22 @@ class nsContextMenu {
|
||||
this.linkDownload,
|
||||
isContentWindowPrivate
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
// Backwards-compatibility wrapper
|
||||
saveImage() {
|
||||
if (this.onCanvas || this.onImage) {
|
||||
this.saveMedia();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Save URL of the clicked upon image, video, or audio.
|
||||
saveMedia() {
|
||||
let doc = this.ownerDoc;
|
||||
let isContentWindowPrivate = this.ownerDoc.isPrivate;
|
||||
let referrerInfo = this.contentData.referrerInfo;
|
||||
let isContentWindowPrivate = this.isRemote
|
||||
? this.ownerDoc.isPrivate
|
||||
: undefined;
|
||||
let referrerInfo = gContextMenuContentData.referrerInfo;
|
||||
let isPrivate = PrivateBrowsingUtils.isBrowserPrivate(this.browser);
|
||||
if (this.onCanvas) {
|
||||
// Bypass cache, since it's a data: URL.
|
||||
@ -1647,8 +1704,8 @@ class nsContextMenu {
|
||||
this.mediaURL,
|
||||
null, // document
|
||||
null, // file name; we'll take it from the URL
|
||||
this.contentData.contentDisposition,
|
||||
this.contentData.contentType,
|
||||
gContextMenuContentData.contentDisposition,
|
||||
gContextMenuContentData.contentType,
|
||||
false, // do not bypass the cache
|
||||
"SaveImageTitle",
|
||||
null, // chosen data
|
||||
@ -1673,26 +1730,26 @@ class nsContextMenu {
|
||||
isContentWindowPrivate
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Backwards-compatibility wrapper
|
||||
sendImage() {
|
||||
if (this.onCanvas || this.onImage) {
|
||||
this.sendMedia();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
sendMedia() {
|
||||
MailIntegration.sendMessage(this.mediaURL, "");
|
||||
}
|
||||
},
|
||||
|
||||
playPlugin() {
|
||||
gPluginHandler.contextMenuCommand(this.browser, this.target, "play");
|
||||
}
|
||||
},
|
||||
|
||||
hidePlugin() {
|
||||
gPluginHandler.contextMenuCommand(this.browser, this.target, "hide");
|
||||
}
|
||||
},
|
||||
|
||||
// Generate email address and put it on clipboard.
|
||||
copyEmail() {
|
||||
@ -1718,7 +1775,7 @@ class nsContextMenu {
|
||||
Ci.nsIClipboardHelper
|
||||
);
|
||||
clipboard.copyString(addresses);
|
||||
}
|
||||
},
|
||||
|
||||
copyLink() {
|
||||
// If we're in a view source tab, remove the view-source: prefix
|
||||
@ -1727,7 +1784,7 @@ class nsContextMenu {
|
||||
Ci.nsIClipboardHelper
|
||||
);
|
||||
clipboard.copyString(linkURL);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Utilities
|
||||
@ -1749,7 +1806,7 @@ class nsContextMenu {
|
||||
if (item) {
|
||||
item.hidden = !aShow;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Set given attribute of specified context-menu item. If the
|
||||
// value is null, then it removes the attribute (which works
|
||||
@ -1765,7 +1822,7 @@ class nsContextMenu {
|
||||
elem.setAttribute(aAttr, aVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Temporary workaround for DOM api not yet implemented by XUL nodes.
|
||||
cloneNode(aItem) {
|
||||
@ -1781,7 +1838,7 @@ class nsContextMenu {
|
||||
|
||||
// Voila!
|
||||
return node;
|
||||
}
|
||||
},
|
||||
|
||||
getLinkURI() {
|
||||
try {
|
||||
@ -1791,12 +1848,12 @@ class nsContextMenu {
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
// Kept for addon compat
|
||||
linkText() {
|
||||
return this.linkTextStr;
|
||||
}
|
||||
},
|
||||
|
||||
// Determines whether or not the separator with the specified ID should be
|
||||
// shown or not by determining if there are any non-hidden items between it
|
||||
@ -1813,7 +1870,7 @@ class nsContextMenu {
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
addDictionaries() {
|
||||
var uri = formatURL("browser.dictionaries.download.url", true);
|
||||
@ -1839,21 +1896,21 @@ class nsContextMenu {
|
||||
var where = newWindowPref == 3 ? "tab" : "window";
|
||||
|
||||
openTrustedLinkIn(uri, where);
|
||||
}
|
||||
},
|
||||
|
||||
bookmarkThisPage() {
|
||||
bookmarkThisPage: function CM_bookmarkThisPage() {
|
||||
window.top.PlacesCommandHook.bookmarkPage().catch(Cu.reportError);
|
||||
}
|
||||
},
|
||||
|
||||
bookmarkLink() {
|
||||
bookmarkLink: function CM_bookmarkLink() {
|
||||
window.top.PlacesCommandHook.bookmarkLink(
|
||||
this.linkURL,
|
||||
this.linkTextStr
|
||||
).catch(Cu.reportError);
|
||||
}
|
||||
},
|
||||
|
||||
addBookmarkForFrame() {
|
||||
let uri = this.contentData.documentURIObject;
|
||||
addBookmarkForFrame: function CM_addBookmarkForFrame() {
|
||||
let uri = gContextMenuContentData.documentURIObject;
|
||||
let mm = this.browser.messageManager;
|
||||
|
||||
let onMessage = message => {
|
||||
@ -1869,21 +1926,21 @@ class nsContextMenu {
|
||||
mm.sendAsyncMessage("ContextMenu:BookmarkFrame", null, {
|
||||
target: this.target,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
savePageAs() {
|
||||
savePageAs: function CM_savePageAs() {
|
||||
saveBrowser(this.browser);
|
||||
}
|
||||
},
|
||||
|
||||
printFrame() {
|
||||
printFrame: function CM_printFrame() {
|
||||
PrintUtils.printWindow(this.frameOuterWindowID, this.browser);
|
||||
}
|
||||
},
|
||||
|
||||
switchPageDirection() {
|
||||
switchPageDirection: function CM_switchPageDirection() {
|
||||
this.browser.messageManager.sendAsyncMessage("SwitchDocumentDirection");
|
||||
}
|
||||
},
|
||||
|
||||
mediaCommand(command, data) {
|
||||
mediaCommand: function CM_mediaCommand(command, data) {
|
||||
let mm = this.browser.messageManager;
|
||||
let win = this.browser.ownerGlobal;
|
||||
let windowUtils = win.windowUtils;
|
||||
@ -1892,14 +1949,14 @@ class nsContextMenu {
|
||||
{ command, data, handlingUserInput: windowUtils.isHandlingUserInput },
|
||||
{ element: this.target }
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
copyMediaLocation() {
|
||||
var clipboard = Cc["@mozilla.org/widget/clipboardhelper;1"].getService(
|
||||
Ci.nsIClipboardHelper
|
||||
);
|
||||
clipboard.copyString(this.mediaURL);
|
||||
}
|
||||
},
|
||||
|
||||
drmLearnMore(aEvent) {
|
||||
let drmInfoURL =
|
||||
@ -1912,14 +1969,14 @@ class nsContextMenu {
|
||||
dest = "tab";
|
||||
}
|
||||
openTrustedLinkIn(drmInfoURL, dest);
|
||||
}
|
||||
},
|
||||
|
||||
get imageURL() {
|
||||
if (this.onImage) {
|
||||
return this.mediaURL;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
},
|
||||
|
||||
// Formats the 'Search <engine> for "<selection or link text>"' context menu.
|
||||
formatSearchContextItem() {
|
||||
@ -1955,18 +2012,13 @@ class nsContextMenu {
|
||||
menuItem.accessKey = gNavigatorBundle.getString(
|
||||
"contextMenuSearch.accesskey"
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
createContainerMenu(aEvent) {
|
||||
let createMenuOptions = {
|
||||
isContextMenu: true,
|
||||
excludeUserContextId: this.contentData.userContextId,
|
||||
excludeUserContextId: gContextMenuContentData.userContextId,
|
||||
};
|
||||
return createUserContextMenu(aEvent, createMenuOptions);
|
||||
}
|
||||
}
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(nsContextMenu, {
|
||||
LoginManagerContextMenu: "resource://gre/modules/LoginManagerContextMenu.jsm",
|
||||
DevToolsShim: "chrome://devtools-startup/content/DevToolsShim.jsm",
|
||||
});
|
||||
},
|
||||
};
|
||||
|
@ -52,12 +52,11 @@
|
||||
}
|
||||
|
||||
let messageManager = window.getGroupMessageManager("browsers");
|
||||
window.messageManager.addMessageListener("contextmenu", this);
|
||||
|
||||
if (gMultiProcessBrowser) {
|
||||
messageManager.addMessageListener("DOMTitleChanged", this);
|
||||
messageManager.addMessageListener("DOMWindowClose", this);
|
||||
messageManager.addMessageListener("DOMWindowClose", this);
|
||||
window.messageManager.addMessageListener("contextmenu", this);
|
||||
messageManager.addMessageListener("Browser:Init", this);
|
||||
} else {
|
||||
this._outerWindowIDBrowserMap.set(
|
||||
@ -2939,10 +2938,6 @@
|
||||
},
|
||||
|
||||
warnAboutClosingTabs(tabsToClose, aCloseTabs) {
|
||||
if (tabsToClose <= 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const pref =
|
||||
aCloseTabs == this.closingTabsEnum.ALL
|
||||
? "browser.tabs.warnOnClose"
|
||||
|
@ -27,7 +27,7 @@ add_task(async function() {
|
||||
let contextMenuPromise = BrowserTestUtils.waitForEvent(
|
||||
contextMenu,
|
||||
"popupshown"
|
||||
);
|
||||
).then(() => gContextMenuContentData.target);
|
||||
|
||||
await ContentTask.spawn(
|
||||
tab.linkedBrowser,
|
||||
|
@ -92,9 +92,6 @@ tags = blocklist
|
||||
[browser_blocklist_content.js]
|
||||
skip-if = !e10s
|
||||
tags = blocklist
|
||||
[browser_enable_DRM_prompt.js]
|
||||
skip-if = (os == 'win' && processor == 'aarch64') # bug 1533164
|
||||
[browser_private_browsing_eme_persistent_state.js]
|
||||
[browser_globalplugin_crashinfobar.js]
|
||||
skip-if = !crashreporter
|
||||
[browser_pluginCrashCommentAndURL.js]
|
||||
|
@ -1,143 +0,0 @@
|
||||
/*
|
||||
* Bug 1366167 - Tests that the "Enable DRM" prompt shows if EME is requested while EME is disabled.
|
||||
*/
|
||||
|
||||
const TEST_URL =
|
||||
getRootDirectory(gTestPath).replace(
|
||||
"chrome://mochitests/content",
|
||||
"https://example.com"
|
||||
) + "empty_file.html";
|
||||
|
||||
add_task(async function() {
|
||||
await BrowserTestUtils.withNewTab(TEST_URL, async function(browser) {
|
||||
// Note: SpecialPowers.pushPrefEnv has problems with the "Enable DRM"
|
||||
// button on the notification box toggling the prefs. So manually
|
||||
// set/unset the prefs the UI we're testing toggles.
|
||||
let emeWasEnabled = Services.prefs.getBoolPref("media.eme.enabled", false);
|
||||
let cdmWasEnabled = Services.prefs.getBoolPref(
|
||||
"media.gmp-widevinecdm.enabled",
|
||||
false
|
||||
);
|
||||
|
||||
// Restore the preferences to their pre-test state on test finish.
|
||||
registerCleanupFunction(function() {
|
||||
Services.prefs.setBoolPref("media.eme.enabled", emeWasEnabled);
|
||||
Services.prefs.setBoolPref(
|
||||
"media.gmp-widevinecdm.enabled",
|
||||
cdmWasEnabled
|
||||
);
|
||||
});
|
||||
|
||||
// Turn off EME and Widevine CDM.
|
||||
Services.prefs.setBoolPref("media.eme.enabled", false);
|
||||
Services.prefs.setBoolPref("media.gmp-widevinecdm.enabled", false);
|
||||
|
||||
// Have content request access to Widevine, UI should drop down to
|
||||
// prompt user to enable DRM.
|
||||
let result = await ContentTask.spawn(browser, {}, async function() {
|
||||
try {
|
||||
let config = [
|
||||
{
|
||||
initDataTypes: ["webm"],
|
||||
videoCapabilities: [{ contentType: 'video/webm; codecs="vp9"' }],
|
||||
},
|
||||
];
|
||||
await content.navigator.requestMediaKeySystemAccess(
|
||||
"com.widevine.alpha",
|
||||
config
|
||||
);
|
||||
} catch (ex) {
|
||||
return { rejected: true };
|
||||
}
|
||||
return { rejected: false };
|
||||
});
|
||||
is(
|
||||
result.rejected,
|
||||
true,
|
||||
"EME request should be denied because EME disabled."
|
||||
);
|
||||
|
||||
// Verify the UI prompt showed.
|
||||
let box = gBrowser.getNotificationBox(browser);
|
||||
let notification = box.currentNotification;
|
||||
|
||||
ok(notification, "Notification should be visible");
|
||||
is(
|
||||
notification.getAttribute("value"),
|
||||
"drmContentDisabled",
|
||||
"Should be showing the right notification"
|
||||
);
|
||||
|
||||
// Verify the "Enable DRM" button is there.
|
||||
let buttons = notification.querySelectorAll(".notification-button");
|
||||
is(buttons.length, 1, "Should have one button.");
|
||||
|
||||
// Prepare a Promise that should resolve when the "Enable DRM" button's
|
||||
// page reload completes.
|
||||
let refreshPromise = BrowserTestUtils.browserLoaded(browser);
|
||||
buttons[0].click();
|
||||
|
||||
// Wait for the reload to complete.
|
||||
await refreshPromise;
|
||||
|
||||
// Verify clicking the "Enable DRM" button enabled DRM.
|
||||
let enabled = Services.prefs.getBoolPref("media.eme.enabled", true);
|
||||
is(
|
||||
enabled,
|
||||
true,
|
||||
"EME should be enabled after click on 'Enable DRM' button"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_eme_locked() {
|
||||
await BrowserTestUtils.withNewTab(TEST_URL, async function(browser) {
|
||||
// Reset prefs manually since we need to unlock them.
|
||||
let emeWasEnabled = Services.prefs.getBoolPref("media.eme.enabled", false);
|
||||
|
||||
// Restore the preferences to their pre-test state on test finish.
|
||||
registerCleanupFunction(function() {
|
||||
Services.prefs.setBoolPref("media.eme.enabled", emeWasEnabled);
|
||||
Services.prefs.unlockPref("media.eme.enabled");
|
||||
});
|
||||
|
||||
// Turn off EME and Widevine CDM.
|
||||
Services.prefs.setBoolPref("media.eme.enabled", false);
|
||||
Services.prefs.lockPref("media.eme.enabled");
|
||||
|
||||
// Have content request access to Widevine, UI should drop down to
|
||||
// prompt user to enable DRM.
|
||||
let result = await ContentTask.spawn(browser, null, async function() {
|
||||
try {
|
||||
let config = [
|
||||
{
|
||||
initDataTypes: ["webm"],
|
||||
videoCapabilities: [{ contentType: 'video/webm; codecs="vp9"' }],
|
||||
},
|
||||
];
|
||||
await content.navigator.requestMediaKeySystemAccess(
|
||||
"com.widevine.alpha",
|
||||
config
|
||||
);
|
||||
} catch (ex) {
|
||||
return { rejected: true };
|
||||
}
|
||||
return { rejected: false };
|
||||
});
|
||||
is(
|
||||
result.rejected,
|
||||
true,
|
||||
"EME request should be denied because EME disabled."
|
||||
);
|
||||
|
||||
// Verify the UI prompt did not show.
|
||||
let box = gBrowser.getNotificationBox(browser);
|
||||
let notification = box.currentNotification;
|
||||
|
||||
is(
|
||||
notification,
|
||||
null,
|
||||
"Notification should not be displayed since pref is locked"
|
||||
);
|
||||
});
|
||||
});
|
@ -1,59 +0,0 @@
|
||||
/* 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 test ensures that navigator.requestMediaKeySystemAccess() requests
|
||||
* to run EME with persistent state are rejected in private browsing windows.
|
||||
* Bug 1334111.
|
||||
*/
|
||||
|
||||
const TEST_URL =
|
||||
getRootDirectory(gTestPath).replace(
|
||||
"chrome://mochitests/content",
|
||||
"https://example.com"
|
||||
) + "empty_file.html";
|
||||
|
||||
async function isEmePersistentStateSupported(mode) {
|
||||
let win = await BrowserTestUtils.openNewBrowserWindow(mode);
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab(win.gBrowser, TEST_URL);
|
||||
let persistentStateSupported = await ContentTask.spawn(
|
||||
tab.linkedBrowser,
|
||||
{},
|
||||
async function() {
|
||||
try {
|
||||
let config = [
|
||||
{
|
||||
initDataTypes: ["webm"],
|
||||
videoCapabilities: [{ contentType: 'video/webm; codecs="vp9"' }],
|
||||
persistentState: "required",
|
||||
},
|
||||
];
|
||||
await content.navigator.requestMediaKeySystemAccess(
|
||||
"org.w3.clearkey",
|
||||
config
|
||||
);
|
||||
} catch (ex) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
|
||||
return persistentStateSupported;
|
||||
}
|
||||
|
||||
add_task(async function test() {
|
||||
is(
|
||||
await isEmePersistentStateSupported({ private: true }),
|
||||
false,
|
||||
"EME persistentState should *NOT* be supported in private browsing window."
|
||||
);
|
||||
is(
|
||||
await isEmePersistentStateSupported({ private: false }),
|
||||
true,
|
||||
"EME persistentState *SHOULD* be supported in non private browsing window."
|
||||
);
|
||||
});
|
@ -11,13 +11,15 @@ add_task(async function() {
|
||||
|
||||
let promiseTabOpened = BrowserTestUtils.waitForNewTab(
|
||||
gBrowser,
|
||||
FILE + "?opened",
|
||||
FILE + "?open-click",
|
||||
true
|
||||
);
|
||||
info("Opening second tab using a click");
|
||||
await ContentTask.spawn(firstTab.linkedBrowser, "", async function() {
|
||||
content.document.querySelector("#open").click();
|
||||
});
|
||||
await BrowserTestUtils.synthesizeMouseAtCenter(
|
||||
"#open-click",
|
||||
{},
|
||||
firstTab.linkedBrowser
|
||||
);
|
||||
|
||||
info("Waiting for the second tab to be opened");
|
||||
let secondTab = await promiseTabOpened;
|
||||
@ -34,6 +36,43 @@ add_task(async function() {
|
||||
|
||||
is(gBrowser.selectedTab, secondTab, "Should've switched tabs");
|
||||
|
||||
BrowserTestUtils.removeTab(firstTab);
|
||||
BrowserTestUtils.removeTab(secondTab);
|
||||
await BrowserTestUtils.removeTab(firstTab);
|
||||
await BrowserTestUtils.removeTab(secondTab);
|
||||
});
|
||||
|
||||
add_task(async function() {
|
||||
info("Opening first tab: " + FILE);
|
||||
let firstTab = await BrowserTestUtils.openNewForegroundTab(gBrowser, FILE);
|
||||
|
||||
let promiseTabOpened = BrowserTestUtils.waitForNewTab(
|
||||
gBrowser,
|
||||
FILE + "?open-mousedown",
|
||||
true
|
||||
);
|
||||
info("Opening second tab using a click");
|
||||
await BrowserTestUtils.synthesizeMouseAtCenter(
|
||||
"#open-mousedown",
|
||||
{ type: "mousedown" },
|
||||
firstTab.linkedBrowser
|
||||
);
|
||||
|
||||
info("Waiting for the second tab to be opened");
|
||||
let secondTab = await promiseTabOpened;
|
||||
|
||||
is(gBrowser.selectedTab, secondTab, "Should've switched tabs");
|
||||
|
||||
info("Ensuring we don't switch back");
|
||||
await new Promise(resolve => {
|
||||
// We need to wait for something _not_ happening, so we need to use an arbitrary setTimeout.
|
||||
//
|
||||
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
|
||||
setTimeout(function() {
|
||||
is(gBrowser.selectedTab, secondTab, "Should've remained in original tab");
|
||||
resolve();
|
||||
}, 500);
|
||||
});
|
||||
|
||||
info("cleanup");
|
||||
await BrowserTestUtils.removeTab(firstTab);
|
||||
await BrowserTestUtils.removeTab(secondTab);
|
||||
});
|
||||
|
@ -1,8 +1,15 @@
|
||||
<!doctype html>
|
||||
<script>
|
||||
function openWindow() {
|
||||
window.childWindow = window.open(location.href + "?opened", "", "");
|
||||
function openWindow(id) {
|
||||
window.childWindow = window.open(location.href + "?" + id, "", "");
|
||||
}
|
||||
</script>
|
||||
<button id="open" onclick="openWindow()">Open window</button>
|
||||
<button id="open-click" onclick="openWindow('open-click')">Open window</button>
|
||||
<button id="focus" onclick="window.childWindow.focus()">Focus window</button>
|
||||
<button id="open-mousedown">Open window</button>
|
||||
<script>
|
||||
document.getElementById("open-mousedown").addEventListener("mousedown", function(e) {
|
||||
openWindow(this.id);
|
||||
e.preventDefault();
|
||||
});
|
||||
</script>
|
||||
|
@ -364,7 +364,7 @@ function openLinkIn(url, where, params) {
|
||||
var aPostData = params.postData;
|
||||
var aCharset = params.charset;
|
||||
var aReferrerInfo = params.referrerInfo
|
||||
? E10SUtils.deserializeReferrerInfo(params.referrerInfo)
|
||||
? params.referrerInfo
|
||||
: new ReferrerInfo(Ci.nsIReferrerInfo.EMPTY, true, null);
|
||||
var aRelatedToCurrent = params.relatedToCurrent;
|
||||
var aAllowInheritPrincipal = !!params.allowInheritPrincipal;
|
||||
|
@ -893,9 +893,6 @@ BrowserGlue.prototype = {
|
||||
);
|
||||
}
|
||||
break;
|
||||
case "flash-plugin-hang":
|
||||
this._handleFlashHang();
|
||||
break;
|
||||
case "xpi-signature-changed":
|
||||
let disabledAddons = JSON.parse(data).disabled;
|
||||
let addons = await AddonManager.getAddonsByIDs(disabledAddons);
|
||||
@ -948,7 +945,6 @@ BrowserGlue.prototype = {
|
||||
os.addObserver(this, "keyword-search");
|
||||
os.addObserver(this, "browser-search-engine-modified");
|
||||
os.addObserver(this, "restart-in-safe-mode");
|
||||
os.addObserver(this, "flash-plugin-hang");
|
||||
os.addObserver(this, "xpi-signature-changed");
|
||||
os.addObserver(this, "sync-ui-state:update");
|
||||
os.addObserver(this, "handlersvc-store-initialized");
|
||||
@ -957,7 +953,6 @@ BrowserGlue.prototype = {
|
||||
ActorManagerParent.addLegacyActors(LEGACY_ACTORS);
|
||||
ActorManagerParent.flush();
|
||||
|
||||
this._flashHangCount = 0;
|
||||
this._firstWindowReady = new Promise(
|
||||
resolve => (this._firstWindowLoaded = resolve)
|
||||
);
|
||||
@ -1012,7 +1007,6 @@ BrowserGlue.prototype = {
|
||||
os.removeObserver(this, "profile-before-change");
|
||||
os.removeObserver(this, "keyword-search");
|
||||
os.removeObserver(this, "browser-search-engine-modified");
|
||||
os.removeObserver(this, "flash-plugin-hang");
|
||||
os.removeObserver(this, "xpi-signature-changed");
|
||||
os.removeObserver(this, "sync-ui-state:update");
|
||||
|
||||
@ -2046,12 +2040,10 @@ BrowserGlue.prototype = {
|
||||
? "tabs.closeWarningMultipleSessionRestore2"
|
||||
: "tabs.closeWarningMultiple";
|
||||
warningMessage = gTabbrowserBundle.GetStringFromName(stringID);
|
||||
if (pagecount > 1) {
|
||||
warningMessage = PluralForm.get(pagecount, warningMessage).replace(
|
||||
"#1",
|
||||
pagecount
|
||||
);
|
||||
}
|
||||
warningMessage = PluralForm.get(pagecount, warningMessage).replace(
|
||||
"#1",
|
||||
pagecount
|
||||
);
|
||||
}
|
||||
|
||||
let warnOnClose = { value: true };
|
||||
@ -3314,67 +3306,6 @@ BrowserGlue.prototype = {
|
||||
);
|
||||
},
|
||||
|
||||
_handleFlashHang() {
|
||||
++this._flashHangCount;
|
||||
if (this._flashHangCount < 2) {
|
||||
return;
|
||||
}
|
||||
// protected mode only applies to win32
|
||||
if (Services.appinfo.XPCOMABI != "x86-msvc") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
Services.prefs.getBoolPref("dom.ipc.plugins.flash.disable-protected-mode")
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if (
|
||||
!Services.prefs.getBoolPref("browser.flash-protected-mode-flip.enable")
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if (Services.prefs.getBoolPref("browser.flash-protected-mode-flip.done")) {
|
||||
return;
|
||||
}
|
||||
Services.prefs.setBoolPref(
|
||||
"dom.ipc.plugins.flash.disable-protected-mode",
|
||||
true
|
||||
);
|
||||
Services.prefs.setBoolPref("browser.flash-protected-mode-flip.done", true);
|
||||
|
||||
let win = BrowserWindowTracker.getTopWindow();
|
||||
if (!win) {
|
||||
return;
|
||||
}
|
||||
let productName = gBrandBundle.GetStringFromName("brandShortName");
|
||||
let message = win.gNavigatorBundle.getFormattedString("flashHang.message", [
|
||||
productName,
|
||||
]);
|
||||
let buttons = [
|
||||
{
|
||||
label: win.gNavigatorBundle.getString("flashHang.helpButton.label"),
|
||||
accessKey: win.gNavigatorBundle.getString(
|
||||
"flashHang.helpButton.accesskey"
|
||||
),
|
||||
callback() {
|
||||
win.openTrustedLinkIn(
|
||||
"https://support.mozilla.org/kb/flash-protected-mode-autodisabled",
|
||||
"tab"
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
win.gNotificationBox.appendNotification(
|
||||
message,
|
||||
"flash-hang",
|
||||
null,
|
||||
win.gNotificationBox.PRIORITY_INFO_MEDIUM,
|
||||
buttons
|
||||
);
|
||||
},
|
||||
|
||||
_updateFxaBadges() {
|
||||
let state = UIState.get();
|
||||
if (
|
||||
|
@ -8,14 +8,11 @@ support-files =
|
||||
worker.js
|
||||
|
||||
[browser_aboutURLs.js]
|
||||
[browser_eme.js]
|
||||
skip-if = (os == "win" && processor == "aarch64") # bug 1531927
|
||||
[browser_favicon.js]
|
||||
[browser_forgetaboutsite.js]
|
||||
skip-if = true # Bug 1541885
|
||||
[browser_forgetAPI_cookie_getCookiesWithOriginAttributes.js]
|
||||
[browser_restore_getCookiesWithOriginAttributes.js]
|
||||
[browser_forgetAPI_EME_forgetThisSite.js]
|
||||
skip-if = (os == "win" && processor == "aarch64") # bug 1531927
|
||||
[browser_forgetAPI_quota_clearStoragesForPrincipal.js]
|
||||
skip-if = verify
|
||||
|
@ -1,217 +0,0 @@
|
||||
/*
|
||||
* Bug 1283325 - A test case to test the EME is originAttributes aware or not.
|
||||
*/
|
||||
const CC = Components.Constructor;
|
||||
|
||||
const TEST_HOST = "example.com";
|
||||
const TEST_URL =
|
||||
"http://" +
|
||||
TEST_HOST +
|
||||
"/browser/browser/components/contextualidentity/test/browser/";
|
||||
|
||||
const TESTKEY = {
|
||||
initDataType: "keyids",
|
||||
initData: '{"kids":["LwVHf8JLtPrv2GUXFW2v_A"], "type":"persistent-license"}',
|
||||
kid: "LwVHf8JLtPrv2GUXFW2v_A",
|
||||
key: "97b9ddc459c8d5ff23c1f2754c95abe8",
|
||||
sessionType: "persistent-license",
|
||||
};
|
||||
|
||||
const USER_ID_DEFAULT = 0;
|
||||
const USER_ID_PERSONAL = 1;
|
||||
|
||||
async function openTabInUserContext(uri, userContextId) {
|
||||
// Open the tab in the correct userContextId.
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, uri, { userContextId });
|
||||
|
||||
// Select tab and make sure its browser is focused.
|
||||
gBrowser.selectedTab = tab;
|
||||
tab.ownerGlobal.focus();
|
||||
|
||||
let browser = gBrowser.getBrowserForTab(tab);
|
||||
await BrowserTestUtils.browserLoaded(browser);
|
||||
return { tab, browser };
|
||||
}
|
||||
|
||||
function HexToBase64(hex) {
|
||||
var bin = "";
|
||||
for (var i = 0; i < hex.length; i += 2) {
|
||||
bin += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
|
||||
}
|
||||
return window
|
||||
.btoa(bin)
|
||||
.replace(/=/g, "")
|
||||
.replace(/\+/g, "-")
|
||||
.replace(/\//g, "_");
|
||||
}
|
||||
|
||||
function Base64ToHex(str) {
|
||||
var bin = window.atob(str.replace(/-/g, "+").replace(/_/g, "/"));
|
||||
var res = "";
|
||||
for (var i = 0; i < bin.length; i++) {
|
||||
res += ("0" + bin.charCodeAt(i).toString(16)).substr(-2);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
function ByteArrayToHex(array) {
|
||||
let bin = String.fromCharCode.apply(null, new Uint8Array(array));
|
||||
let res = "";
|
||||
|
||||
for (let i = 0; i < bin.length; i++) {
|
||||
res += ("0" + bin.charCodeAt(i).toString(16)).substr(-2);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
function generateKeyObject(aKid, aKey) {
|
||||
let keyObj = {
|
||||
kty: "oct",
|
||||
kid: aKid,
|
||||
k: HexToBase64(aKey),
|
||||
};
|
||||
|
||||
return new TextEncoder().encode(
|
||||
JSON.stringify({
|
||||
keys: [keyObj],
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
function generateKeyInfo(aData) {
|
||||
let keyInfo = {
|
||||
initDataType: aData.initDataType,
|
||||
initData: new TextEncoder().encode(aData.initData),
|
||||
sessionType: aData.sessionType,
|
||||
keyObj: generateKeyObject(aData.kid, aData.key),
|
||||
};
|
||||
|
||||
return keyInfo;
|
||||
}
|
||||
|
||||
add_task(async function setup() {
|
||||
// Make sure userContext is enabled.
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["privacy.userContext.enabled", true],
|
||||
["media.mediasource.enabled", true],
|
||||
["media.mediasource.webm.enabled", true],
|
||||
["media.clearkey.persistent-license.enabled", true],
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test() {
|
||||
// Open a tab with the default container.
|
||||
let defaultContainer = await openTabInUserContext(
|
||||
TEST_URL + "empty_file.html",
|
||||
USER_ID_DEFAULT
|
||||
);
|
||||
|
||||
// Generate the key info for the default container.
|
||||
let keyInfo = generateKeyInfo(TESTKEY);
|
||||
|
||||
// Update the media key for the default container.
|
||||
let result = await ContentTask.spawn(
|
||||
defaultContainer.browser,
|
||||
keyInfo,
|
||||
async function(aKeyInfo) {
|
||||
let access = await content.navigator.requestMediaKeySystemAccess(
|
||||
"org.w3.clearkey",
|
||||
[
|
||||
{
|
||||
initDataTypes: [aKeyInfo.initDataType],
|
||||
videoCapabilities: [{ contentType: "video/webm" }],
|
||||
sessionTypes: ["persistent-license"],
|
||||
persistentState: "required",
|
||||
},
|
||||
]
|
||||
);
|
||||
let mediaKeys = await access.createMediaKeys();
|
||||
let session = mediaKeys.createSession(aKeyInfo.sessionType);
|
||||
let res = {};
|
||||
|
||||
// Insert the media key.
|
||||
await new Promise(resolve => {
|
||||
session.addEventListener("message", function(event) {
|
||||
session
|
||||
.update(aKeyInfo.keyObj)
|
||||
.then(() => {
|
||||
resolve();
|
||||
})
|
||||
.catch(() => {
|
||||
ok(false, "Update the media key fail.");
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
session.generateRequest(aKeyInfo.initDataType, aKeyInfo.initData);
|
||||
});
|
||||
|
||||
let map = session.keyStatuses;
|
||||
|
||||
is(map.size, 1, "One media key has been added.");
|
||||
|
||||
if (map.size === 1) {
|
||||
res.keyId = map.keys().next().value;
|
||||
res.sessionId = session.sessionId;
|
||||
}
|
||||
|
||||
// Close the session.
|
||||
session.close();
|
||||
await session.closed;
|
||||
|
||||
return res;
|
||||
}
|
||||
);
|
||||
|
||||
// Check the media key ID.
|
||||
is(
|
||||
ByteArrayToHex(result.keyId),
|
||||
Base64ToHex(TESTKEY.kid),
|
||||
"The key Id of the default container is correct."
|
||||
);
|
||||
|
||||
// Store the sessionId for the further checking.
|
||||
keyInfo.sessionId = result.sessionId;
|
||||
|
||||
// Open a tab with personal container.
|
||||
let personalContainer = await openTabInUserContext(
|
||||
TEST_URL + "empty_file.html",
|
||||
USER_ID_PERSONAL
|
||||
);
|
||||
|
||||
await ContentTask.spawn(personalContainer.browser, keyInfo, async function(
|
||||
aKeyInfo
|
||||
) {
|
||||
let access = await content.navigator.requestMediaKeySystemAccess(
|
||||
"org.w3.clearkey",
|
||||
[
|
||||
{
|
||||
initDataTypes: [aKeyInfo.initDataType],
|
||||
videoCapabilities: [{ contentType: "video/webm" }],
|
||||
sessionTypes: ["persistent-license"],
|
||||
persistentState: "required",
|
||||
},
|
||||
]
|
||||
);
|
||||
let mediaKeys = await access.createMediaKeys();
|
||||
let session = mediaKeys.createSession(aKeyInfo.sessionType);
|
||||
|
||||
// First, load the session to check that mediakeys do not share with
|
||||
// default container.
|
||||
await session.load(aKeyInfo.sessionId);
|
||||
|
||||
let map = session.keyStatuses;
|
||||
|
||||
// Check that there is no media key here.
|
||||
is(map.size, 0, "No media key should be here for the personal container.");
|
||||
});
|
||||
|
||||
// Close default container tab.
|
||||
BrowserTestUtils.removeTab(defaultContainer.tab);
|
||||
|
||||
// Close personal container tab.
|
||||
BrowserTestUtils.removeTab(personalContainer.tab);
|
||||
});
|
@ -1,257 +0,0 @@
|
||||
/*
|
||||
* Bug 1278037 - A Test case for checking whether forgetting APIs are working for the media key.
|
||||
*/
|
||||
|
||||
const CC = Components.Constructor;
|
||||
|
||||
const TEST_HOST = "example.com";
|
||||
const TEST_URL =
|
||||
"http://" +
|
||||
TEST_HOST +
|
||||
"/browser/browser/components/contextualidentity/test/browser/";
|
||||
|
||||
const USER_CONTEXTS = ["default", "personal"];
|
||||
|
||||
const TEST_EME_KEY = {
|
||||
initDataType: "keyids",
|
||||
initData: '{"kids":["LwVHf8JLtPrv2GUXFW2v_A"], "type":"persistent-license"}',
|
||||
kid: "LwVHf8JLtPrv2GUXFW2v_A",
|
||||
key: "97b9ddc459c8d5ff23c1f2754c95abe8",
|
||||
sessionType: "persistent-license",
|
||||
};
|
||||
|
||||
//
|
||||
// Support functions.
|
||||
//
|
||||
|
||||
async function openTabInUserContext(uri, userContextId) {
|
||||
// Open the tab in the correct userContextId.
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, uri, { userContextId });
|
||||
|
||||
// Select tab and make sure its browser is focused.
|
||||
gBrowser.selectedTab = tab;
|
||||
tab.ownerGlobal.focus();
|
||||
|
||||
let browser = gBrowser.getBrowserForTab(tab);
|
||||
await BrowserTestUtils.browserLoaded(browser);
|
||||
return { tab, browser };
|
||||
}
|
||||
|
||||
function HexToBase64(hex) {
|
||||
var bin = "";
|
||||
for (var i = 0; i < hex.length; i += 2) {
|
||||
bin += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
|
||||
}
|
||||
return window
|
||||
.btoa(bin)
|
||||
.replace(/=/g, "")
|
||||
.replace(/\+/g, "-")
|
||||
.replace(/\//g, "_");
|
||||
}
|
||||
|
||||
function Base64ToHex(str) {
|
||||
var bin = window.atob(str.replace(/-/g, "+").replace(/_/g, "/"));
|
||||
var res = "";
|
||||
for (var i = 0; i < bin.length; i++) {
|
||||
res += ("0" + bin.charCodeAt(i).toString(16)).substr(-2);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
function ByteArrayToHex(array) {
|
||||
let bin = String.fromCharCode.apply(null, new Uint8Array(array));
|
||||
let res = "";
|
||||
|
||||
for (let i = 0; i < bin.length; i++) {
|
||||
res += ("0" + bin.charCodeAt(i).toString(16)).substr(-2);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
function generateKeyObject(aKid, aKey) {
|
||||
let keyObj = {
|
||||
kty: "oct",
|
||||
kid: aKid,
|
||||
k: HexToBase64(aKey),
|
||||
};
|
||||
|
||||
return new TextEncoder().encode(
|
||||
JSON.stringify({
|
||||
keys: [keyObj],
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
function generateKeyInfo(aData) {
|
||||
let keyInfo = {
|
||||
initDataType: aData.initDataType,
|
||||
initData: new TextEncoder().encode(aData.initData),
|
||||
sessionType: aData.sessionType,
|
||||
keyObj: generateKeyObject(aData.kid, aData.key),
|
||||
};
|
||||
|
||||
return keyInfo;
|
||||
}
|
||||
|
||||
// Setup a EME key for the given browser, and return the sessionId.
|
||||
async function setupEMEKey(browser) {
|
||||
// Generate the key info.
|
||||
let keyInfo = generateKeyInfo(TEST_EME_KEY);
|
||||
|
||||
// Setup the EME key.
|
||||
let result = await ContentTask.spawn(browser, keyInfo, async function(
|
||||
aKeyInfo
|
||||
) {
|
||||
let access = await content.navigator.requestMediaKeySystemAccess(
|
||||
"org.w3.clearkey",
|
||||
[
|
||||
{
|
||||
initDataTypes: [aKeyInfo.initDataType],
|
||||
videoCapabilities: [{ contentType: "video/webm" }],
|
||||
sessionTypes: ["persistent-license"],
|
||||
persistentState: "required",
|
||||
},
|
||||
]
|
||||
);
|
||||
let mediaKeys = await access.createMediaKeys();
|
||||
let session = mediaKeys.createSession(aKeyInfo.sessionType);
|
||||
let res = {};
|
||||
|
||||
// Insert the EME key.
|
||||
await new Promise(resolve => {
|
||||
session.addEventListener("message", function(event) {
|
||||
session
|
||||
.update(aKeyInfo.keyObj)
|
||||
.then(() => {
|
||||
resolve();
|
||||
})
|
||||
.catch(() => {
|
||||
ok(false, "Update the EME key fail.");
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
session.generateRequest(aKeyInfo.initDataType, aKeyInfo.initData);
|
||||
});
|
||||
|
||||
let map = session.keyStatuses;
|
||||
|
||||
is(map.size, 1, "One EME key has been added.");
|
||||
|
||||
if (map.size === 1) {
|
||||
res.keyId = map.keys().next().value;
|
||||
res.sessionId = session.sessionId;
|
||||
}
|
||||
|
||||
// Close the session.
|
||||
session.close();
|
||||
await session.closed;
|
||||
|
||||
return res;
|
||||
});
|
||||
|
||||
// Check the EME key ID.
|
||||
is(
|
||||
ByteArrayToHex(result.keyId),
|
||||
Base64ToHex(TEST_EME_KEY.kid),
|
||||
"The key Id is correct."
|
||||
);
|
||||
return result.sessionId;
|
||||
}
|
||||
|
||||
// Check whether the EME key has been cleared.
|
||||
async function checkEMEKey(browser, emeSessionId) {
|
||||
// Generate the key info.
|
||||
let keyInfo = generateKeyInfo(TEST_EME_KEY);
|
||||
keyInfo.sessionId = emeSessionId;
|
||||
|
||||
await ContentTask.spawn(browser, keyInfo, async function(aKeyInfo) {
|
||||
let access = await content.navigator.requestMediaKeySystemAccess(
|
||||
"org.w3.clearkey",
|
||||
[
|
||||
{
|
||||
initDataTypes: [aKeyInfo.initDataType],
|
||||
videoCapabilities: [{ contentType: "video/webm" }],
|
||||
sessionTypes: ["persistent-license"],
|
||||
persistentState: "required",
|
||||
},
|
||||
]
|
||||
);
|
||||
let mediaKeys = await access.createMediaKeys();
|
||||
let session = mediaKeys.createSession(aKeyInfo.sessionType);
|
||||
|
||||
// First, load the session with the sessionId.
|
||||
await session.load(aKeyInfo.sessionId);
|
||||
|
||||
let map = session.keyStatuses;
|
||||
|
||||
// Check that there is no media key here.
|
||||
is(
|
||||
map.size,
|
||||
0,
|
||||
"No media key should be here after forgetThisSite() was called."
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
//
|
||||
// Test functions.
|
||||
//
|
||||
|
||||
add_task(async function setup() {
|
||||
// Make sure userContext is enabled.
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["privacy.userContext.enabled", true],
|
||||
["media.mediasource.enabled", true],
|
||||
["media.mediasource.webm.enabled", true],
|
||||
["media.clearkey.persistent-license.enabled", true],
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_EME_forgetThisSite() {
|
||||
let tabs = [];
|
||||
let emeSessionIds = [];
|
||||
|
||||
for (let userContextId of Object.keys(USER_CONTEXTS)) {
|
||||
// Open our tab in the given user context.
|
||||
tabs[userContextId] = await openTabInUserContext(
|
||||
TEST_URL + "empty_file.html",
|
||||
userContextId
|
||||
);
|
||||
|
||||
// Setup EME Key.
|
||||
emeSessionIds[userContextId] = await setupEMEKey(
|
||||
tabs[userContextId].browser
|
||||
);
|
||||
|
||||
// Close this tab.
|
||||
BrowserTestUtils.removeTab(tabs[userContextId].tab);
|
||||
}
|
||||
|
||||
// Clear all EME data for a given domain with originAttributes pattern.
|
||||
let mps = Cc["@mozilla.org/gecko-media-plugin-service;1"].getService(
|
||||
Ci.mozIGeckoMediaPluginChromeService
|
||||
);
|
||||
mps.forgetThisSite(TEST_HOST, JSON.stringify({}));
|
||||
|
||||
// Open tabs again to check EME keys have been cleared.
|
||||
for (let userContextId of Object.keys(USER_CONTEXTS)) {
|
||||
// Open our tab in the given user context.
|
||||
tabs[userContextId] = await openTabInUserContext(
|
||||
TEST_URL + "empty_file.html",
|
||||
userContextId
|
||||
);
|
||||
|
||||
// Check whether EME Key has been cleared.
|
||||
await checkEMEKey(
|
||||
tabs[userContextId].browser,
|
||||
emeSessionIds[userContextId]
|
||||
);
|
||||
|
||||
// Close this tab.
|
||||
BrowserTestUtils.removeTab(tabs[userContextId].tab);
|
||||
}
|
||||
});
|
@ -761,18 +761,6 @@ var Policies = {
|
||||
},
|
||||
},
|
||||
|
||||
EncryptedMediaExtensions: {
|
||||
onBeforeAddons(manager, param) {
|
||||
let locked = false;
|
||||
if ("Locked" in param) {
|
||||
locked = param.Locked;
|
||||
}
|
||||
if ("Enabled" in param) {
|
||||
setDefaultPref("media.eme.enabled", param.Enabled, locked);
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
Extensions: {
|
||||
onBeforeUIStartup(manager, param) {
|
||||
let uninstallingPromise = Promise.resolve();
|
||||
|
@ -860,15 +860,9 @@
|
||||
"intl.accept_languages": {
|
||||
"type": "string"
|
||||
},
|
||||
"media.eme.enabled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"media.gmp-gmpopenh264.enabled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"media.gmp-widevinecdm.enabled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"media.peerconnection.enabled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
|
@ -1046,7 +1046,7 @@ class Window extends WindowBase {
|
||||
// A new window is being opened and it is adopting an existing tab, we return
|
||||
// an empty iterator here because there should be no other tabs to return during
|
||||
// that duration (See Bug 1458918 for a rationale).
|
||||
if (this.window.gBrowserInit.isAdoptingTab()) {
|
||||
if (this.window.gBrowserInit && this.window.gBrowserInit.isAdoptingTab()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1065,6 +1065,10 @@ class Window extends WindowBase {
|
||||
}
|
||||
|
||||
get activeTab() {
|
||||
if (!this.window.gBrowser || !this.window.gBrowserInit) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let { tabManager } = this.extension;
|
||||
|
||||
// A new window is being opened and it is adopting a tab, and we do not create
|
||||
|
@ -178,9 +178,6 @@ Preferences.addAll([
|
||||
// Files and Applications
|
||||
{ id: "pref.downloads.disable_button.edit_actions", type: "bool" },
|
||||
|
||||
// DRM content
|
||||
{ id: "media.eme.enabled", type: "bool" },
|
||||
|
||||
// Update
|
||||
{ id: "browser.preferences.advanced.selectedTabIndex", type: "int" },
|
||||
|
||||
@ -477,25 +474,6 @@ var gMainPane = {
|
||||
}
|
||||
}
|
||||
|
||||
let drmInfoURL =
|
||||
Services.urlFormatter.formatURLPref("app.support.baseURL") +
|
||||
"drm-content";
|
||||
document
|
||||
.getElementById("playDRMContentLink")
|
||||
.setAttribute("href", drmInfoURL);
|
||||
let emeUIEnabled = Services.prefs.getBoolPref("browser.eme.ui.enabled");
|
||||
// Force-disable/hide on WinXP:
|
||||
if (navigator.platform.toLowerCase().startsWith("win")) {
|
||||
emeUIEnabled =
|
||||
emeUIEnabled && parseFloat(Services.sysinfo.get("version")) >= 6;
|
||||
}
|
||||
if (!emeUIEnabled) {
|
||||
// Don't want to rely on .hidden for the toplevel groupbox because
|
||||
// of the pane hiding/showing code potentially interfering:
|
||||
document
|
||||
.getElementById("drmGroup")
|
||||
.setAttribute("style", "display: none !important");
|
||||
}
|
||||
// Initialize the Firefox Updates section.
|
||||
let version = AppConstants.MOZ_APP_VERSION_DISPLAY;
|
||||
|
||||
|
@ -391,17 +391,6 @@
|
||||
preference="pref.downloads.disable_button.edit_actions"/>
|
||||
</groupbox>
|
||||
|
||||
|
||||
<!-- DRM Content -->
|
||||
<groupbox id="drmGroup" data-category="paneGeneral" data-subcategory="drm" hidden="true">
|
||||
<label><html:h2 data-l10n-id="drm-content-header"/></label>
|
||||
<hbox align="center">
|
||||
<checkbox id="playDRMContent" preference="media.eme.enabled"
|
||||
class="tail-with-learn-more" data-l10n-id="play-drm-content" />
|
||||
<label id="playDRMContentLink" class="learnMore" data-l10n-id="play-drm-content-learn-more" is="text-link"/>
|
||||
</hbox>
|
||||
</groupbox>
|
||||
|
||||
#ifdef HAVE_SHELL_SERVICE
|
||||
<stringbundle id="bundleShell" src="chrome://browser/locale/shellservice.properties"/>
|
||||
<stringbundle id="bundleBrand" src="chrome://branding/locale/brand.properties"/>
|
||||
|
@ -1 +1 @@
|
||||
68.14.3
|
||||
68.14.4
|
||||
|
@ -1 +1 @@
|
||||
68.14.3b
|
||||
68.14.4b
|
||||
|
@ -234,7 +234,6 @@ These should match what Safari and other Apple applications use on OS X Lion. --
|
||||
<!ENTITY urlbar.servicesNotificationAnchor.tooltip "Open install message panel">
|
||||
<!ENTITY urlbar.translateNotificationAnchor.tooltip "Translate this page">
|
||||
<!ENTITY urlbar.translatedNotificationAnchor.tooltip "Manage page translation">
|
||||
<!ENTITY urlbar.emeNotificationAnchor.tooltip "Manage use of DRM software">
|
||||
<!ENTITY urlbar.midiNotificationAnchor.tooltip "Open MIDI panel">
|
||||
|
||||
<!ENTITY urlbar.cameraBlocked.tooltip "You have blocked your camera for this website.">
|
||||
|
@ -898,11 +898,6 @@ slowStartup.helpButton.accesskey = L
|
||||
slowStartup.disableNotificationButton.label = Don’t Tell Me Again
|
||||
slowStartup.disableNotificationButton.accesskey = A
|
||||
|
||||
# LOCALIZATION NOTE - %S is brandShortName
|
||||
flashHang.message = %S changed some Adobe Flash settings to improve performance.
|
||||
flashHang.helpButton.label = Learn More…
|
||||
flashHang.helpButton.accesskey = L
|
||||
|
||||
# LOCALIZATION NOTE (customizeMode.tabTitle): %S is brandShortName
|
||||
customizeMode.tabTitle = Customize %S
|
||||
|
||||
|
@ -14,7 +14,7 @@ tabs.closeAndQuitTitleTabsWin=Exit and close tabs?
|
||||
# http://developer.mozilla.org/en/docs/Localization_and_Plurals
|
||||
# The singular form is not considered since this string is used only for
|
||||
# multiple tabs.
|
||||
tabs.closeWarningMultiple=;You are about to close #1 tabs. Are you sure you want to continue?
|
||||
tabs.closeWarningMultiple=You are about to close #1 tab. Are you sure you want to continue?;You are about to close #1 tabs. Are you sure you want to continue?
|
||||
# LOCALIZATION NOTE (tabs.closeWarningMultipleSessionRestore2):
|
||||
# Semicolon-separated list of plural forms. See:
|
||||
# http://developer.mozilla.org/en/docs/Localization_and_Plurals
|
||||
|
@ -1024,7 +1024,6 @@ async function sanitizeSessionPrincipal(progress, principal) {
|
||||
Ci.nsIClearDataService.CLEAR_COOKIES |
|
||||
Ci.nsIClearDataService.CLEAR_DOM_STORAGES |
|
||||
Ci.nsIClearDataService.CLEAR_SECURITY_SETTINGS |
|
||||
Ci.nsIClearDataService.CLEAR_EME |
|
||||
Ci.nsIClearDataService.CLEAR_PLUGIN_DATA,
|
||||
resolve
|
||||
);
|
||||
|
@ -376,7 +376,6 @@ var SiteDataManager = {
|
||||
Ci.nsIClearDataService.CLEAR_DOM_STORAGES |
|
||||
Ci.nsIClearDataService.CLEAR_SECURITY_SETTINGS |
|
||||
Ci.nsIClearDataService.CLEAR_PLUGIN_DATA |
|
||||
Ci.nsIClearDataService.CLEAR_EME |
|
||||
Ci.nsIClearDataService.CLEAR_ALL_CACHES;
|
||||
promises.push(
|
||||
new Promise(function(resolve) {
|
||||
@ -493,7 +492,6 @@ var SiteDataManager = {
|
||||
Ci.nsIClearDataService.CLEAR_COOKIES |
|
||||
Ci.nsIClearDataService.CLEAR_DOM_STORAGES |
|
||||
Ci.nsIClearDataService.CLEAR_SECURITY_SETTINGS |
|
||||
Ci.nsIClearDataService.CLEAR_EME |
|
||||
Ci.nsIClearDataService.CLEAR_PLUGIN_DATA,
|
||||
resolve
|
||||
);
|
||||
|
@ -45,9 +45,3 @@
|
||||
#context-reload:-moz-locale-dir(rtl) {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
#context-media-eme-learnmore {
|
||||
list-style-image: url("chrome://browser/skin/drm-icon.svg");
|
||||
-moz-context-properties: fill;
|
||||
fill: currentColor;
|
||||
}
|
||||
|
@ -1,8 +0,0 @@
|
||||
<!-- 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/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="context-fill" fill-opacity="context-fill-opacity">
|
||||
<path d="M7.058,9.72c-0.245,0.245-0.62,0.27-0.834,0.056C6.01,9.562,6.035,9.186,6.28,8.942l0.218-0.218 c-0.245-0.245-0.645-0.245-0.89,0L4.496,9.836c-0.245,0.245-0.245,0.645,0,0.89l0.779,0.779c0.245,0.245,0.645,0.245,0.89,0 l1.112-1.112c0.245-0.245,0.245-0.645,0-0.89L7.058,9.72z"/>
|
||||
<path d="M10.726,4.496c-0.245-0.245-0.645-0.245-0.89,0L8.723,5.608c-0.245,0.245-0.245,0.645,0,0.89 L8.95,6.272c0.245-0.245,0.62-0.27,0.834-0.056s0.189,0.59-0.056,0.834L9.502,7.277c0.245,0.245,0.645,0.245,0.89,0l1.112-1.112 c0.245-0.245,0.245-0.645,0-0.89L10.726,4.496z"/>
|
||||
<path d="M8,0C3.582,0,0,3.582,0,8s3.582,8,8,8s8-3.582,8-8S12.418,0,8,0z M12.527,6.81l-1.489,1.489 c-0.631,0.631-1.663,0.631-2.293,0L8.612,8.167L8.167,8.612l0.133,0.133c0.631,0.631,0.631,1.663,0,2.293L6.81,12.527 c-0.631,0.631-1.663,0.631-2.293,0l-1.044-1.044c-0.631-0.631-0.631-1.663,0-2.293l1.489-1.489c0.631-0.631,1.663-0.631,2.293,0 l0.133,0.133l0.445-0.445L7.701,7.255c-0.631-0.631-0.631-1.663,0-2.293L9.19,3.473c0.631-0.631,1.663-0.631,2.293,0l1.044,1.044 C13.158,5.148,13.158,6.18,12.527,6.81z"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.4 KiB |
@ -51,7 +51,6 @@
|
||||
skin/classic/browser/downloads/download-summary.svg (../shared/downloads/download-summary.svg)
|
||||
skin/classic/browser/downloads/download-icons.svg (../shared/downloads/download-icons.svg)
|
||||
skin/classic/browser/downloads/notification-start-animation.svg (../shared/downloads/notification-start-animation.svg)
|
||||
skin/classic/browser/drm-icon.svg (../shared/drm-icon.svg)
|
||||
skin/classic/browser/fullscreen/insecure.svg (../shared/fullscreen/insecure.svg)
|
||||
skin/classic/browser/fullscreen/secure.svg (../shared/fullscreen/secure.svg)
|
||||
skin/classic/browser/connection-secure.svg (../shared/identity-block/connection-secure.svg)
|
||||
|
@ -232,25 +232,6 @@ html|*#webRTC-previewVideo {
|
||||
min-width: 6.5em;
|
||||
}
|
||||
|
||||
/* EME */
|
||||
|
||||
.popup-notification-icon[popupid="drmContentPlaying"],
|
||||
.drm-icon {
|
||||
list-style-image: url("chrome://browser/skin/drm-icon.svg");
|
||||
}
|
||||
|
||||
.notification-anchor-icon[animate=true],
|
||||
#eme-notification-icon[firstplay=true] {
|
||||
animation: emeTeachingMoment 0.2s linear 0s 5 normal;
|
||||
}
|
||||
|
||||
@keyframes emeTeachingMoment {
|
||||
0% {transform: translateX(0); }
|
||||
25% {transform: translateX(3px) }
|
||||
75% {transform: translateX(-3px) }
|
||||
100% { transform: translateX(0); }
|
||||
}
|
||||
|
||||
/* INSTALL ADDONS */
|
||||
|
||||
.install-icon {
|
||||
|
@ -23356,7 +23356,6 @@ ARGBSetRow_X86
|
||||
?GetBrowserDOMWindow@nsGlobalWindowInner@@UAG?AW4nsresult@@PAPAVnsIBrowserDOMWindow@@@Z
|
||||
?GetBrowserDOMWindow@nsGlobalWindowInner@@QAEPAVnsIBrowserDOMWindow@@AAVErrorResult@mozilla@@@Z
|
||||
?GetBrowserDOMWindowOuter@nsGlobalWindowOuter@@QAEPAVnsIBrowserDOMWindow@@XZ
|
||||
?IsCrossProcessWrapper@nsXPCComponents_Utils@@UAG?AW4nsresult@@V?$Handle@TValue@JS@@@JS@@PA_N@Z
|
||||
?Self@nsGlobalWindowInner@@QAEPAVBrowsingContext@dom@mozilla@@XZ
|
||||
?Location@nsGlobalWindowInner@@UAEPAV0dom@mozilla@@XZ
|
||||
??0Location@dom@mozilla@@QAE@PAVnsPIDOMWindowInner@@PAVnsIDocShell@@@Z
|
||||
|
@ -23915,7 +23915,6 @@ workerlz4_decompress
|
||||
?GetBrowserDOMWindow@nsGlobalWindowInner@@UEAA?AW4nsresult@@PEAPEAVnsIBrowserDOMWindow@@@Z
|
||||
?GetBrowserDOMWindow@nsGlobalWindowInner@@QEAAPEAVnsIBrowserDOMWindow@@AEAVErrorResult@mozilla@@@Z
|
||||
?GetBrowserDOMWindowOuter@nsGlobalWindowOuter@@QEAAPEAVnsIBrowserDOMWindow@@XZ
|
||||
?IsCrossProcessWrapper@nsXPCComponents_Utils@@UEAA?AW4nsresult@@V?$Handle@TValue@JS@@@JS@@PEA_N@Z
|
||||
?QueryInterface@ReferrerInfo@dom@mozilla@@UEAA?AW4nsresult@@AEBUnsID@@PEAPEAX@Z
|
||||
?Release@ReferrerInfo@dom@mozilla@@UEAAKXZ
|
||||
?ReferrerInfo_GetInterfacesHelper@dom@mozilla@@YA?AW4nsresult@@AEAV?$nsTArray@UnsID@@@@@Z
|
||||
|
1
config/external/moz.build
vendored
1
config/external/moz.build
vendored
@ -55,7 +55,6 @@ external_dirs += [
|
||||
'media/libspeex_resampler',
|
||||
'media/libsoundtouch',
|
||||
'media/mp4parse-rust',
|
||||
'media/psshparser'
|
||||
]
|
||||
|
||||
DIRS += ['../../' + i for i in external_dirs]
|
||||
|
@ -10,4 +10,4 @@
|
||||
# hardcoded milestones in the tree from these two files.
|
||||
#--------------------------------------------------------
|
||||
|
||||
68.14.3
|
||||
68.14.4
|
||||
|
@ -128,7 +128,6 @@ support-files =
|
||||
test-message-categories-workers.html
|
||||
test-message-categories-workers.js
|
||||
test-mixedcontent-securityerrors.html
|
||||
test-navigate-to-parse-error.html
|
||||
test-network-exceptions.html
|
||||
test-network-request.html
|
||||
test-network.html
|
||||
@ -375,7 +374,6 @@ skip-if = true # Bug XXX # Bug 1404382
|
||||
[browser_webconsole_longstring.js]
|
||||
[browser_webconsole_message_categories.js]
|
||||
[browser_webconsole_multiple_windows_and_tabs.js]
|
||||
[browser_webconsole_navigate_to_parse_error.js]
|
||||
[browser_webconsole_network_attach.js]
|
||||
[browser_webconsole_network_exceptions.js]
|
||||
[browser_webconsole_network_message_close_on_escape.js]
|
||||
|
@ -1,27 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Tests that ensure CSP 'navigate-to' does not parse.
|
||||
// Bug 1566149
|
||||
|
||||
"use strict";
|
||||
|
||||
const TEST_URI =
|
||||
"data:text/html;charset=utf8,Web Console navigate-to parse error test";
|
||||
const TEST_VIOLATION =
|
||||
"https://example.com/browser/devtools/client/webconsole/" +
|
||||
"test/browser/test-navigate-to-parse-error.html";
|
||||
|
||||
const CSP_VIOLATION_MSG =
|
||||
"Content Security Policy: Couldn\u2019t process unknown directive \u2018navigate-to\u2019";
|
||||
|
||||
add_task(async function() {
|
||||
const hud = await openNewTabAndConsole(TEST_URI);
|
||||
hud.ui.clearOutput();
|
||||
|
||||
const onRepeatedMessage = waitForRepeatedMessage(hud, CSP_VIOLATION_MSG, 2);
|
||||
await loadDocument(TEST_VIOLATION);
|
||||
await onRepeatedMessage;
|
||||
|
||||
ok(true, "Received expected messages");
|
||||
});
|
@ -1,13 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Security-Policy" content="navigate-to https://example.com"></meta>
|
||||
<meta charset="UTF-8">
|
||||
<title>Test for Bug 1566149 - Write test to ensure CSP 'navigate-to' does not parse</title>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1566149">Mozilla Bug 1566149</a>
|
||||
</body>
|
||||
</html>
|
@ -1323,7 +1323,6 @@ Document::Document(const char* aContentType)
|
||||
mViewportType(Unknown),
|
||||
mSubDocuments(nullptr),
|
||||
mHeaderData(nullptr),
|
||||
mFlashClassification(FlashClassification::Unknown),
|
||||
mScrollAnchorAdjustmentLength(0),
|
||||
mScrollAnchorAdjustmentCount(0),
|
||||
mBoxObjectTable(nullptr),
|
||||
@ -3301,11 +3300,6 @@ bool Document::GetAllowPlugins() {
|
||||
}
|
||||
}
|
||||
|
||||
FlashClassification classification = DocumentFlashClassification();
|
||||
if (classification == FlashClassification::Denied) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -14668,48 +14662,6 @@ void Document::TraceProtos(JSTracer* aTrc) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the classification of the Flash plugins in the document based on
|
||||
* the classification lists. For more information, see
|
||||
* toolkit/components/url-classifier/flash-block-lists.rst
|
||||
*/
|
||||
FlashClassification Document::DocumentFlashClassification() {
|
||||
// If neither pref is on, skip the null-principal and principal URI checks.
|
||||
if (!StaticPrefs::plugins_http_https_only() &&
|
||||
!StaticPrefs::plugins_flashBlock_enabled()) {
|
||||
return FlashClassification::Unknown;
|
||||
}
|
||||
|
||||
if (!NodePrincipal()->GetIsCodebasePrincipal()) {
|
||||
return FlashClassification::Denied;
|
||||
}
|
||||
|
||||
if (StaticPrefs::plugins_http_https_only()) {
|
||||
// Only allow plugins for documents from an HTTP/HTTPS origin. This should
|
||||
// allow dependent data: URIs to load plugins, but not:
|
||||
// * chrome documents
|
||||
// * "bare" data: loads
|
||||
// * FTP/gopher/file
|
||||
|
||||
if (!(NodePrincipal()->SchemeIs("http") ||
|
||||
NodePrincipal()->SchemeIs("https"))) {
|
||||
return FlashClassification::Denied;
|
||||
}
|
||||
}
|
||||
|
||||
// If flash blocking is disabled, it is equivalent to all sites being
|
||||
// on neither list.
|
||||
if (!StaticPrefs::plugins_flashBlock_enabled()) {
|
||||
return FlashClassification::Unknown;
|
||||
}
|
||||
|
||||
if (mFlashClassification == FlashClassification::Unknown) {
|
||||
mFlashClassification = DocumentFlashClassificationInternal();
|
||||
}
|
||||
|
||||
return mFlashClassification;
|
||||
}
|
||||
|
||||
void Document::AddResizeObserver(ResizeObserver& aObserver) {
|
||||
if (!mResizeObserverController) {
|
||||
mResizeObserverController = MakeUnique<ResizeObserverController>(this);
|
||||
@ -14746,130 +14698,6 @@ void Document::ScheduleResizeObserversNotification() const {
|
||||
mResizeObserverController->ScheduleNotification();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes |mIsThirdPartyForFlashClassifier| if necessary and returns its
|
||||
* value. The value returned represents whether this document should be
|
||||
* considered Third-Party.
|
||||
*
|
||||
* A top-level document cannot be a considered Third-Party; only subdocuments
|
||||
* may. For a subdocument to be considered Third-Party, it must meet ANY ONE
|
||||
* of the following requirements:
|
||||
* - The document's parent is Third-Party
|
||||
* - The document has a different scheme (http/https) than its parent document
|
||||
* - The document's domain and subdomain do not match those of its parent
|
||||
* document.
|
||||
*
|
||||
* If there is an error in determining whether the document is Third-Party,
|
||||
* it will be assumed to be Third-Party for security reasons.
|
||||
*/
|
||||
bool Document::IsThirdPartyForFlashClassifier() {
|
||||
if (mIsThirdPartyForFlashClassifier.isSome()) {
|
||||
return mIsThirdPartyForFlashClassifier.value();
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocShellTreeItem> docshell = this->GetDocShell();
|
||||
if (!docshell) {
|
||||
mIsThirdPartyForFlashClassifier.emplace(true);
|
||||
return mIsThirdPartyForFlashClassifier.value();
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocShellTreeItem> parent;
|
||||
nsresult rv = docshell->GetInProcessSameTypeParent(getter_AddRefs(parent));
|
||||
MOZ_ASSERT(
|
||||
NS_SUCCEEDED(rv),
|
||||
"nsIDocShellTreeItem::GetInProcessSameTypeParent should never fail");
|
||||
bool isTopLevel = !parent;
|
||||
|
||||
if (isTopLevel) {
|
||||
mIsThirdPartyForFlashClassifier.emplace(false);
|
||||
return mIsThirdPartyForFlashClassifier.value();
|
||||
}
|
||||
|
||||
nsCOMPtr<Document> parentDocument = GetInProcessParentDocument();
|
||||
if (!parentDocument) {
|
||||
// Failure
|
||||
mIsThirdPartyForFlashClassifier.emplace(true);
|
||||
return mIsThirdPartyForFlashClassifier.value();
|
||||
}
|
||||
|
||||
if (parentDocument->IsThirdPartyForFlashClassifier()) {
|
||||
mIsThirdPartyForFlashClassifier.emplace(true);
|
||||
return mIsThirdPartyForFlashClassifier.value();
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal = NodePrincipal();
|
||||
nsCOMPtr<nsIPrincipal> parentPrincipal = parentDocument->GetPrincipal();
|
||||
|
||||
bool principalsMatch = false;
|
||||
rv = principal->Equals(parentPrincipal, &principalsMatch);
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
// Failure
|
||||
mIsThirdPartyForFlashClassifier.emplace(true);
|
||||
return mIsThirdPartyForFlashClassifier.value();
|
||||
}
|
||||
|
||||
if (!principalsMatch) {
|
||||
mIsThirdPartyForFlashClassifier.emplace(true);
|
||||
return mIsThirdPartyForFlashClassifier.value();
|
||||
}
|
||||
|
||||
// Fall-through. Document is not a Third-Party Document.
|
||||
mIsThirdPartyForFlashClassifier.emplace(false);
|
||||
return mIsThirdPartyForFlashClassifier.value();
|
||||
}
|
||||
|
||||
FlashClassification Document::DocumentFlashClassificationInternal() {
|
||||
FlashClassification classification = FlashClassification::Unknown;
|
||||
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(GetChannel());
|
||||
if (httpChannel) {
|
||||
nsIHttpChannel::FlashPluginState state = nsIHttpChannel::FlashPluginUnknown;
|
||||
httpChannel->GetFlashPluginState(&state);
|
||||
|
||||
// Allow unknown children to inherit allowed status from parent, but do not
|
||||
// allow denied children to do so.
|
||||
|
||||
if (state == nsIHttpChannel::FlashPluginDeniedInSubdocuments &&
|
||||
IsThirdPartyForFlashClassifier()) {
|
||||
return FlashClassification::Denied;
|
||||
}
|
||||
|
||||
if (state == nsIHttpChannel::FlashPluginDenied) {
|
||||
return FlashClassification::Denied;
|
||||
}
|
||||
|
||||
if (state == nsIHttpChannel::FlashPluginAllowed) {
|
||||
classification = FlashClassification::Allowed;
|
||||
}
|
||||
}
|
||||
|
||||
if (IsTopLevelContentDocument()) {
|
||||
return classification;
|
||||
}
|
||||
|
||||
Document* parentDocument = GetInProcessParentDocument();
|
||||
if (!parentDocument) {
|
||||
return FlashClassification::Denied;
|
||||
}
|
||||
|
||||
FlashClassification parentClassification =
|
||||
parentDocument->DocumentFlashClassification();
|
||||
|
||||
if (parentClassification == FlashClassification::Denied) {
|
||||
return FlashClassification::Denied;
|
||||
}
|
||||
|
||||
// Allow unknown children to inherit allowed status from parent, but
|
||||
// do not allow denied children to do so.
|
||||
if (classification == FlashClassification::Unknown &&
|
||||
parentClassification == FlashClassification::Allowed) {
|
||||
return FlashClassification::Allowed;
|
||||
}
|
||||
|
||||
return classification;
|
||||
}
|
||||
|
||||
void Document::ClearStaleServoData() {
|
||||
DocumentStyleRootIterator iter(this);
|
||||
while (Element* root = iter.GetNextStyleRoot()) {
|
||||
|
@ -3861,10 +3861,6 @@ class Document : public nsINode,
|
||||
// determine if it belongs to a tracker.
|
||||
bool IsScriptTracking(JSContext* aCx) const;
|
||||
|
||||
// For more information on Flash classification, see
|
||||
// toolkit/components/url-classifier/flash-block-lists.rst
|
||||
FlashClassification DocumentFlashClassification();
|
||||
|
||||
// ResizeObserver usage.
|
||||
void AddResizeObserver(ResizeObserver&);
|
||||
void RemoveResizeObserver(ResizeObserver&);
|
||||
@ -3969,18 +3965,12 @@ class Document : public nsINode,
|
||||
// Returns a ViewportMetaData for this document.
|
||||
ViewportMetaData GetViewportMetaData() const;
|
||||
|
||||
FlashClassification DocumentFlashClassificationInternal();
|
||||
|
||||
nsTArray<nsString> mL10nResources;
|
||||
|
||||
// The application cache that this document is associated with, if
|
||||
// any. This can change during the lifetime of the document.
|
||||
nsCOMPtr<nsIApplicationCache> mApplicationCache;
|
||||
|
||||
public:
|
||||
bool IsThirdPartyForFlashClassifier();
|
||||
|
||||
private:
|
||||
void DoCacheAllKnownLangPrefs();
|
||||
void RecomputeLanguageFromCharset();
|
||||
|
||||
@ -5011,14 +5001,6 @@ class Document : public nsINode,
|
||||
|
||||
DocHeaderData* mHeaderData;
|
||||
|
||||
// For determining if this is a flash document which should be
|
||||
// blocked based on its principal.
|
||||
FlashClassification mFlashClassification;
|
||||
|
||||
// Do not use this value directly. Call the |IsThirdPartyForFlashClassifier()|
|
||||
// method, which caches its result here.
|
||||
Maybe<bool> mIsThirdPartyForFlashClassifier;
|
||||
|
||||
nsRevocableEventPtr<nsRunnableMethod<Document, void, false>>
|
||||
mPendingTitleChangeEvent;
|
||||
|
||||
|
@ -979,6 +979,99 @@ bool nsAttrValue::Equals(const nsAtom* aValue,
|
||||
return aValue->Equals(val);
|
||||
}
|
||||
|
||||
struct HasPrefixFn {
|
||||
static bool Check(const char16_t* aAttrValue, size_t aAttrLen,
|
||||
const nsAString& aSearchValue,
|
||||
nsCaseTreatment aCaseSensitive) {
|
||||
if (aCaseSensitive == eCaseMatters) {
|
||||
if (aSearchValue.Length() > aAttrLen) {
|
||||
return false;
|
||||
}
|
||||
return !memcmp(aAttrValue, aSearchValue.BeginReading(),
|
||||
aSearchValue.Length() * sizeof(char16_t));
|
||||
}
|
||||
return StringBeginsWith(nsDependentString(aAttrValue, aAttrLen),
|
||||
aSearchValue,
|
||||
nsASCIICaseInsensitiveStringComparator());
|
||||
}
|
||||
};
|
||||
|
||||
struct HasSuffixFn {
|
||||
static bool Check(const char16_t* aAttrValue, size_t aAttrLen,
|
||||
const nsAString& aSearchValue,
|
||||
nsCaseTreatment aCaseSensitive) {
|
||||
if (aCaseSensitive == eCaseMatters) {
|
||||
if (aSearchValue.Length() > aAttrLen) {
|
||||
return false;
|
||||
}
|
||||
return !memcmp(aAttrValue + aAttrLen - aSearchValue.Length(),
|
||||
aSearchValue.BeginReading(),
|
||||
aSearchValue.Length() * sizeof(char16_t));
|
||||
}
|
||||
return StringEndsWith(nsDependentString(aAttrValue, aAttrLen), aSearchValue,
|
||||
nsASCIICaseInsensitiveStringComparator());
|
||||
}
|
||||
};
|
||||
|
||||
struct HasSubstringFn {
|
||||
static bool Check(const char16_t* aAttrValue, size_t aAttrLen,
|
||||
const nsAString& aSearchValue,
|
||||
nsCaseTreatment aCaseSensitive) {
|
||||
if (aCaseSensitive == eCaseMatters) {
|
||||
if (aSearchValue.IsEmpty()) {
|
||||
return true;
|
||||
}
|
||||
const char16_t* end = aAttrValue + aAttrLen;
|
||||
return std::search(aAttrValue, end, aSearchValue.BeginReading(),
|
||||
aSearchValue.EndReading()) != end;
|
||||
}
|
||||
return FindInReadable(aSearchValue, nsDependentString(aAttrValue, aAttrLen),
|
||||
nsASCIICaseInsensitiveStringComparator());
|
||||
}
|
||||
};
|
||||
|
||||
template <typename F>
|
||||
bool nsAttrValue::SubstringCheck(const nsAString& aValue,
|
||||
nsCaseTreatment aCaseSensitive) const {
|
||||
switch (BaseType()) {
|
||||
case eStringBase: {
|
||||
auto str = static_cast<nsStringBuffer*>(GetPtr());
|
||||
if (str) {
|
||||
return F::Check(static_cast<char16_t*>(str->Data()),
|
||||
str->StorageSize() / sizeof(char16_t) - 1, aValue,
|
||||
aCaseSensitive);
|
||||
}
|
||||
return aValue.IsEmpty();
|
||||
}
|
||||
case eAtomBase: {
|
||||
auto atom = static_cast<nsAtom*>(GetPtr());
|
||||
return F::Check(atom->GetUTF16String(), atom->GetLength(), aValue,
|
||||
aCaseSensitive);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
nsAutoString val;
|
||||
ToString(val);
|
||||
return F::Check(val.BeginReading(), val.Length(), aValue, aCaseSensitive);
|
||||
}
|
||||
|
||||
bool nsAttrValue::HasPrefix(const nsAString& aValue,
|
||||
nsCaseTreatment aCaseSensitive) const {
|
||||
return SubstringCheck<HasPrefixFn>(aValue, aCaseSensitive);
|
||||
}
|
||||
|
||||
bool nsAttrValue::HasSuffix(const nsAString& aValue,
|
||||
nsCaseTreatment aCaseSensitive) const {
|
||||
return SubstringCheck<HasSuffixFn>(aValue, aCaseSensitive);
|
||||
}
|
||||
|
||||
bool nsAttrValue::HasSubstring(const nsAString& aValue,
|
||||
nsCaseTreatment aCaseSensitive) const {
|
||||
return SubstringCheck<HasSubstringFn>(aValue, aCaseSensitive);
|
||||
}
|
||||
|
||||
bool nsAttrValue::EqualsAsStrings(const nsAttrValue& aOther) const {
|
||||
if (Type() == aOther.Type()) {
|
||||
return Equals(aOther);
|
||||
|
@ -234,6 +234,10 @@ class nsAttrValue {
|
||||
// aCaseSensitive == eIgnoreCase means ASCII case-insenstive matching
|
||||
bool Equals(const nsAString& aValue, nsCaseTreatment aCaseSensitive) const;
|
||||
bool Equals(const nsAtom* aValue, nsCaseTreatment aCaseSensitive) const;
|
||||
bool HasPrefix(const nsAString& aValue, nsCaseTreatment aCaseSensitive) const;
|
||||
bool HasSuffix(const nsAString& aValue, nsCaseTreatment aCaseSensitive) const;
|
||||
bool HasSubstring(const nsAString& aValue,
|
||||
nsCaseTreatment aCaseSensitive) const;
|
||||
|
||||
/**
|
||||
* Compares this object with aOther according to their string representation.
|
||||
@ -506,6 +510,10 @@ class nsAttrValue {
|
||||
int32_t EnumTableEntryToValue(const EnumTable* aEnumTable,
|
||||
const EnumTable* aTableEntry);
|
||||
|
||||
template <typename F>
|
||||
bool SubstringCheck(const nsAString& aValue,
|
||||
nsCaseTreatment aCaseSensitive) const;
|
||||
|
||||
static MiscContainer* AllocMiscContainer();
|
||||
static void DeallocMiscContainer(MiscContainer* aCont);
|
||||
|
||||
|
@ -3031,16 +3031,6 @@ bool nsObjectLoadingContent::ShouldPlay(FallbackType& aReason) {
|
||||
nsCOMPtr<Document> topDoc = topWindow->GetDoc();
|
||||
NS_ENSURE_TRUE(topDoc, false);
|
||||
|
||||
// Check the flash blocking status for this page (this applies to Flash only)
|
||||
FlashClassification documentClassification = FlashClassification::Unknown;
|
||||
if (IsFlashMIME(mContentType)) {
|
||||
documentClassification = ownerDoc->DocumentFlashClassification();
|
||||
}
|
||||
if (documentClassification == FlashClassification::Denied) {
|
||||
aReason = eFallbackSuppressed;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check the permission manager for permission based on the principal of
|
||||
// the toplevel content.
|
||||
nsCOMPtr<nsIPermissionManager> permissionManager =
|
||||
@ -3108,16 +3098,10 @@ bool nsObjectLoadingContent::ShouldPlay(FallbackType& aReason) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// On the following switch we don't need to handle the case where
|
||||
// documentClassification is FlashClassification::Denied because
|
||||
// that's already handled above.
|
||||
switch (enabledState) {
|
||||
case nsIPluginTag::STATE_ENABLED:
|
||||
return true;
|
||||
case nsIPluginTag::STATE_CLICKTOPLAY:
|
||||
if (documentClassification == FlashClassification::Allowed) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
MOZ_CRASH("Unexpected enabledState");
|
||||
|
@ -3295,30 +3295,6 @@ nsresult EventStateManager::PostHandleEvent(nsPresContext* aPresContext,
|
||||
// if we're here, the event handler returned false, so stop
|
||||
// any of our own processing of a drag. Workaround for bug 43258.
|
||||
StopTrackingDragGesture(true);
|
||||
|
||||
// When the event was cancelled, there is currently a chrome document
|
||||
// focused and a mousedown just occurred on a content document, ensure
|
||||
// that the window that was clicked is focused.
|
||||
EnsureDocument(mPresContext);
|
||||
nsIFocusManager* fm = nsFocusManager::GetFocusManager();
|
||||
if (mDocument && fm) {
|
||||
nsCOMPtr<mozIDOMWindowProxy> window;
|
||||
fm->GetFocusedWindow(getter_AddRefs(window));
|
||||
auto* currentWindow = nsPIDOMWindowOuter::From(window);
|
||||
if (currentWindow && mDocument->GetWindow() &&
|
||||
currentWindow != mDocument->GetWindow() &&
|
||||
!nsContentUtils::IsChromeDoc(mDocument)) {
|
||||
nsCOMPtr<nsPIDOMWindowOuter> currentTop;
|
||||
nsCOMPtr<nsPIDOMWindowOuter> newTop;
|
||||
currentTop = currentWindow->GetInProcessTop();
|
||||
newTop = mDocument->GetWindow()->GetInProcessTop();
|
||||
nsCOMPtr<Document> currentDoc = currentWindow->GetExtantDoc();
|
||||
if (nsContentUtils::IsChromeDoc(currentDoc) ||
|
||||
(currentTop && newTop && currentTop != newTop)) {
|
||||
fm->SetFocusedWindow(mDocument->GetWindow());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
SetActiveManager(this, activeContent);
|
||||
} break;
|
||||
|
@ -5335,15 +5335,6 @@ void HTMLMediaElement::MetadataLoaded(const MediaInfo* aInfo,
|
||||
ProcessMediaFragmentURI();
|
||||
mDecoder->SetFragmentEndTime(mFragmentEnd);
|
||||
}
|
||||
if (mIsEncrypted) {
|
||||
// We only support playback of encrypted content via MSE by default.
|
||||
if (!mMediaSource && Preferences::GetBool("media.eme.mse-only", true)) {
|
||||
DecodeError(
|
||||
MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
|
||||
"Encrypted content not supported outside of MSE"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (IsVideo() && aInfo->HasVideo()) {
|
||||
// We are a video element playing video so update the screen wakelock
|
||||
|
@ -117,7 +117,6 @@ MediaLoadUnsupportedTypeAttributeLoadingNextChild=Specified “type” attribute
|
||||
MediaLoadUnsupportedMimeType=HTTP “Content-Type” of “%1$S” is not supported. Load of media resource %2$S failed.
|
||||
# LOCALIZATION NOTE: %S is the URL of the media resource which failed to load because of error in decoding.
|
||||
MediaLoadDecodeError=Media resource %S could not be decoded.
|
||||
MediaWidevineNoWMF=Trying to play Widevine with no Windows Media Foundation. See https://support.mozilla.org/kb/fix-video-audio-problems-firefox-windows
|
||||
# LOCALIZATION NOTE: %S is a comma-separated list of codecs (e.g. 'video/mp4, video/webm')
|
||||
MediaWMFNeeded=To play video formats %S, you need to install extra Microsoft software, see https://support.mozilla.org/kb/fix-video-audio-problems-firefox-windows
|
||||
# LOCALIZATION NOTE: %S is a comma-separated list of codecs (e.g. 'video/mp4, video/webm')
|
||||
|
@ -10,5 +10,3 @@ openH264_name=OpenH264 Video Codec provided by Cisco Systems, Inc.
|
||||
openH264_description2=This plugin is automatically installed by Mozilla to comply with the WebRTC specification and to enable WebRTC calls with devices that require the H.264 video codec. Visit https://www.openh264.org/ to view the codec source code and learn more about the implementation.
|
||||
|
||||
cdm_description2=This plugin enables playback of encrypted media in compliance with the Encrypted Media Extensions specification. Encrypted media is typically used by sites to protect against copying of premium media content. Visit https://www.w3.org/TR/encrypted-media/ for more information on Encrypted Media Extensions.
|
||||
|
||||
widevine_description=Widevine Content Decryption Module provided by Google Inc.
|
||||
|
@ -42,10 +42,6 @@ namespace mozilla {
|
||||
|
||||
class MediaContainerType;
|
||||
|
||||
// EME Key System String.
|
||||
#define EME_KEY_SYSTEM_CLEARKEY "org.w3.clearkey"
|
||||
#define EME_KEY_SYSTEM_WIDEVINE "com.widevine.alpha"
|
||||
|
||||
/**
|
||||
* ReentrantMonitorConditionallyEnter
|
||||
*
|
||||
|
@ -238,10 +238,6 @@ struct NotificationAndReportStringId {
|
||||
};
|
||||
|
||||
// Note: ReportStringIds are limited to alphanumeric only.
|
||||
static const NotificationAndReportStringId sMediaWidevineNoWMF = {
|
||||
dom::DecoderDoctorNotificationType::Platform_decoder_not_found,
|
||||
"MediaWidevineNoWMF",
|
||||
{ReportParam::None}};
|
||||
static const NotificationAndReportStringId sMediaWMFNeeded = {
|
||||
dom::DecoderDoctorNotificationType::Platform_decoder_not_found,
|
||||
"MediaWMFNeeded",
|
||||
@ -276,8 +272,7 @@ static const NotificationAndReportStringId sMediaDecodeWarning = {
|
||||
{ReportParam::ResourceURL, ReportParam::DecodeIssue}};
|
||||
|
||||
static const NotificationAndReportStringId* const
|
||||
sAllNotificationsAndReportStringIds[] = {&sMediaWidevineNoWMF,
|
||||
&sMediaWMFNeeded,
|
||||
sAllNotificationsAndReportStringIds[] = {&sMediaWMFNeeded,
|
||||
&sMediaPlatformDecoderNotFound,
|
||||
&sMediaCannotPlayNoDecoders,
|
||||
&sMediaNoDecoders,
|
||||
@ -493,10 +488,6 @@ void DecoderDoctorDocumentWatcher::SynthesizeAnalysis() {
|
||||
#if defined(MOZ_FFMPEG)
|
||||
nsAutoString formatsRequiringFFMpeg;
|
||||
#endif
|
||||
nsAutoString supportedKeySystems;
|
||||
nsAutoString unsupportedKeySystems;
|
||||
DecoderDoctorDiagnostics::KeySystemIssue lastKeySystemIssue =
|
||||
DecoderDoctorDiagnostics::eUnset;
|
||||
// Only deal with one decode error per document (the first one found).
|
||||
const MediaResult* firstDecodeError = nullptr;
|
||||
const nsString* firstDecodeErrorMediaSrc = nullptr;
|
||||
@ -552,15 +543,13 @@ void DecoderDoctorDocumentWatcher::SynthesizeAnalysis() {
|
||||
|
||||
// Check if issues have been solved, by finding if some now-playable
|
||||
// key systems or formats were previously recorded as having issues.
|
||||
if (!supportedKeySystems.IsEmpty() || !playableFormats.IsEmpty()) {
|
||||
if (!playableFormats.IsEmpty()) {
|
||||
DD_DEBUG(
|
||||
"DecoderDoctorDocumentWatcher[%p, doc=%p]::SynthesizeAnalysis() - "
|
||||
"supported key systems '%s', playable formats '%s'; See if they show "
|
||||
"playable formats '%s'; See if they show "
|
||||
"issues have been solved...",
|
||||
this, mDocument, NS_ConvertUTF16toUTF8(supportedKeySystems).Data(),
|
||||
NS_ConvertUTF16toUTF8(playableFormats).get());
|
||||
const nsAString* workingFormatsArray[] = {&supportedKeySystems,
|
||||
&playableFormats};
|
||||
this, mDocument, NS_ConvertUTF16toUTF8(playableFormats).get());
|
||||
const nsAString* workingFormats = &playableFormats;
|
||||
// For each type of notification, retrieve the pref that contains formats/
|
||||
// key systems with issues.
|
||||
for (const NotificationAndReportStringId* id :
|
||||
@ -576,23 +565,21 @@ void DecoderDoctorDocumentWatcher::SynthesizeAnalysis() {
|
||||
// See if that list of formats-with-issues contains any formats that are
|
||||
// now playable/supported.
|
||||
bool solved = false;
|
||||
for (const nsAString* workingFormats : workingFormatsArray) {
|
||||
for (const auto& workingFormat : MakeStringListRange(*workingFormats)) {
|
||||
if (FormatsListContains(formatsWithIssues, workingFormat)) {
|
||||
// This now-working format used not to work -> Report solved issue.
|
||||
DD_INFO(
|
||||
"DecoderDoctorDocumentWatcher[%p, "
|
||||
"doc=%p]::SynthesizeAnalysis() - %s solved ('%s' now works, it "
|
||||
"was in pref(%s)='%s')",
|
||||
this, mDocument, id->mReportStringId,
|
||||
NS_ConvertUTF16toUTF8(workingFormat).get(), formatsPref.Data(),
|
||||
NS_ConvertUTF16toUTF8(formatsWithIssues).get());
|
||||
ReportAnalysis(mDocument, *id, true, workingFormat);
|
||||
// This particular Notification&ReportId has been solved, no need
|
||||
// to keep looking at other keysys/formats that might solve it too.
|
||||
solved = true;
|
||||
break;
|
||||
}
|
||||
for (const auto& workingFormat : MakeStringListRange(*workingFormats)) {
|
||||
if (FormatsListContains(formatsWithIssues, workingFormat)) {
|
||||
// This now-working format used not to work -> Report solved issue.
|
||||
DD_INFO(
|
||||
"DecoderDoctorDocumentWatcher[%p, "
|
||||
"doc=%p]::SynthesizeAnalysis() - %s solved ('%s' now works, it "
|
||||
"was in pref(%s)='%s')",
|
||||
this, mDocument, id->mReportStringId,
|
||||
NS_ConvertUTF16toUTF8(workingFormat).get(), formatsPref.Data(),
|
||||
NS_ConvertUTF16toUTF8(formatsWithIssues).get());
|
||||
ReportAnalysis(mDocument, *id, true, workingFormat);
|
||||
// This particular Notification&ReportId has been solved, no need
|
||||
// to keep looking at other keysys/formats that might solve it too.
|
||||
solved = true;
|
||||
break;
|
||||
}
|
||||
if (solved) {
|
||||
break;
|
||||
@ -608,25 +595,6 @@ void DecoderDoctorDocumentWatcher::SynthesizeAnalysis() {
|
||||
}
|
||||
}
|
||||
|
||||
// Look at Key System issues first, as they take precedence over format
|
||||
// checks.
|
||||
if (!unsupportedKeySystems.IsEmpty() && supportedKeySystems.IsEmpty()) {
|
||||
// No supported key systems!
|
||||
switch (lastKeySystemIssue) {
|
||||
case DecoderDoctorDiagnostics::eWidevineWithNoWMF:
|
||||
DD_INFO(
|
||||
"DecoderDoctorDocumentWatcher[%p, doc=%p]::SynthesizeAnalysis() - "
|
||||
"unsupported key systems: %s, Widevine without WMF",
|
||||
this, mDocument,
|
||||
NS_ConvertUTF16toUTF8(unsupportedKeySystems).get());
|
||||
ReportAnalysis(mDocument, sMediaWidevineNoWMF, false,
|
||||
unsupportedKeySystems);
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Next, check playability of requested formats.
|
||||
if (!unplayableFormats.IsEmpty()) {
|
||||
// Some requested formats cannot be played.
|
||||
|
@ -88,14 +88,6 @@ class DecoderDoctorDiagnostics {
|
||||
void SetGMP(const nsACString& aGMP) { mGMP = aGMP; }
|
||||
const nsACString& GMP() const { return mGMP; }
|
||||
|
||||
const nsAString& KeySystem() const { return mKeySystem; }
|
||||
bool IsKeySystemSupported() const { return mIsKeySystemSupported; }
|
||||
enum KeySystemIssue { eUnset, eWidevineWithNoWMF };
|
||||
void SetKeySystemIssue(KeySystemIssue aKeySystemIssue) {
|
||||
mKeySystemIssue = aKeySystemIssue;
|
||||
}
|
||||
KeySystemIssue GetKeySystemIssue() const { return mKeySystemIssue; }
|
||||
|
||||
DecoderDoctorEvent event() const { return mEvent; }
|
||||
|
||||
const MediaResult& DecodeIssue() const { return mDecodeIssue; }
|
||||
@ -118,10 +110,6 @@ class DecoderDoctorDiagnostics {
|
||||
bool mAudioNotSupported = false;
|
||||
nsCString mGMP;
|
||||
|
||||
nsString mKeySystem;
|
||||
bool mIsKeySystemSupported = false;
|
||||
KeySystemIssue mKeySystemIssue = eUnset;
|
||||
|
||||
DecoderDoctorEvent mEvent;
|
||||
|
||||
MediaResult mDecodeIssue = NS_OK;
|
||||
|
@ -254,64 +254,6 @@ GMPErr GMPChild::GetAPI(const char* aAPIName, void* aHostAPI, void** aPluginAPI,
|
||||
return mGMPLoader->GetAPI(aAPIName, aHostAPI, aPluginAPI, aDecryptorId);
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult GMPChild::RecvPreloadLibs(const nsCString& aLibs) {
|
||||
// Pre-load libraries that may need to be used by the EME plugin but that
|
||||
// can't be loaded after the sandbox has started.
|
||||
#ifdef XP_WIN
|
||||
// Items in this must be lowercase!
|
||||
constexpr static const char16_t* whitelist[] = {
|
||||
u"dxva2.dll", // Get monitor information
|
||||
u"evr.dll", // MFGetStrideForBitmapInfoHeader
|
||||
u"freebl3.dll", // NSS for clearkey CDM
|
||||
u"mfplat.dll", // MFCreateSample, MFCreateAlignedMemoryBuffer,
|
||||
// MFCreateMediaType
|
||||
u"msmpeg2vdec.dll", // H.264 decoder
|
||||
u"nss3.dll", // NSS for clearkey CDM
|
||||
u"psapi.dll", // For GetMappedFileNameW, see bug 1383611
|
||||
u"softokn3.dll", // NSS for clearkey CDM
|
||||
};
|
||||
constexpr static bool (*IsASCII)(const char16_t*) =
|
||||
IsAsciiNullTerminated<char16_t>;
|
||||
static_assert(AllOf(std::begin(whitelist), std::end(whitelist), IsASCII),
|
||||
"Items in the whitelist must not contain non-ASCII "
|
||||
"characters!");
|
||||
|
||||
nsTArray<nsCString> libs;
|
||||
SplitAt(", ", aLibs, libs);
|
||||
for (nsCString lib : libs) {
|
||||
ToLowerCase(lib);
|
||||
for (const char16_t* whiteListedLib : whitelist) {
|
||||
if (nsDependentString(whiteListedLib)
|
||||
.EqualsASCII(lib.Data(), lib.Length())) {
|
||||
LoadLibraryW(char16ptr_t(whiteListedLib));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#elif defined(XP_LINUX)
|
||||
constexpr static const char* whitelist[] = {
|
||||
"libfreeblpriv3.so",
|
||||
"libsoftokn3.so",
|
||||
};
|
||||
|
||||
nsTArray<nsCString> libs;
|
||||
SplitAt(", ", aLibs, libs);
|
||||
for (const nsCString& lib : libs) {
|
||||
for (const char* whiteListedLib : whitelist) {
|
||||
if (lib.EqualsASCII(whiteListedLib)) {
|
||||
auto libHandle = dlopen(whiteListedLib, RTLD_NOW | RTLD_GLOBAL);
|
||||
if (libHandle) {
|
||||
mLibHandles.AppendElement(libHandle);
|
||||
} else {
|
||||
MOZ_CRASH("Couldn't load lib needed by NSS");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
bool GMPChild::GetUTF8LibPath(nsACString& aOutLibPath) {
|
||||
#if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
|
||||
nsAutoCString pluginDirectoryPath, pluginFilePath;
|
||||
|
@ -44,7 +44,6 @@ class GMPChild : public PGMPChild {
|
||||
mozilla::ipc::IPCResult RecvProvideStorageId(const nsCString& aStorageId);
|
||||
|
||||
mozilla::ipc::IPCResult AnswerStartPlugin(const nsString& aAdapter);
|
||||
mozilla::ipc::IPCResult RecvPreloadLibs(const nsCString& aLibs);
|
||||
|
||||
PGMPTimerChild* AllocPGMPTimerChild();
|
||||
bool DeallocPGMPTimerChild(PGMPTimerChild* aActor);
|
||||
|
@ -77,9 +77,6 @@ void GMPParent::CloneFrom(const GMPParent* aOther) {
|
||||
mVersion = aOther->mVersion;
|
||||
mDescription = aOther->mDescription;
|
||||
mDisplayName = aOther->mDisplayName;
|
||||
#if defined(XP_WIN) || defined(XP_LINUX)
|
||||
mLibs = aOther->mLibs;
|
||||
#endif
|
||||
for (const GMPCapability& cap : aOther->mCapabilities) {
|
||||
mCapabilities.AppendElement(cap);
|
||||
}
|
||||
@ -159,19 +156,6 @@ nsresult GMPParent::LoadProcess() {
|
||||
GMP_PARENT_LOG_DEBUG("%s: Opened channel to new child process",
|
||||
__FUNCTION__);
|
||||
|
||||
#if defined(XP_WIN) || defined(XP_LINUX)
|
||||
if (!mLibs.IsEmpty()) {
|
||||
bool ok = SendPreloadLibs(mLibs);
|
||||
if (!ok) {
|
||||
GMP_PARENT_LOG_DEBUG("%s: Failed to send preload-libs to child process",
|
||||
__FUNCTION__);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
GMP_PARENT_LOG_DEBUG("%s: Sent preload-libs ('%s') to child process",
|
||||
__FUNCTION__, mLibs.get());
|
||||
}
|
||||
#endif
|
||||
|
||||
// Intr call to block initialization on plugin load.
|
||||
if (!CallStartPlugin(mAdapter)) {
|
||||
GMP_PARENT_LOG_DEBUG("%s: Failed to send start to child process",
|
||||
@ -369,19 +353,6 @@ bool GMPCapability::Supports(const nsTArray<GMPCapability>& aCapabilities,
|
||||
}
|
||||
for (const nsCString& tag : capabilities.mAPITags) {
|
||||
if (tag.Equals(aTag)) {
|
||||
#ifdef XP_WIN
|
||||
// Clearkey on Windows advertises that it can decode in its GMP info
|
||||
// file, but uses Windows Media Foundation to decode. That's not present
|
||||
// on Windows XP, and on some Vista, Windows N, and KN variants without
|
||||
// certain services packs.
|
||||
if (tag.EqualsLiteral(EME_KEY_SYSTEM_CLEARKEY)) {
|
||||
if (capabilities.mAPIName.EqualsLiteral(GMP_API_VIDEO_DECODER)) {
|
||||
if (!WMFDecoderModule::HasH264()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -561,11 +532,6 @@ RefPtr<GenericPromise> GMPParent::ReadGMPInfoFile(nsIFile* aFile) {
|
||||
return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
|
||||
}
|
||||
|
||||
#if defined(XP_WIN) || defined(XP_LINUX)
|
||||
// "Libraries" field is optional.
|
||||
ReadInfoField(parser, NS_LITERAL_CSTRING("libraries"), mLibs);
|
||||
#endif
|
||||
|
||||
nsTArray<nsCString> apiTokens;
|
||||
SplitAt(", ", apis, apiTokens);
|
||||
for (nsCString api : apiTokens) {
|
||||
|
@ -176,9 +176,6 @@ class GMPParent final
|
||||
nsCString mDisplayName; // name of plugin displayed to users
|
||||
nsCString mDescription; // description of plugin for display to users
|
||||
nsCString mVersion;
|
||||
#if defined(XP_WIN) || defined(XP_LINUX)
|
||||
nsCString mLibs;
|
||||
#endif
|
||||
nsString mAdapter;
|
||||
uint32_t mPluginId;
|
||||
nsTArray<GMPCapability> mCapabilities;
|
||||
|
@ -27,7 +27,6 @@ child:
|
||||
async CrashPluginNow();
|
||||
intr StartPlugin(nsString adapter);
|
||||
async ProvideStorageId(nsCString storageId);
|
||||
async PreloadLibs(nsCString libs);
|
||||
async CloseActive();
|
||||
async InitGMPContentChild(Endpoint<PGMPContentChild> endpoint);
|
||||
};
|
||||
|
@ -72,9 +72,9 @@ MediaResult RemoteAudioDecoderChild::InitIPDL(
|
||||
RemoteAudioDecoderParent::RemoteAudioDecoderParent(
|
||||
RemoteDecoderManagerParent* aParent, const AudioInfo& aAudioInfo,
|
||||
const CreateDecoderParams::OptionSet& aOptions,
|
||||
nsISerialEventTarget* aManagerThread, TaskQueue* aDecodeTaskQueue,
|
||||
bool* aSuccess, nsCString* aErrorDescription)
|
||||
: RemoteDecoderParent(aParent, aManagerThread, aDecodeTaskQueue),
|
||||
TaskQueue* aManagerTaskQueue, TaskQueue* aDecodeTaskQueue, bool* aSuccess,
|
||||
nsCString* aErrorDescription)
|
||||
: RemoteDecoderParent(aParent, aManagerTaskQueue, aDecodeTaskQueue),
|
||||
mAudioInfo(aAudioInfo) {
|
||||
CreateDecoderParams params(mAudioInfo);
|
||||
params.mTaskQueue = mDecodeTaskQueue;
|
||||
|
@ -26,14 +26,13 @@ class RemoteAudioDecoderParent final : public RemoteDecoderParent {
|
||||
RemoteAudioDecoderParent(RemoteDecoderManagerParent* aParent,
|
||||
const AudioInfo& aAudioInfo,
|
||||
const CreateDecoderParams::OptionSet& aOptions,
|
||||
nsISerialEventTarget* aManagerThread,
|
||||
TaskQueue* aManagerTaskQueue,
|
||||
TaskQueue* aDecodeTaskQueue, bool* aSuccess,
|
||||
nsCString* aErrorDescription);
|
||||
|
||||
protected:
|
||||
MediaResult ProcessDecodedData(const MediaDataDecoder::DecodedData& aData,
|
||||
DecodedOutputIPDL& aDecodedData) override;
|
||||
|
||||
private:
|
||||
// Can only be accessed from the manager thread
|
||||
// Note: we can't keep a reference to the original AudioInfo here
|
||||
|
@ -27,7 +27,8 @@ using namespace ipc;
|
||||
using namespace layers;
|
||||
using namespace gfx;
|
||||
|
||||
StaticRefPtr<nsISerialEventTarget> sRemoteDecoderManagerParentThread;
|
||||
StaticRefPtr<nsIThread> sRemoteDecoderManagerParentThread;
|
||||
StaticRefPtr<TaskQueue> sRemoteDecoderManagerTaskQueue;
|
||||
|
||||
SurfaceDescriptorGPUVideo RemoteDecoderManagerParent::StoreImage(
|
||||
Image* aImage, TextureClient* aTexture) {
|
||||
@ -39,6 +40,27 @@ SurfaceDescriptorGPUVideo RemoteDecoderManagerParent::StoreImage(
|
||||
return ret;
|
||||
}
|
||||
|
||||
class RemoteDecoderManagerThreadHolder {
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RemoteDecoderManagerThreadHolder)
|
||||
|
||||
public:
|
||||
RemoteDecoderManagerThreadHolder() = default;
|
||||
|
||||
private:
|
||||
~RemoteDecoderManagerThreadHolder() {
|
||||
NS_DispatchToMainThread(
|
||||
NS_NewRunnableFunction("dom::RemoteDecoderManagerThreadHolder::~"
|
||||
"RemoteDecoderManagerThreadHolder",
|
||||
[]() {
|
||||
sRemoteDecoderManagerParentThread->Shutdown();
|
||||
sRemoteDecoderManagerParentThread = nullptr;
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
StaticRefPtr<RemoteDecoderManagerThreadHolder>
|
||||
sRemoteDecoderManagerParentThreadHolder;
|
||||
|
||||
class RemoteDecoderManagerThreadShutdownObserver : public nsIObserver {
|
||||
virtual ~RemoteDecoderManagerThreadShutdownObserver() = default;
|
||||
|
||||
@ -70,13 +92,25 @@ bool RemoteDecoderManagerParent::StartupThreads() {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISerialEventTarget> managerThread;
|
||||
nsresult rv = NS_CreateBackgroundTaskQueue("RemVidParent",
|
||||
getter_AddRefs(managerThread));
|
||||
RefPtr<nsIThread> managerThread;
|
||||
nsresult rv =
|
||||
NS_NewNamedThread("RemVidParent", getter_AddRefs(managerThread));
|
||||
if (NS_FAILED(rv)) {
|
||||
return false;
|
||||
}
|
||||
sRemoteDecoderManagerParentThread = managerThread;
|
||||
sRemoteDecoderManagerParentThreadHolder =
|
||||
new RemoteDecoderManagerThreadHolder();
|
||||
#if XP_WIN
|
||||
sRemoteDecoderManagerParentThread->Dispatch(
|
||||
NS_NewRunnableFunction("RemoteDecoderManagerParent::StartupThreads",
|
||||
[]() {
|
||||
DebugOnly<HRESULT> hr =
|
||||
CoInitializeEx(0, COINIT_MULTITHREADED);
|
||||
MOZ_ASSERT(SUCCEEDED(hr));
|
||||
}),
|
||||
NS_DISPATCH_NORMAL);
|
||||
#endif
|
||||
if (XRE_IsGPUProcess()) {
|
||||
sRemoteDecoderManagerParentThread->Dispatch(
|
||||
NS_NewRunnableFunction(
|
||||
@ -85,22 +119,26 @@ bool RemoteDecoderManagerParent::StartupThreads() {
|
||||
NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
sRemoteDecoderManagerTaskQueue = new TaskQueue(
|
||||
managerThread.forget(),
|
||||
"RemoteDecoderManagerParent::sRemoteDecoderManagerTaskQueue");
|
||||
|
||||
auto* obs = new RemoteDecoderManagerThreadShutdownObserver();
|
||||
observerService->AddObserver(obs, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
void RemoteDecoderManagerParent::ShutdownThreads() {
|
||||
sRemoteDecoderManagerParentThread = nullptr;
|
||||
sRemoteDecoderManagerTaskQueue = nullptr;
|
||||
|
||||
sRemoteDecoderManagerParentThreadHolder = nullptr;
|
||||
while (sRemoteDecoderManagerParentThread) {
|
||||
NS_ProcessNextEvent(nullptr, true);
|
||||
}
|
||||
}
|
||||
|
||||
void RemoteDecoderManagerParent::ShutdownVideoBridge() {
|
||||
if (sRemoteDecoderManagerParentThread) {
|
||||
if (sRemoteDecoderManagerParentThread->IsOnCurrentThread()) {
|
||||
VideoBridgeChild::Shutdown();
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<Runnable> task = NS_NewRunnableFunction(
|
||||
"RemoteDecoderManagerParent::ShutdownVideoBridge",
|
||||
[]() { VideoBridgeChild::Shutdown(); });
|
||||
@ -109,7 +147,7 @@ void RemoteDecoderManagerParent::ShutdownVideoBridge() {
|
||||
}
|
||||
|
||||
bool RemoteDecoderManagerParent::OnManagerThread() {
|
||||
return sRemoteDecoderManagerParentThread->IsOnCurrentThread();
|
||||
return NS_GetCurrentThread() == sRemoteDecoderManagerParentThread;
|
||||
}
|
||||
|
||||
bool RemoteDecoderManagerParent::CreateForContent(
|
||||
@ -123,7 +161,7 @@ bool RemoteDecoderManagerParent::CreateForContent(
|
||||
}
|
||||
|
||||
RefPtr<RemoteDecoderManagerParent> parent =
|
||||
new RemoteDecoderManagerParent(sRemoteDecoderManagerParentThread);
|
||||
new RemoteDecoderManagerParent(sRemoteDecoderManagerParentThreadHolder);
|
||||
|
||||
RefPtr<Runnable> task =
|
||||
NewRunnableMethod<Endpoint<PRemoteDecoderManagerParent>&&>(
|
||||
@ -154,8 +192,8 @@ bool RemoteDecoderManagerParent::CreateVideoBridgeToOtherProcess(
|
||||
}
|
||||
|
||||
RemoteDecoderManagerParent::RemoteDecoderManagerParent(
|
||||
nsISerialEventTarget* aThread)
|
||||
: mThread(aThread) {
|
||||
RemoteDecoderManagerThreadHolder* aHolder)
|
||||
: mThreadHolder(aHolder) {
|
||||
MOZ_COUNT_CTOR(RemoteDecoderManagerParent);
|
||||
}
|
||||
|
||||
@ -165,7 +203,7 @@ RemoteDecoderManagerParent::~RemoteDecoderManagerParent() {
|
||||
|
||||
void RemoteDecoderManagerParent::ActorDestroy(
|
||||
mozilla::ipc::IProtocol::ActorDestroyReason) {
|
||||
mThread = nullptr;
|
||||
mThreadHolder = nullptr;
|
||||
}
|
||||
|
||||
PRemoteDecoderParent* RemoteDecoderManagerParent::AllocPRemoteDecoderParent(
|
||||
@ -183,12 +221,12 @@ PRemoteDecoderParent* RemoteDecoderManagerParent::AllocPRemoteDecoderParent(
|
||||
aRemoteDecoderInfo.get_VideoDecoderInfoIPDL();
|
||||
return new RemoteVideoDecoderParent(
|
||||
this, decoderInfo.videoInfo(), decoderInfo.framerate(), aOptions,
|
||||
aIdentifier, sRemoteDecoderManagerParentThread, decodeTaskQueue,
|
||||
aSuccess, aErrorDescription);
|
||||
aIdentifier, sRemoteDecoderManagerTaskQueue, decodeTaskQueue, aSuccess,
|
||||
aErrorDescription);
|
||||
} else if (aRemoteDecoderInfo.type() == RemoteDecoderInfoIPDL::TAudioInfo) {
|
||||
return new RemoteAudioDecoderParent(
|
||||
this, aRemoteDecoderInfo.get_AudioInfo(), aOptions,
|
||||
sRemoteDecoderManagerParentThread, decodeTaskQueue, aSuccess,
|
||||
sRemoteDecoderManagerTaskQueue, decodeTaskQueue, aSuccess,
|
||||
aErrorDescription);
|
||||
}
|
||||
|
||||
|
@ -47,10 +47,12 @@ class RemoteDecoderManagerParent final : public PRemoteDecoderManagerParent {
|
||||
const SurfaceDescriptorGPUVideo& aSD);
|
||||
|
||||
void ActorDestroy(mozilla::ipc::IProtocol::ActorDestroyReason) override;
|
||||
|
||||
void ActorDealloc() override;
|
||||
|
||||
private:
|
||||
explicit RemoteDecoderManagerParent(nsISerialEventTarget* aThread);
|
||||
explicit RemoteDecoderManagerParent(
|
||||
RemoteDecoderManagerThreadHolder* aThreadHolder);
|
||||
~RemoteDecoderManagerParent();
|
||||
|
||||
void Open(Endpoint<PRemoteDecoderManagerParent>&& aEndpoint);
|
||||
@ -58,7 +60,7 @@ class RemoteDecoderManagerParent final : public PRemoteDecoderManagerParent {
|
||||
std::map<uint64_t, RefPtr<layers::Image>> mImageMap;
|
||||
std::map<uint64_t, RefPtr<layers::TextureClient>> mTextureMap;
|
||||
|
||||
nsCOMPtr<nsISerialEventTarget> mThread;
|
||||
RefPtr<RemoteDecoderManagerThreadHolder> mThreadHolder;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -10,11 +10,11 @@
|
||||
namespace mozilla {
|
||||
|
||||
RemoteDecoderParent::RemoteDecoderParent(RemoteDecoderManagerParent* aParent,
|
||||
nsISerialEventTarget* aManagerThread,
|
||||
TaskQueue* aManagerTaskQueue,
|
||||
TaskQueue* aDecodeTaskQueue)
|
||||
: mParent(aParent),
|
||||
mDecodeTaskQueue(aDecodeTaskQueue),
|
||||
mManagerThread(aManagerThread),
|
||||
mManagerTaskQueue(aManagerTaskQueue),
|
||||
mDecodedFramePool(1, ShmemPool::PoolType::DynamicPool) {
|
||||
MOZ_COUNT_CTOR(RemoteDecoderParent);
|
||||
MOZ_ASSERT(OnManagerThread());
|
||||
@ -39,7 +39,7 @@ mozilla::ipc::IPCResult RemoteDecoderParent::RecvInit(
|
||||
MOZ_ASSERT(OnManagerThread());
|
||||
RefPtr<RemoteDecoderParent> self = this;
|
||||
mDecoder->Init()->Then(
|
||||
mManagerThread, __func__,
|
||||
mManagerTaskQueue, __func__,
|
||||
[self, resolver = std::move(aResolver)](
|
||||
MediaDataDecoder::InitPromise::ResolveOrRejectValue&& aValue) {
|
||||
if (!self->CanRecv()) {
|
||||
@ -91,7 +91,7 @@ mozilla::ipc::IPCResult RemoteDecoderParent::RecvDecode(
|
||||
|
||||
RefPtr<RemoteDecoderParent> self = this;
|
||||
mDecoder->Decode(data)->Then(
|
||||
mManagerThread, __func__,
|
||||
mManagerTaskQueue, __func__,
|
||||
[self, this, resolver = std::move(aResolver)](
|
||||
MediaDataDecoder::DecodePromise::ResolveOrRejectValue&& aValue) {
|
||||
// If we are here, we know all previously returned DecodedOutputIPDL got
|
||||
@ -123,7 +123,7 @@ mozilla::ipc::IPCResult RemoteDecoderParent::RecvFlush(
|
||||
MOZ_ASSERT(OnManagerThread());
|
||||
RefPtr<RemoteDecoderParent> self = this;
|
||||
mDecoder->Flush()->Then(
|
||||
mManagerThread, __func__,
|
||||
mManagerTaskQueue, __func__,
|
||||
[self, resolver = std::move(aResolver)](
|
||||
MediaDataDecoder::FlushPromise::ResolveOrRejectValue&& aValue) {
|
||||
if (aValue.IsReject()) {
|
||||
@ -141,7 +141,7 @@ mozilla::ipc::IPCResult RemoteDecoderParent::RecvDrain(
|
||||
MOZ_ASSERT(OnManagerThread());
|
||||
RefPtr<RemoteDecoderParent> self = this;
|
||||
mDecoder->Drain()->Then(
|
||||
mManagerThread, __func__,
|
||||
mManagerTaskQueue, __func__,
|
||||
[self, this, resolver = std::move(aResolver)](
|
||||
MediaDataDecoder::DecodePromise::ResolveOrRejectValue&& aValue) {
|
||||
if (!self->CanRecv()) {
|
||||
@ -169,7 +169,7 @@ mozilla::ipc::IPCResult RemoteDecoderParent::RecvShutdown(
|
||||
if (mDecoder) {
|
||||
RefPtr<RemoteDecoderParent> self = this;
|
||||
mDecoder->Shutdown()->Then(
|
||||
mManagerThread, __func__,
|
||||
mManagerTaskQueue, __func__,
|
||||
[self, resolver = std::move(aResolver)](
|
||||
const ShutdownPromise::ResolveOrRejectValue& aValue) {
|
||||
MOZ_ASSERT(aValue.IsResolve());
|
||||
|
@ -21,7 +21,7 @@ class RemoteDecoderParent : public PRemoteDecoderParent {
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RemoteDecoderParent)
|
||||
|
||||
RemoteDecoderParent(RemoteDecoderManagerParent* aParent,
|
||||
nsISerialEventTarget* aManagerThread,
|
||||
TaskQueue* aManagerTaskQueue,
|
||||
TaskQueue* aDecodeTaskQueue);
|
||||
|
||||
void Destroy();
|
||||
@ -56,7 +56,7 @@ class RemoteDecoderParent : public PRemoteDecoderParent {
|
||||
void ReleaseBuffer(ShmemBuffer&& aBuffer);
|
||||
void ReleaseUsedShmems();
|
||||
RefPtr<RemoteDecoderParent> mIPDLSelfRef;
|
||||
const RefPtr<nsISerialEventTarget> mManagerThread;
|
||||
const RefPtr<TaskQueue> mManagerTaskQueue;
|
||||
ShmemPool mDecodedFramePool;
|
||||
AutoTArray<ShmemBuffer, 4> mUsedShmems;
|
||||
};
|
||||
|
@ -246,9 +246,9 @@ RemoteVideoDecoderParent::RemoteVideoDecoderParent(
|
||||
RemoteDecoderManagerParent* aParent, const VideoInfo& aVideoInfo,
|
||||
float aFramerate, const CreateDecoderParams::OptionSet& aOptions,
|
||||
const Maybe<layers::TextureFactoryIdentifier>& aIdentifier,
|
||||
nsISerialEventTarget* aManagerThread, TaskQueue* aDecodeTaskQueue,
|
||||
bool* aSuccess, nsCString* aErrorDescription)
|
||||
: RemoteDecoderParent(aParent, aManagerThread, aDecodeTaskQueue),
|
||||
TaskQueue* aManagerTaskQueue, TaskQueue* aDecodeTaskQueue, bool* aSuccess,
|
||||
nsCString* aErrorDescription)
|
||||
: RemoteDecoderParent(aParent, aManagerTaskQueue, aDecodeTaskQueue),
|
||||
mVideoInfo(aVideoInfo) {
|
||||
if (aIdentifier) {
|
||||
// Check to see if we have a direct PVideoBridge connection to the
|
||||
|
@ -51,8 +51,8 @@ class RemoteVideoDecoderParent final : public RemoteDecoderParent {
|
||||
RemoteDecoderManagerParent* aParent, const VideoInfo& aVideoInfo,
|
||||
float aFramerate, const CreateDecoderParams::OptionSet& aOptions,
|
||||
const Maybe<layers::TextureFactoryIdentifier>& aIdentifier,
|
||||
nsISerialEventTarget* aManagerThread, TaskQueue* aDecodeTaskQueue,
|
||||
bool* aSuccess, nsCString* aErrorDescription);
|
||||
TaskQueue* aManagerTaskQueue, TaskQueue* aDecodeTaskQueue, bool* aSuccess,
|
||||
nsCString* aErrorDescription);
|
||||
|
||||
protected:
|
||||
MediaResult ProcessDecodedData(const MediaDataDecoder::DecodedData& aData,
|
||||
|
@ -507,10 +507,7 @@ void PluginModuleChromeParent::OnProcessLaunched(const bool aSucceeded) {
|
||||
|
||||
#if defined(XP_WIN) && defined(_X86_)
|
||||
// Protected mode only applies to Windows and only to x86.
|
||||
if (!mIsBlocklisted && mIsFlashPlugin &&
|
||||
(Preferences::GetBool("dom.ipc.plugins.flash.disable-protected-mode",
|
||||
false) ||
|
||||
mSandboxLevel >= 2)) {
|
||||
if (!mIsBlocklisted && mIsFlashPlugin) {
|
||||
Unused << SendDisableFlashProtectedMode();
|
||||
}
|
||||
#endif
|
||||
|
@ -9,7 +9,6 @@ support-files =
|
||||
file_clipboard_events_chrome.html
|
||||
file_DOM_element_instanceof.xul
|
||||
file_MozDomFullscreen.html
|
||||
file_bug799299.xul
|
||||
file_bug800817.xul
|
||||
file_bug830858.xul
|
||||
file_bug1224790-1_modal.xul
|
||||
@ -41,7 +40,6 @@ support-files =
|
||||
[test_DOM_element_instanceof.xul]
|
||||
[test_activation.xul]
|
||||
tags = fullscreen
|
||||
[test_bug799299.xul]
|
||||
[test_bug800817.xul]
|
||||
[test_bug830858.xul]
|
||||
[test_bug1224790-1.xul]
|
||||
|
@ -1,65 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
|
||||
<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=799299
|
||||
-->
|
||||
<window title="Mozilla Bug 799299"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
|
||||
|
||||
<!-- test results are displayed in the html:body -->
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=799299"
|
||||
target="_blank">Mozilla Bug 799299</a>
|
||||
</body>
|
||||
|
||||
<!-- test code goes here -->
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
/** Test for Bug 799299 **/
|
||||
|
||||
function sendClick(win) {
|
||||
var wu = win.windowUtils;
|
||||
wu.sendMouseEventToWindow("mousedown", 10, 10, 0, 0, 0);
|
||||
wu.sendMouseEventToWindow("mouseup", 10, 10, 0, 0, 0);
|
||||
}
|
||||
|
||||
function runTests() {
|
||||
var b1 = document.getElementById("b1");
|
||||
var b2 = document.getElementById("b2");
|
||||
b1.contentWindow.focus();
|
||||
opener.wrappedJSObject.is(document.activeElement, b1,
|
||||
"Focused first iframe");
|
||||
|
||||
var didCallDummy = false;
|
||||
b2.contentWindow.addEventListener("mousedown", function(e) { didCallDummy = true; });
|
||||
sendClick(b2.contentWindow);
|
||||
opener.wrappedJSObject.ok(didCallDummy, "dummy mousedown handler should fire");
|
||||
opener.wrappedJSObject.is(document.activeElement, b2,
|
||||
"Focus shifted to second iframe");
|
||||
|
||||
b1.contentWindow.focus();
|
||||
opener.wrappedJSObject.is(document.activeElement, b1,
|
||||
"Re-focused first iframe for the first time");
|
||||
|
||||
var didCallListener = false;
|
||||
b2.contentWindow.addEventListener("mousedown", function(e) { didCallListener = true; e.preventDefault(); });
|
||||
sendClick(b2.contentWindow);
|
||||
opener.wrappedJSObject.ok(didCallListener, "mousedown handler should fire");
|
||||
opener.wrappedJSObject.is(document.activeElement, b2,
|
||||
"focus should move to the second iframe");
|
||||
|
||||
window.close();
|
||||
opener.wrappedJSObject.SimpleTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForFocus(runTests);
|
||||
]]>
|
||||
</script>
|
||||
<hbox flex="1">
|
||||
<browser id="b1" type="content" src="about:blank" flex="1" style="border: 1px solid black;"/>
|
||||
<browser id="b2" type="content" src="about:blank" flex="1" style="border: 1px solid black;"/>
|
||||
</hbox>
|
||||
</window>
|
@ -1,31 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
|
||||
<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=799299
|
||||
-->
|
||||
<window title="Mozilla Bug 799299" onload="runTests()"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
|
||||
|
||||
<!-- test results are displayed in the html:body -->
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=799299"
|
||||
target="_blank">Mozilla Bug 799299</a>
|
||||
</body>
|
||||
|
||||
<!-- test code goes here -->
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
/** Test for Bug 799299 **/
|
||||
|
||||
function runTests() {
|
||||
window.open("file_bug799299.xul", "_blank", "chrome,width=600,height=550");
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
]]>
|
||||
</script>
|
||||
</window>
|
@ -813,39 +813,6 @@ function startTest()
|
||||
expectFocusShift(() => synthesizeKey("KEY_Tab", {shiftKey: true}),
|
||||
null, textbox1.inputField, true, "shift+tab on textbox with tabindex set");
|
||||
|
||||
// ---- test for bug 618907 which ensures that canceling the mousedown event still focuses the
|
||||
// right frame
|
||||
|
||||
var childContentFrame = document.getElementById("ifa")
|
||||
childContentFrame.style.MozUserFocus = "";
|
||||
|
||||
var frab = childContentFrame.contentDocument.getElementById("fra-b");
|
||||
var mouseDownListener = event => event.preventDefault();
|
||||
frab.addEventListener("mousedown", mouseDownListener, false);
|
||||
|
||||
var childElementToFocus = childContentFrame.contentDocument.getElementById("fra");
|
||||
gLastFocus = childElementToFocus;
|
||||
gLastFocusWindow = childContentFrame.contentWindow;
|
||||
gLastFocus.focus();
|
||||
gEvents = "";
|
||||
|
||||
setFocusTo("t1", window);
|
||||
|
||||
gLastFocusMethod = -1;
|
||||
expectFocusShift(() => synthesizeMouse(frab, 5, 5, { }, childContentFrame.contentWindow),
|
||||
null, childElementToFocus, true,
|
||||
"mousedown event canceled - chrome to content");
|
||||
|
||||
frab.removeEventListener("mousedown", mouseDownListener, false);
|
||||
|
||||
var t5 = getById("t5");
|
||||
t5.addEventListener("mousedown", mouseDownListener, false);
|
||||
synthesizeMouse(t5, 10, 10, { })
|
||||
t5.removeEventListener("mousedown", mouseDownListener, false);
|
||||
is(fm.focusedElement, childElementToFocus,
|
||||
"mousedown event cancelled - content to chrome - element");
|
||||
is(fm.focusedWindow, childContentFrame.contentWindow, "mousedown event cancelled - content to chrome - window");
|
||||
|
||||
// ---- test to check that refocusing an element during a blur event doesn't succeed
|
||||
|
||||
var t1 = getById("t1");
|
||||
|
@ -583,18 +583,6 @@ partial interface Document {
|
||||
[ChromeOnly] readonly attribute DOMString cspJSON;
|
||||
};
|
||||
|
||||
// For more information on Flash classification, see
|
||||
// toolkit/components/url-classifier/flash-block-lists.rst
|
||||
enum FlashClassification {
|
||||
"unknown", // Site is not on the whitelist or blacklist
|
||||
"allowed", // Site is on the Flash whitelist
|
||||
"denied" // Site is on the Flash blacklist
|
||||
};
|
||||
partial interface Document {
|
||||
[ChromeOnly]
|
||||
readonly attribute FlashClassification documentFlashClassification;
|
||||
};
|
||||
|
||||
partial interface Document {
|
||||
[Func="Document::DocumentSupportsL10n"] readonly attribute DocumentL10n? l10n;
|
||||
};
|
||||
|
@ -1,15 +0,0 @@
|
||||
/* 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/.
|
||||
*/
|
||||
|
||||
[GenerateInitFromJSON]
|
||||
dictionary WidevineCDMManifest {
|
||||
required DOMString name;
|
||||
required DOMString description;
|
||||
required DOMString version;
|
||||
required DOMString x-cdm-module-versions;
|
||||
required DOMString x-cdm-interface-versions;
|
||||
required DOMString x-cdm-host-versions;
|
||||
required DOMString x-cdm-codecs;
|
||||
};
|
@ -329,9 +329,6 @@ with Files("Webrtc*"):
|
||||
with Files("WheelEvent.webidl"):
|
||||
BUG_COMPONENT = ("Core", "DOM: Events")
|
||||
|
||||
with Files("WidevineCDMManifest.webidl"):
|
||||
BUG_COMPONENT = ("Core", "Audio/Video: Playback")
|
||||
|
||||
with Files("WindowOrWorkerGlobalScope.webidl"):
|
||||
BUG_COMPONENT = ("Core", "DOM: Workers")
|
||||
|
||||
@ -904,7 +901,6 @@ WEBIDL_FILES = [
|
||||
'WebGLRenderingContext.webidl',
|
||||
'WebSocket.webidl',
|
||||
'WheelEvent.webidl',
|
||||
'WidevineCDMManifest.webidl',
|
||||
'WindowOrWorkerGlobalScope.webidl',
|
||||
'WindowRoot.webidl',
|
||||
'Worker.webidl',
|
||||
|
@ -74,7 +74,8 @@ class SharedGL final {
|
||||
MutexAutoLock lock(sMutex);
|
||||
|
||||
if (mTargetSurface != EGL_NO_SURFACE) {
|
||||
GLLibraryEGL::Get()->fDestroySurface(EGL_DISPLAY(), mTargetSurface);
|
||||
const auto& egl = *(sContext->mEgl);
|
||||
egl.fDestroySurface(egl.Display(), mTargetSurface);
|
||||
}
|
||||
|
||||
// Destroy shared GL context when no one uses it.
|
||||
@ -89,13 +90,14 @@ class SharedGL final {
|
||||
|
||||
auto* egl = gl::GLLibraryEGL::Get();
|
||||
EGLDisplay eglDisplay = egl->fGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||
MOZ_ASSERT(eglDisplay == egl->Display());
|
||||
EGLConfig eglConfig;
|
||||
CreateConfig(&eglConfig, /* bpp */ 24, /* depth buffer? */ false);
|
||||
CreateConfig(egl, &eglConfig, /* bpp */ 24, /* depth buffer? */ false);
|
||||
EGLint attributes[] = {LOCAL_EGL_CONTEXT_CLIENT_VERSION, 2, LOCAL_EGL_NONE};
|
||||
EGLContext eglContext =
|
||||
egl->fCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT, attributes);
|
||||
RefPtr<GLContextEGL> gl = new GLContextEGL(
|
||||
CreateContextFlags::NONE, SurfaceCaps::Any(),
|
||||
egl, CreateContextFlags::NONE, SurfaceCaps::Any(),
|
||||
/* offscreen? */ false, eglConfig, EGL_NO_SURFACE, eglContext);
|
||||
if (!gl->Init()) {
|
||||
NS_WARNING("Fail to create GL context for native blitter.");
|
||||
@ -111,8 +113,9 @@ class SharedGL final {
|
||||
sMutex.AssertCurrentThreadOwns();
|
||||
MOZ_ASSERT(sContext);
|
||||
|
||||
mTargetSurface = gl::GLLibraryEGL::Get()->fCreateWindowSurface(
|
||||
sContext->GetEGLDisplay(), sContext->mConfig, window.NativeWindow(), 0);
|
||||
const auto& egl = *(sContext->mEgl);
|
||||
mTargetSurface = egl.fCreateWindowSurface(egl.Display(), sContext->mConfig,
|
||||
window.NativeWindow(), 0);
|
||||
}
|
||||
|
||||
static bool UnmakeCurrent(RefPtr<GLContextEGL>& gl) {
|
||||
@ -122,9 +125,9 @@ class SharedGL final {
|
||||
if (!gl->IsCurrent()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return gl::GLLibraryEGL::Get()->fMakeCurrent(
|
||||
EGL_DISPLAY(), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
const auto& egl = *(gl->mEgl);
|
||||
return egl.fMakeCurrent(egl.Display(), EGL_NO_SURFACE, EGL_NO_SURFACE,
|
||||
EGL_NO_CONTEXT);
|
||||
}
|
||||
|
||||
static Mutex sMutex;
|
||||
|
@ -11,7 +11,8 @@ namespace mozilla {
|
||||
namespace gl {
|
||||
|
||||
bool DoesEGLContextSupportSharingWithEGLImage(GLContext* gl) {
|
||||
auto* egl = gl::GLLibraryEGL::Get();
|
||||
const auto& gle = GLContextEGL::Cast(gl);
|
||||
const auto& egl = gle->mEgl;
|
||||
|
||||
return egl->HasKHRImageBase() && egl->HasKHRImageTexture2D() &&
|
||||
gl->IsExtensionSupported(GLContext::OES_EGL_image);
|
||||
@ -20,12 +21,11 @@ bool DoesEGLContextSupportSharingWithEGLImage(GLContext* gl) {
|
||||
EGLImage CreateEGLImage(GLContext* gl, GLuint tex) {
|
||||
MOZ_ASSERT(DoesEGLContextSupportSharingWithEGLImage(gl));
|
||||
|
||||
auto* egl = gl::GLLibraryEGL::Get();
|
||||
|
||||
const auto& gle = GLContextEGL::Cast(gl);
|
||||
const auto& egl = gle->mEgl;
|
||||
EGLClientBuffer clientBuffer = (EGLClientBuffer)((uint64_t)tex);
|
||||
EGLContext eglContext = GLContextEGL::Cast(gl)->mContext;
|
||||
EGLImage image =
|
||||
egl->fCreateImage(EGL_DISPLAY(), eglContext, LOCAL_EGL_GL_TEXTURE_2D,
|
||||
egl->fCreateImage(egl->Display(), gle->mContext, LOCAL_EGL_GL_TEXTURE_2D,
|
||||
clientBuffer, nullptr);
|
||||
return image;
|
||||
}
|
||||
@ -37,13 +37,12 @@ EGLImage CreateEGLImage(GLContext* gl, GLuint tex) {
|
||||
EGLImageWrapper* EGLImageWrapper::Create(GLContext* gl, GLuint tex) {
|
||||
MOZ_ASSERT(DoesEGLContextSupportSharingWithEGLImage(gl));
|
||||
|
||||
auto* egl = gl::GLLibraryEGL::Get();
|
||||
|
||||
EGLDisplay display = EGL_DISPLAY();
|
||||
EGLContext eglContext = GLContextEGL::Cast(gl)->mContext;
|
||||
const auto& gle = GLContextEGL::Cast(gl);
|
||||
const auto& egl = gle->mEgl;
|
||||
const auto& display = egl->Display();
|
||||
EGLClientBuffer clientBuffer = (EGLClientBuffer)((uint64_t)tex);
|
||||
EGLImage image = egl->fCreateImage(
|
||||
display, eglContext, LOCAL_EGL_GL_TEXTURE_2D, clientBuffer, nullptr);
|
||||
display, gle->mContext, LOCAL_EGL_GL_TEXTURE_2D, clientBuffer, nullptr);
|
||||
if (!image) {
|
||||
#ifdef DEBUG
|
||||
printf_stderr("Could not create EGL images: ERROR (0x%04x)\n",
|
||||
|
@ -1083,23 +1083,23 @@ void GLBlitHelper::DrawBlitTextureToFramebuffer(const GLuint srcTex,
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void GLBlitHelper::BlitFramebuffer(const gfx::IntSize& srcSize,
|
||||
const gfx::IntSize& destSize,
|
||||
void GLBlitHelper::BlitFramebuffer(const gfx::IntRect& srcRect,
|
||||
const gfx::IntRect& destRect,
|
||||
GLuint filter) const {
|
||||
MOZ_ASSERT(mGL->IsSupported(GLFeature::framebuffer_blit));
|
||||
|
||||
const ScopedGLState scissor(mGL, LOCAL_GL_SCISSOR_TEST, false);
|
||||
mGL->fBlitFramebuffer(0, 0, srcSize.width, srcSize.height, 0, 0,
|
||||
destSize.width, destSize.height,
|
||||
LOCAL_GL_COLOR_BUFFER_BIT, filter);
|
||||
mGL->fBlitFramebuffer(srcRect.x, srcRect.y, srcRect.XMost(), srcRect.YMost(),
|
||||
destRect.x, destRect.y, destRect.XMost(),
|
||||
destRect.YMost(), LOCAL_GL_COLOR_BUFFER_BIT, filter);
|
||||
}
|
||||
|
||||
// --
|
||||
|
||||
void GLBlitHelper::BlitFramebufferToFramebuffer(const GLuint srcFB,
|
||||
const GLuint destFB,
|
||||
const gfx::IntSize& srcSize,
|
||||
const gfx::IntSize& destSize,
|
||||
const gfx::IntRect& srcRect,
|
||||
const gfx::IntRect& destRect,
|
||||
GLuint filter) const {
|
||||
MOZ_ASSERT(mGL->IsSupported(GLFeature::framebuffer_blit));
|
||||
MOZ_GL_ASSERT(mGL, !srcFB || mGL->fIsFramebuffer(srcFB));
|
||||
@ -1109,7 +1109,7 @@ void GLBlitHelper::BlitFramebufferToFramebuffer(const GLuint srcFB,
|
||||
mGL->fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER, srcFB);
|
||||
mGL->fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER, destFB);
|
||||
|
||||
BlitFramebuffer(srcSize, destSize, filter);
|
||||
BlitFramebuffer(srcRect, destRect, filter);
|
||||
}
|
||||
|
||||
void GLBlitHelper::BlitTextureToFramebuffer(GLuint srcTex,
|
||||
@ -1122,7 +1122,7 @@ void GLBlitHelper::BlitTextureToFramebuffer(GLuint srcTex,
|
||||
const ScopedFramebufferForTexture srcWrapper(mGL, srcTex, srcTarget);
|
||||
const ScopedBindFramebuffer bindFB(mGL);
|
||||
mGL->fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER, srcWrapper.FB());
|
||||
BlitFramebuffer(srcSize, destSize);
|
||||
BlitFramebuffer(gfx::IntRect({}, srcSize), gfx::IntRect({}, destSize));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1139,7 +1139,7 @@ void GLBlitHelper::BlitFramebufferToTexture(GLuint destTex,
|
||||
const ScopedFramebufferForTexture destWrapper(mGL, destTex, destTarget);
|
||||
const ScopedBindFramebuffer bindFB(mGL);
|
||||
mGL->fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER, destWrapper.FB());
|
||||
BlitFramebuffer(srcSize, destSize);
|
||||
BlitFramebuffer(gfx::IntRect({}, srcSize), gfx::IntRect({}, destSize));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -156,12 +156,12 @@ class GLBlitHelper final {
|
||||
public:
|
||||
~GLBlitHelper();
|
||||
|
||||
void BlitFramebuffer(const gfx::IntSize& srcSize,
|
||||
const gfx::IntSize& destSize,
|
||||
void BlitFramebuffer(const gfx::IntRect& srcRect,
|
||||
const gfx::IntRect& destRect,
|
||||
GLuint filter = LOCAL_GL_NEAREST) const;
|
||||
void BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB,
|
||||
const gfx::IntSize& srcSize,
|
||||
const gfx::IntSize& destSize,
|
||||
const gfx::IntRect& srcRect,
|
||||
const gfx::IntRect& destRect,
|
||||
GLuint filter = LOCAL_GL_NEAREST) const;
|
||||
void BlitFramebufferToTexture(GLuint destTex, const gfx::IntSize& srcSize,
|
||||
const gfx::IntSize& destSize,
|
||||
|
@ -18,9 +18,9 @@
|
||||
namespace mozilla {
|
||||
namespace gl {
|
||||
|
||||
static EGLStreamKHR StreamFromD3DTexture(ID3D11Texture2D* const texD3D,
|
||||
static EGLStreamKHR StreamFromD3DTexture(GLLibraryEGL* const egl,
|
||||
ID3D11Texture2D* const texD3D,
|
||||
const EGLAttrib* const postAttribs) {
|
||||
auto* egl = gl::GLLibraryEGL::Get();
|
||||
if (!egl->IsExtensionSupported(
|
||||
GLLibraryEGL::NV_stream_consumer_gltexture_yuv) ||
|
||||
!egl->IsExtensionSupported(
|
||||
@ -83,7 +83,8 @@ class BindAnglePlanes final {
|
||||
MOZ_RELEASE_ASSERT(numPlanes >= 1 && numPlanes <= 3);
|
||||
|
||||
const auto& gl = mParent.mGL;
|
||||
auto* egl = gl::GLLibraryEGL::Get();
|
||||
const auto& gle = GLContextEGL::Cast(gl);
|
||||
const auto& egl = gle->mEgl;
|
||||
const auto& display = egl->Display();
|
||||
|
||||
gl->fGenTextures(numPlanes, mTempTexs);
|
||||
@ -95,7 +96,7 @@ class BindAnglePlanes final {
|
||||
if (postAttribsList) {
|
||||
postAttribs = postAttribsList[i];
|
||||
}
|
||||
mStreams[i] = StreamFromD3DTexture(texD3DList[i], postAttribs);
|
||||
mStreams[i] = StreamFromD3DTexture(egl, texD3DList[i], postAttribs);
|
||||
mSuccess &= bool(mStreams[i]);
|
||||
}
|
||||
|
||||
@ -119,7 +120,8 @@ class BindAnglePlanes final {
|
||||
|
||||
~BindAnglePlanes() {
|
||||
const auto& gl = mParent.mGL;
|
||||
auto* egl = gl::GLLibraryEGL::Get();
|
||||
const auto& gle = GLContextEGL::Cast(gl);
|
||||
const auto& egl = gle->mEgl;
|
||||
const auto& display = egl->Display();
|
||||
|
||||
if (mSuccess) {
|
||||
@ -148,7 +150,8 @@ ID3D11Device* GLBlitHelper::GetD3D11() const {
|
||||
|
||||
if (!mGL->IsANGLE()) return nullptr;
|
||||
|
||||
auto* egl = gl::GLLibraryEGL::Get();
|
||||
const auto& gle = GLContextEGL::Cast(mGL);
|
||||
const auto& egl = gle->mEgl;
|
||||
EGLDeviceEXT deviceEGL = 0;
|
||||
MOZ_ALWAYS_TRUE(egl->fQueryDisplayAttribEXT(
|
||||
egl->Display(), LOCAL_EGL_DEVICE_EXT, (EGLAttrib*)&deviceEGL));
|
||||
|
@ -15,6 +15,8 @@
|
||||
typedef void NSOpenGLContext;
|
||||
#endif
|
||||
|
||||
class nsIWidget;
|
||||
|
||||
namespace mozilla {
|
||||
namespace gl {
|
||||
|
||||
|
@ -20,12 +20,13 @@ class GLContextEGL : public GLContext {
|
||||
friend class TextureImageEGL;
|
||||
|
||||
static already_AddRefed<GLContextEGL> CreateGLContext(
|
||||
CreateContextFlags flags, const SurfaceCaps& caps, bool isOffscreen,
|
||||
EGLConfig config, EGLSurface surface, nsACString* const out_failureId);
|
||||
GLLibraryEGL*, CreateContextFlags flags, const SurfaceCaps& caps,
|
||||
bool isOffscreen, EGLConfig config, EGLSurface surface,
|
||||
nsACString* const out_failureId);
|
||||
|
||||
public:
|
||||
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GLContextEGL, override)
|
||||
GLContextEGL(CreateContextFlags flags, const SurfaceCaps& caps,
|
||||
GLContextEGL(GLLibraryEGL*, CreateContextFlags flags, const SurfaceCaps& caps,
|
||||
bool isOffscreen, EGLConfig config, EGLSurface surface,
|
||||
EGLContext context);
|
||||
|
||||
@ -46,11 +47,8 @@ class GLContextEGL : public GLContext {
|
||||
|
||||
void SetIsDoubleBuffered(bool aIsDB) { mIsDoubleBuffered = aIsDB; }
|
||||
|
||||
virtual bool IsANGLE() const override {
|
||||
return GLLibraryEGL::Get()->IsANGLE();
|
||||
}
|
||||
|
||||
virtual bool IsWARP() const override { return GLLibraryEGL::Get()->IsWARP(); }
|
||||
virtual bool IsANGLE() const override { return mEgl->IsANGLE(); }
|
||||
virtual bool IsWARP() const override { return mEgl->IsWARP(); }
|
||||
|
||||
virtual bool BindTexImage() override;
|
||||
|
||||
@ -79,8 +77,6 @@ class GLContextEGL : public GLContext {
|
||||
|
||||
EGLSurface GetEGLSurface() const { return mSurface; }
|
||||
|
||||
EGLDisplay GetEGLDisplay() const { return GLLibraryEGL::Get()->Display(); }
|
||||
|
||||
bool BindTex2DOffscreen(GLContext* aOffscreen);
|
||||
void UnbindTex2DOffscreen(GLContext* aOffscreen);
|
||||
void BindOffscreenFramebuffer();
|
||||
@ -102,17 +98,14 @@ class GLContextEGL : public GLContext {
|
||||
virtual void OnMarkDestroyed() override;
|
||||
|
||||
public:
|
||||
const EGLConfig mConfig;
|
||||
|
||||
protected:
|
||||
const RefPtr<GLLibraryEGL> mEgl;
|
||||
EGLSurface mSurface;
|
||||
const EGLSurface mFallbackSurface;
|
||||
|
||||
public:
|
||||
const EGLConfig mConfig;
|
||||
const EGLContext mContext;
|
||||
|
||||
protected:
|
||||
EGLSurface mSurface;
|
||||
const EGLSurface mFallbackSurface;
|
||||
|
||||
EGLSurface mSurfaceOverride = EGL_NO_SURFACE;
|
||||
RefPtr<gfxASurface> mThebesSurface;
|
||||
bool mBound = false;
|
||||
@ -124,9 +117,10 @@ class GLContextEGL : public GLContext {
|
||||
bool mOwnsContext = true;
|
||||
|
||||
static EGLSurface CreatePBufferSurfaceTryingPowerOfTwo(
|
||||
EGLConfig config, EGLenum bindToTextureFormat, gfx::IntSize& pbsize);
|
||||
GLLibraryEGL*, EGLConfig config, EGLenum bindToTextureFormat,
|
||||
gfx::IntSize& pbsize);
|
||||
#if defined(MOZ_WAYLAND)
|
||||
static EGLSurface CreateWaylandBufferSurface(EGLConfig config,
|
||||
static EGLSurface CreateWaylandBufferSurface(GLLibraryEGL*, EGLConfig config,
|
||||
gfx::IntSize& pbsize);
|
||||
#endif
|
||||
#if defined(MOZ_WIDGET_ANDROID)
|
||||
@ -135,7 +129,7 @@ class GLContextEGL : public GLContext {
|
||||
#endif // defined(MOZ_WIDGET_ANDROID)
|
||||
};
|
||||
|
||||
bool CreateConfig(EGLConfig* config, int32_t depth
|
||||
bool CreateConfig(GLLibraryEGL*, EGLConfig* config, int32_t depth
|
||||
#ifdef MOZ_BUILD_WEBRENDER
|
||||
,
|
||||
bool enableDepthBuffer
|
||||
|
@ -13,9 +13,10 @@
|
||||
#include "mozilla/StaticPrefs_layout.h"
|
||||
#include "prenv.h"
|
||||
#include "GeckoProfiler.h"
|
||||
#include "mozilla/gfx/MacIOSurface.h"
|
||||
#include "MozFramebuffer.h"
|
||||
#include "mozilla/layers/CompositorOptions.h"
|
||||
#include "mozilla/widget/CompositorWidget.h"
|
||||
#include "ScopedGLHelpers.h"
|
||||
|
||||
#include <OpenGL/OpenGL.h>
|
||||
|
||||
@ -115,6 +116,7 @@ bool GLContextCGL::SwapBuffers() {
|
||||
AUTO_PROFILER_LABEL("GLContextCGL::SwapBuffers", GRAPHICS);
|
||||
|
||||
[mContext flushBuffer];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -198,11 +200,15 @@ already_AddRefed<GLContext> GLContextProviderCGL::CreateForWindow(nsIWidget* aWi
|
||||
#endif
|
||||
|
||||
const NSOpenGLPixelFormatAttribute* attribs;
|
||||
SurfaceCaps caps = SurfaceCaps::ForRGBA();
|
||||
if (sCGLLibrary.UseDoubleBufferedWindows()) {
|
||||
#ifdef MOZ_BUILD_WEBRENDER
|
||||
if (aWebRender) {
|
||||
attribs =
|
||||
aForceAccelerated ? kAttribs_doubleBuffered_accel_webrender : kAttribs_doubleBuffered;
|
||||
MOZ_RELEASE_ASSERT(aForceAccelerated,
|
||||
"At the moment, aForceAccelerated is always true if aWebRender is true. "
|
||||
"If this changes, please update the code here.");
|
||||
attribs = kAttribs_doubleBuffered_accel_webrender;
|
||||
caps.depth = true;
|
||||
} else {
|
||||
#endif
|
||||
attribs = aForceAccelerated ? kAttribs_doubleBuffered_accel : kAttribs_doubleBuffered;
|
||||
@ -220,8 +226,7 @@ already_AddRefed<GLContext> GLContextProviderCGL::CreateForWindow(nsIWidget* aWi
|
||||
GLint opaque = StaticPrefs::gfx_compositor_glcontext_opaque();
|
||||
[context setValues:&opaque forParameter:NSOpenGLCPSurfaceOpacity];
|
||||
|
||||
RefPtr<GLContextCGL> glContext =
|
||||
new GLContextCGL(CreateContextFlags::NONE, SurfaceCaps::ForRGBA(), context, false);
|
||||
RefPtr<GLContextCGL> glContext = new GLContextCGL(CreateContextFlags::NONE, caps, context, false);
|
||||
|
||||
if (!glContext->Init()) {
|
||||
glContext = nullptr;
|
||||
|
@ -130,7 +130,7 @@ void DeleteWaylandGLSurface(EGLSurface surface) {
|
||||
(_array).AppendElement(_k); \
|
||||
} while (0)
|
||||
|
||||
static bool CreateConfig(EGLConfig* aConfig
|
||||
static bool CreateConfig(GLLibraryEGL*, EGLConfig* aConfig
|
||||
#ifdef MOZ_BUILD_WEBRENDER
|
||||
,
|
||||
bool aEnableDepthBuffer
|
||||
@ -166,29 +166,27 @@ static bool is_power_of_two(int v) {
|
||||
return (v & (v - 1)) == 0;
|
||||
}
|
||||
|
||||
static void DestroySurface(EGLSurface oldSurface) {
|
||||
auto* egl = gl::GLLibraryEGL::Get();
|
||||
|
||||
static void DestroySurface(GLLibraryEGL* const egl,
|
||||
const EGLSurface oldSurface) {
|
||||
if (oldSurface != EGL_NO_SURFACE) {
|
||||
// TODO: This breaks TLS MakeCurrent caching.
|
||||
egl->fMakeCurrent(EGL_DISPLAY(), EGL_NO_SURFACE, EGL_NO_SURFACE,
|
||||
egl->fMakeCurrent(egl->Display(), EGL_NO_SURFACE, EGL_NO_SURFACE,
|
||||
EGL_NO_CONTEXT);
|
||||
egl->fDestroySurface(EGL_DISPLAY(), oldSurface);
|
||||
egl->fDestroySurface(egl->Display(), oldSurface);
|
||||
#if defined(MOZ_WAYLAND)
|
||||
DeleteWaylandGLSurface(oldSurface);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static EGLSurface CreateFallbackSurface(const EGLConfig& config) {
|
||||
static EGLSurface CreateFallbackSurface(GLLibraryEGL* const egl,
|
||||
const EGLConfig& config) {
|
||||
nsCString discardFailureId;
|
||||
if (!GLLibraryEGL::EnsureInitialized(false, &discardFailureId)) {
|
||||
gfxCriticalNote << "Failed to load EGL library 3!";
|
||||
return EGL_NO_SURFACE;
|
||||
}
|
||||
|
||||
auto* egl = gl::GLLibraryEGL::Get();
|
||||
|
||||
if (egl->IsExtensionSupported(GLLibraryEGL::KHR_surfaceless_context)) {
|
||||
// We don't need a PBuffer surface in this case
|
||||
return EGL_NO_SURFACE;
|
||||
@ -205,7 +203,7 @@ static EGLSurface CreateFallbackSurface(const EGLConfig& config) {
|
||||
}
|
||||
|
||||
EGLSurface surface =
|
||||
egl->fCreatePbufferSurface(EGL_DISPLAY(), config, pbattrs.data());
|
||||
egl->fCreatePbufferSurface(egl->Display(), config, pbattrs.data());
|
||||
if (!surface) {
|
||||
MOZ_CRASH("Failed to create fallback EGLSurface");
|
||||
}
|
||||
@ -213,10 +211,10 @@ static EGLSurface CreateFallbackSurface(const EGLConfig& config) {
|
||||
return surface;
|
||||
}
|
||||
|
||||
static EGLSurface CreateSurfaceFromNativeWindow(EGLNativeWindowType window,
|
||||
const EGLConfig& config) {
|
||||
static EGLSurface CreateSurfaceFromNativeWindow(
|
||||
GLLibraryEGL* const egl, const EGLNativeWindowType window,
|
||||
const EGLConfig config) {
|
||||
MOZ_ASSERT(window);
|
||||
auto* egl = gl::GLLibraryEGL::Get();
|
||||
EGLSurface newSurface = EGL_NO_SURFACE;
|
||||
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
@ -227,7 +225,7 @@ static EGLSurface CreateSurfaceFromNativeWindow(EGLNativeWindowType window,
|
||||
config, nativeWindow, 0);
|
||||
ANativeWindow_release(nativeWindow);
|
||||
#else
|
||||
newSurface = egl->fCreateWindowSurface(EGL_DISPLAY(), config, window, 0);
|
||||
newSurface = egl->fCreateWindowSurface(egl->Display(), config, window, 0);
|
||||
#endif
|
||||
return newSurface;
|
||||
}
|
||||
@ -274,13 +272,13 @@ already_AddRefed<GLContext> GLContextEGLFactory::Create(
|
||||
// formart
|
||||
const int bpp = 32;
|
||||
const bool withDepth = true;
|
||||
if (!CreateConfig(&config, bpp, withDepth)) {
|
||||
if (!CreateConfig(egl, &config, bpp, withDepth)) {
|
||||
gfxCriticalNote << "Failed to create EGLConfig for WebRender ANGLE!";
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
#endif
|
||||
if (!CreateConfig(&config
|
||||
if (!CreateConfig(egl, &config
|
||||
#ifdef MOZ_BUILD_WEBRENDER
|
||||
,
|
||||
aWebRender
|
||||
@ -295,7 +293,7 @@ already_AddRefed<GLContext> GLContextEGLFactory::Create(
|
||||
|
||||
EGLSurface surface = EGL_NO_SURFACE;
|
||||
if (aWindow) {
|
||||
surface = mozilla::gl::CreateSurfaceFromNativeWindow(aWindow, config);
|
||||
surface = mozilla::gl::CreateSurfaceFromNativeWindow(egl, aWindow, config);
|
||||
}
|
||||
|
||||
CreateContextFlags flags = CreateContextFlags::NONE;
|
||||
@ -306,11 +304,11 @@ already_AddRefed<GLContext> GLContextEGLFactory::Create(
|
||||
#endif
|
||||
SurfaceCaps caps = SurfaceCaps::Any();
|
||||
RefPtr<GLContextEGL> gl = GLContextEGL::CreateGLContext(
|
||||
flags, caps, false, config, surface, &discardFailureId);
|
||||
egl, flags, caps, false, config, surface, &discardFailureId);
|
||||
if (!gl) {
|
||||
const auto err = egl->fGetError();
|
||||
gfxCriticalNote << "Failed to create EGLContext!: " << gfx::hexa(err);
|
||||
mozilla::gl::DestroySurface(surface);
|
||||
mozilla::gl::DestroySurface(egl, surface);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -321,13 +319,13 @@ already_AddRefed<GLContext> GLContextEGLFactory::Create(
|
||||
if (surface != EGL_NO_SURFACE &&
|
||||
!GDK_IS_X11_DISPLAY(gdk_display_get_default())) {
|
||||
// Make eglSwapBuffers() non-blocking on wayland
|
||||
egl->fSwapInterval(EGL_DISPLAY(), 0);
|
||||
egl->fSwapInterval(egl->Display(), 0);
|
||||
}
|
||||
#endif
|
||||
#ifdef MOZ_BUILD_WEBRENDER
|
||||
if (aWebRender && egl->IsANGLE()) {
|
||||
MOZ_ASSERT(doubleBuffered);
|
||||
egl->fSwapInterval(EGL_DISPLAY(), 0);
|
||||
egl->fSwapInterval(egl->Display(), 0);
|
||||
}
|
||||
#endif
|
||||
return gl.forget();
|
||||
@ -351,22 +349,24 @@ EGLSurface GLContextEGL::CreateEGLSurfaceForCompositorWidget(
|
||||
return EGL_NO_SURFACE;
|
||||
}
|
||||
|
||||
return mozilla::gl::CreateSurfaceFromNativeWindow(window, aConfig);
|
||||
const auto& egl = GLLibraryEGL::Get();
|
||||
return mozilla::gl::CreateSurfaceFromNativeWindow(egl, window, aConfig);
|
||||
}
|
||||
#endif
|
||||
|
||||
GLContextEGL::GLContextEGL(CreateContextFlags flags, const SurfaceCaps& caps,
|
||||
bool isOffscreen, EGLConfig config,
|
||||
EGLSurface surface, EGLContext context)
|
||||
GLContextEGL::GLContextEGL(GLLibraryEGL* const egl, CreateContextFlags flags,
|
||||
const SurfaceCaps& caps, bool isOffscreen,
|
||||
EGLConfig config, EGLSurface surface,
|
||||
EGLContext context)
|
||||
: GLContext(flags, caps, nullptr, isOffscreen, false),
|
||||
mEgl(egl),
|
||||
mConfig(config),
|
||||
mEgl(gl::GLLibraryEGL::Get()),
|
||||
mContext(context),
|
||||
mSurface(surface),
|
||||
mFallbackSurface(CreateFallbackSurface(config)),
|
||||
mContext(context) {
|
||||
mFallbackSurface(CreateFallbackSurface(mEgl, mConfig)) {
|
||||
#ifdef DEBUG
|
||||
printf_stderr("Initializing context %p surface %p on display %p\n", mContext,
|
||||
mSurface, EGL_DISPLAY());
|
||||
mSurface, mEgl->Display());
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -386,13 +386,13 @@ GLContextEGL::~GLContextEGL() {
|
||||
|
||||
#ifdef DEBUG
|
||||
printf_stderr("Destroying context %p surface %p on display %p\n", mContext,
|
||||
mSurface, EGL_DISPLAY());
|
||||
mSurface, mEgl->Display());
|
||||
#endif
|
||||
|
||||
mEgl->fDestroyContext(EGL_DISPLAY(), mContext);
|
||||
mEgl->fDestroyContext(mEgl->Display(), mContext);
|
||||
|
||||
mozilla::gl::DestroySurface(mSurface);
|
||||
mozilla::gl::DestroySurface(mFallbackSurface);
|
||||
mozilla::gl::DestroySurface(mEgl, mSurface);
|
||||
mozilla::gl::DestroySurface(mEgl, mFallbackSurface);
|
||||
}
|
||||
|
||||
bool GLContextEGL::Init() {
|
||||
@ -417,8 +417,8 @@ bool GLContextEGL::BindTexImage() {
|
||||
|
||||
if (mBound && !ReleaseTexImage()) return false;
|
||||
|
||||
EGLBoolean success = mEgl->fBindTexImage(EGL_DISPLAY(), (EGLSurface)mSurface,
|
||||
LOCAL_EGL_BACK_BUFFER);
|
||||
EGLBoolean success = mEgl->fBindTexImage(
|
||||
mEgl->Display(), (EGLSurface)mSurface, LOCAL_EGL_BACK_BUFFER);
|
||||
if (success == LOCAL_EGL_FALSE) return false;
|
||||
|
||||
mBound = true;
|
||||
@ -431,7 +431,7 @@ bool GLContextEGL::ReleaseTexImage() {
|
||||
if (!mSurface) return false;
|
||||
|
||||
EGLBoolean success;
|
||||
success = mEgl->fReleaseTexImage(EGL_DISPLAY(), (EGLSurface)mSurface,
|
||||
success = mEgl->fReleaseTexImage(mEgl->Display(), (EGLSurface)mSurface,
|
||||
LOCAL_EGL_BACK_BUFFER);
|
||||
if (success == LOCAL_EGL_FALSE) return false;
|
||||
|
||||
@ -462,7 +462,7 @@ bool GLContextEGL::MakeCurrentImpl() const {
|
||||
}
|
||||
|
||||
const bool succeeded =
|
||||
mEgl->fMakeCurrent(EGL_DISPLAY(), surface, surface, mContext);
|
||||
mEgl->fMakeCurrent(mEgl->Display(), surface, surface, mContext);
|
||||
if (!succeeded) {
|
||||
const auto eglError = mEgl->fGetError();
|
||||
if (eglError == LOCAL_EGL_CONTEXT_LOST) {
|
||||
@ -496,7 +496,7 @@ bool GLContextEGL::RenewSurface(CompositorWidget* aWidget) {
|
||||
GET_NATIVE_WINDOW_FROM_COMPOSITOR_WIDGET(aWidget);
|
||||
if (nativeWindow) {
|
||||
mSurface =
|
||||
mozilla::gl::CreateSurfaceFromNativeWindow(nativeWindow, mConfig);
|
||||
mozilla::gl::CreateSurfaceFromNativeWindow(mEgl, nativeWindow, mConfig);
|
||||
if (!mSurface) {
|
||||
NS_WARNING("Failed to create EGLSurface from native window");
|
||||
return false;
|
||||
@ -506,9 +506,8 @@ bool GLContextEGL::RenewSurface(CompositorWidget* aWidget) {
|
||||
MOZ_ASSERT(ok);
|
||||
#if defined(MOZ_WAYLAND)
|
||||
if (mSurface && !GDK_IS_X11_DISPLAY(gdk_display_get_default())) {
|
||||
const auto* egl = gl::GLLibraryEGL::Get();
|
||||
// Make eglSwapBuffers() non-blocking on wayland
|
||||
egl->fSwapInterval(EGL_DISPLAY(), 0);
|
||||
mEgl->fSwapInterval(mEgl->Display(), 0);
|
||||
}
|
||||
#endif
|
||||
return ok;
|
||||
@ -516,7 +515,7 @@ bool GLContextEGL::RenewSurface(CompositorWidget* aWidget) {
|
||||
|
||||
void GLContextEGL::ReleaseSurface() {
|
||||
if (mOwnsContext) {
|
||||
mozilla::gl::DestroySurface(mSurface);
|
||||
mozilla::gl::DestroySurface(mEgl, mSurface);
|
||||
}
|
||||
if (mSurface == mSurfaceOverride) {
|
||||
mSurfaceOverride = EGL_NO_SURFACE;
|
||||
@ -532,7 +531,7 @@ bool GLContextEGL::SwapBuffers() {
|
||||
EGLSurface surface =
|
||||
mSurfaceOverride != EGL_NO_SURFACE ? mSurfaceOverride : mSurface;
|
||||
if (surface) {
|
||||
return mEgl->fSwapBuffers(EGL_DISPLAY(), surface);
|
||||
return mEgl->fSwapBuffers(mEgl->Display(), surface);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
@ -540,15 +539,16 @@ bool GLContextEGL::SwapBuffers() {
|
||||
|
||||
void GLContextEGL::GetWSIInfo(nsCString* const out) const {
|
||||
out->AppendLiteral("EGL_VENDOR: ");
|
||||
out->Append((const char*)mEgl->fQueryString(EGL_DISPLAY(), LOCAL_EGL_VENDOR));
|
||||
out->Append(
|
||||
(const char*)mEgl->fQueryString(mEgl->Display(), LOCAL_EGL_VENDOR));
|
||||
|
||||
out->AppendLiteral("\nEGL_VERSION: ");
|
||||
out->Append(
|
||||
(const char*)mEgl->fQueryString(EGL_DISPLAY(), LOCAL_EGL_VERSION));
|
||||
(const char*)mEgl->fQueryString(mEgl->Display(), LOCAL_EGL_VERSION));
|
||||
|
||||
out->AppendLiteral("\nEGL_EXTENSIONS: ");
|
||||
out->Append(
|
||||
(const char*)mEgl->fQueryString(EGL_DISPLAY(), LOCAL_EGL_EXTENSIONS));
|
||||
(const char*)mEgl->fQueryString(mEgl->Display(), LOCAL_EGL_EXTENSIONS));
|
||||
|
||||
#ifndef ANDROID // This query will crash some old android.
|
||||
out->AppendLiteral("\nEGL_EXTENSIONS(nullptr): ");
|
||||
@ -563,10 +563,9 @@ void GLContextEGL::HoldSurface(gfxASurface* aSurf) { mThebesSurface = aSurf; }
|
||||
#define LOCAL_EGL_CONTEXT_PROVOKING_VERTEX_DONT_CARE_MOZ 0x6000
|
||||
|
||||
already_AddRefed<GLContextEGL> GLContextEGL::CreateGLContext(
|
||||
CreateContextFlags flags, const SurfaceCaps& caps, bool isOffscreen,
|
||||
EGLConfig config, EGLSurface surface, nsACString* const out_failureId) {
|
||||
auto* egl = gl::GLLibraryEGL::Get();
|
||||
|
||||
GLLibraryEGL* const egl, CreateContextFlags flags, const SurfaceCaps& caps,
|
||||
bool isOffscreen, EGLConfig config, EGLSurface surface,
|
||||
nsACString* const out_failureId) {
|
||||
if (egl->fBindAPI(LOCAL_EGL_OPENGL_ES_API) == LOCAL_EGL_FALSE) {
|
||||
*out_failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_EGL_ES");
|
||||
NS_WARNING("Failed to bind API to GLES!");
|
||||
@ -635,7 +634,7 @@ already_AddRefed<GLContextEGL> GLContextEGL::CreateGLContext(
|
||||
terminated_attribs.push_back(cur);
|
||||
}
|
||||
|
||||
return egl->fCreateContext(EGL_DISPLAY(), config, EGL_NO_CONTEXT,
|
||||
return egl->fCreateContext(egl->Display(), config, EGL_NO_CONTEXT,
|
||||
terminated_attribs.data());
|
||||
};
|
||||
|
||||
@ -663,7 +662,7 @@ already_AddRefed<GLContextEGL> GLContextEGL::CreateGLContext(
|
||||
MOZ_ASSERT(context);
|
||||
|
||||
RefPtr<GLContextEGL> glContext =
|
||||
new GLContextEGL(flags, caps, isOffscreen, config, surface, context);
|
||||
new GLContextEGL(egl, flags, caps, isOffscreen, config, surface, context);
|
||||
if (!glContext->Init()) {
|
||||
*out_failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_EGL_INIT");
|
||||
return nullptr;
|
||||
@ -672,8 +671,9 @@ already_AddRefed<GLContextEGL> GLContextEGL::CreateGLContext(
|
||||
return glContext.forget();
|
||||
}
|
||||
|
||||
// static
|
||||
EGLSurface GLContextEGL::CreatePBufferSurfaceTryingPowerOfTwo(
|
||||
EGLConfig config, EGLenum bindToTextureFormat,
|
||||
GLLibraryEGL* const egl, EGLConfig config, EGLenum bindToTextureFormat,
|
||||
mozilla::gfx::IntSize& pbsize) {
|
||||
nsTArray<EGLint> pbattrs(16);
|
||||
EGLSurface surface = nullptr;
|
||||
@ -697,9 +697,7 @@ TRY_AGAIN_POWER_OF_TWO:
|
||||
pbattrs.AppendElement(cur);
|
||||
}
|
||||
|
||||
auto* egl = gl::GLLibraryEGL::Get();
|
||||
|
||||
surface = egl->fCreatePbufferSurface(EGL_DISPLAY(), config, &pbattrs[0]);
|
||||
surface = egl->fCreatePbufferSurface(egl->Display(), config, &pbattrs[0]);
|
||||
if (!surface) {
|
||||
if (!is_power_of_two(pbsize.width) || !is_power_of_two(pbsize.height)) {
|
||||
if (!is_power_of_two(pbsize.width))
|
||||
@ -728,8 +726,9 @@ WaylandGLSurface::~WaylandGLSurface() {
|
||||
wl_surface_destroy(mWaylandSurface);
|
||||
}
|
||||
|
||||
// static
|
||||
EGLSurface GLContextEGL::CreateWaylandBufferSurface(
|
||||
EGLConfig config, mozilla::gfx::IntSize& pbsize) {
|
||||
GLLibraryEGL* const egl, EGLConfig config, mozilla::gfx::IntSize& pbsize) {
|
||||
// Available as of GTK 3.8+
|
||||
static auto sGdkWaylandDisplayGetWlCompositor =
|
||||
(wl_compositor * (*)(GdkDisplay*))
|
||||
@ -743,9 +742,8 @@ EGLSurface GLContextEGL::CreateWaylandBufferSurface(
|
||||
struct wl_egl_window* eglwindow =
|
||||
wl_egl_window_create(wlsurface, pbsize.width, pbsize.height);
|
||||
|
||||
auto* egl = gl::GLLibraryEGL::Get();
|
||||
EGLSurface surface =
|
||||
egl->fCreateWindowSurface(EGL_DISPLAY(), config, eglwindow, 0);
|
||||
egl->fCreateWindowSurface(egl->Display(), config, eglwindow, 0);
|
||||
|
||||
if (surface) {
|
||||
WaylandGLSurface* waylandData = new WaylandGLSurface(wlsurface, eglwindow);
|
||||
@ -811,7 +809,7 @@ static const EGLint kEGLConfigAttribsRGBA32[] = {
|
||||
8,
|
||||
EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS};
|
||||
|
||||
bool CreateConfig(EGLConfig* aConfig, int32_t depth
|
||||
bool CreateConfig(GLLibraryEGL* const egl, EGLConfig* aConfig, int32_t depth
|
||||
#ifdef MOZ_BUILD_WEBRENDER
|
||||
,
|
||||
bool aEnableDepthBuffer
|
||||
@ -836,9 +834,7 @@ bool CreateConfig(EGLConfig* aConfig, int32_t depth
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* egl = gl::GLLibraryEGL::Get();
|
||||
|
||||
if (!egl->fChooseConfig(EGL_DISPLAY(), attribs, configs, ncfg, &ncfg) ||
|
||||
if (!egl->fChooseConfig(egl->Display(), attribs, configs, ncfg, &ncfg) ||
|
||||
ncfg < 1) {
|
||||
return false;
|
||||
}
|
||||
@ -846,11 +842,12 @@ bool CreateConfig(EGLConfig* aConfig, int32_t depth
|
||||
for (int j = 0; j < ncfg; ++j) {
|
||||
EGLConfig config = configs[j];
|
||||
EGLint r, g, b, a;
|
||||
if (egl->fGetConfigAttrib(EGL_DISPLAY(), config, LOCAL_EGL_RED_SIZE, &r) &&
|
||||
egl->fGetConfigAttrib(EGL_DISPLAY(), config, LOCAL_EGL_GREEN_SIZE,
|
||||
if (egl->fGetConfigAttrib(egl->Display(), config, LOCAL_EGL_RED_SIZE, &r) &&
|
||||
egl->fGetConfigAttrib(egl->Display(), config, LOCAL_EGL_GREEN_SIZE,
|
||||
&g) &&
|
||||
egl->fGetConfigAttrib(EGL_DISPLAY(), config, LOCAL_EGL_BLUE_SIZE, &b) &&
|
||||
egl->fGetConfigAttrib(EGL_DISPLAY(), config, LOCAL_EGL_ALPHA_SIZE,
|
||||
egl->fGetConfigAttrib(egl->Display(), config, LOCAL_EGL_BLUE_SIZE,
|
||||
&b) &&
|
||||
egl->fGetConfigAttrib(egl->Display(), config, LOCAL_EGL_ALPHA_SIZE,
|
||||
&a) &&
|
||||
((depth == 16 && r == 5 && g == 6 && b == 5) ||
|
||||
(depth == 24 && r == 8 && g == 8 && b == 8) ||
|
||||
@ -858,7 +855,7 @@ bool CreateConfig(EGLConfig* aConfig, int32_t depth
|
||||
#ifdef MOZ_BUILD_WEBRENDER
|
||||
EGLint z;
|
||||
if (aEnableDepthBuffer) {
|
||||
if (!egl->fGetConfigAttrib(EGL_DISPLAY(), config, LOCAL_EGL_DEPTH_SIZE,
|
||||
if (!egl->fGetConfigAttrib(egl->Display(), config, LOCAL_EGL_DEPTH_SIZE,
|
||||
&z) ||
|
||||
z != 24) {
|
||||
continue;
|
||||
@ -877,14 +874,14 @@ bool CreateConfig(EGLConfig* aConfig, int32_t depth
|
||||
//
|
||||
// NB: It's entirely legal for the returned EGLConfig to be valid yet
|
||||
// have the value null.
|
||||
static bool CreateConfig(EGLConfig* aConfig
|
||||
static bool CreateConfig(GLLibraryEGL* const egl, EGLConfig* const aConfig
|
||||
#ifdef MOZ_BUILD_WEBRENDER
|
||||
,
|
||||
bool aEnableDepthBuffer
|
||||
#endif
|
||||
) {
|
||||
int32_t depth = gfxVars::ScreenDepth();
|
||||
if (!CreateConfig(aConfig, depth
|
||||
if (!CreateConfig(egl, aConfig, depth
|
||||
#ifdef MOZ_BUILD_WEBRENDER
|
||||
,
|
||||
aEnableDepthBuffer
|
||||
@ -894,7 +891,7 @@ static bool CreateConfig(EGLConfig* aConfig
|
||||
// Bug 736005
|
||||
// Android doesn't always support 16 bit so also try 24 bit
|
||||
if (depth == 16) {
|
||||
return CreateConfig(aConfig, 24
|
||||
return CreateConfig(egl, aConfig, 24
|
||||
# ifdef MOZ_BUILD_WEBRENDER
|
||||
,
|
||||
aEnableDepthBuffer
|
||||
@ -904,7 +901,7 @@ static bool CreateConfig(EGLConfig* aConfig
|
||||
// Bug 970096
|
||||
// Some devices that have 24 bit screens only support 16 bit OpenGL?
|
||||
if (depth == 24) {
|
||||
return CreateConfig(aConfig, 16
|
||||
return CreateConfig(egl, aConfig, 16
|
||||
# ifdef MOZ_BUILD_WEBRENDER
|
||||
,
|
||||
aEnableDepthBuffer
|
||||
@ -928,10 +925,11 @@ already_AddRefed<GLContext> GLContextProviderEGL::CreateWrappingExisting(
|
||||
|
||||
if (!aContext || !aSurface) return nullptr;
|
||||
|
||||
const auto& egl = GLLibraryEGL::Get();
|
||||
SurfaceCaps caps = SurfaceCaps::Any();
|
||||
EGLConfig config = EGL_NO_CONFIG;
|
||||
RefPtr<GLContextEGL> gl =
|
||||
new GLContextEGL(CreateContextFlags::NONE, caps, false, config,
|
||||
new GLContextEGL(egl, CreateContextFlags::NONE, caps, false, config,
|
||||
(EGLSurface)aSurface, (EGLContext)aContext);
|
||||
gl->SetIsDoubleBuffered(true);
|
||||
gl->mOwnsContext = false;
|
||||
@ -991,7 +989,7 @@ EGLSurface GLContextProviderEGL::CreateEGLSurface(void* aWindow,
|
||||
}
|
||||
auto* egl = gl::GLLibraryEGL::Get();
|
||||
EGLConfig config = aConfig;
|
||||
if (!config && !CreateConfig(&config
|
||||
if (!config && !CreateConfig(egl, &config
|
||||
# ifdef MOZ_BUILD_WEBRENDER
|
||||
,
|
||||
/* aEnableDepthBuffer */ false
|
||||
@ -1003,7 +1001,7 @@ EGLSurface GLContextProviderEGL::CreateEGLSurface(void* aWindow,
|
||||
MOZ_ASSERT(aWindow);
|
||||
|
||||
EGLSurface surface =
|
||||
egl->fCreateWindowSurface(EGL_DISPLAY(), config, aWindow, 0);
|
||||
egl->fCreateWindowSurface(egl->Display(), config, aWindow, 0);
|
||||
if (surface == EGL_NO_SURFACE) {
|
||||
MOZ_CRASH("GFX: Failed to create EGLSurface 2!");
|
||||
}
|
||||
@ -1018,7 +1016,7 @@ void GLContextProviderEGL::DestroyEGLSurface(EGLSurface surface) {
|
||||
MOZ_CRASH("GFX: Failed to load EGL library 5!");
|
||||
}
|
||||
auto* egl = gl::GLLibraryEGL::Get();
|
||||
egl->fDestroySurface(EGL_DISPLAY(), surface);
|
||||
egl->fDestroySurface(egl->Display(), surface);
|
||||
}
|
||||
#endif // defined(ANDROID)
|
||||
|
||||
@ -1156,12 +1154,12 @@ already_AddRefed<GLContextEGL> GLContextEGL::CreateEGLPBufferOffscreenContext(
|
||||
EGLSurface surface = nullptr;
|
||||
#if defined(MOZ_WAYLAND)
|
||||
if (!GDK_IS_X11_DISPLAY(gdk_display_get_default())) {
|
||||
surface = GLContextEGL::CreateWaylandBufferSurface(config, pbSize);
|
||||
surface = GLContextEGL::CreateWaylandBufferSurface(egl, config, pbSize);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
surface = GLContextEGL::CreatePBufferSurfaceTryingPowerOfTwo(
|
||||
config, LOCAL_EGL_NONE, pbSize);
|
||||
egl, config, LOCAL_EGL_NONE, pbSize);
|
||||
}
|
||||
if (!surface) {
|
||||
*out_failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_EGL_POT");
|
||||
@ -1170,7 +1168,7 @@ already_AddRefed<GLContextEGL> GLContextEGL::CreateEGLPBufferOffscreenContext(
|
||||
}
|
||||
|
||||
RefPtr<GLContextEGL> gl = GLContextEGL::CreateGLContext(
|
||||
flags, configCaps, true, config, surface, out_failureId);
|
||||
egl, flags, configCaps, true, config, surface, out_failureId);
|
||||
if (!gl) {
|
||||
NS_WARNING("Failed to create GLContext from PBuffer");
|
||||
egl->fDestroySurface(egl->Display(), surface);
|
||||
|
@ -358,7 +358,7 @@ class GLLibraryEGL final {
|
||||
|
||||
////
|
||||
|
||||
EGLDisplay Display() {
|
||||
EGLDisplay Display() const {
|
||||
MOZ_ASSERT(mInitialized);
|
||||
return mEGLDisplay;
|
||||
}
|
||||
@ -541,8 +541,6 @@ class GLLibraryEGL final {
|
||||
static StaticRefPtr<GLLibraryEGL> sEGLLibrary;
|
||||
};
|
||||
|
||||
#define EGL_DISPLAY() GLLibraryEGL::Get()->Display()
|
||||
|
||||
} /* namespace gl */
|
||||
} /* namespace mozilla */
|
||||
|
||||
|
@ -476,7 +476,10 @@ bool GLScreenBuffer::Swap(const gfx::IntSize& size) {
|
||||
GLContext::LocalErrorScope errorScope(*mGL);
|
||||
#endif
|
||||
|
||||
SharedSurface::ProdCopy(src, dest, mFactory.get());
|
||||
if (!SharedSurface::ProdCopy(src, dest, mFactory.get())) {
|
||||
newBack->Surf()->ProducerRelease();
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
MOZ_ASSERT(!errorScope.GetError());
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "nsThreadUtils.h"
|
||||
#include "ScopedGLHelpers.h"
|
||||
#include "SharedSurfaceGL.h"
|
||||
#include "mozilla/gfx/Logging.h"
|
||||
#include "mozilla/layers/CompositorTypes.h"
|
||||
#include "mozilla/layers/TextureClientSharedSurface.h"
|
||||
#include "mozilla/layers/TextureForwarder.h"
|
||||
@ -24,7 +25,7 @@ namespace mozilla {
|
||||
namespace gl {
|
||||
|
||||
/*static*/
|
||||
void SharedSurface::ProdCopy(SharedSurface* src, SharedSurface* dest,
|
||||
bool SharedSurface::ProdCopy(SharedSurface* src, SharedSurface* dest,
|
||||
SurfaceFactory* factory) {
|
||||
GLContext* gl = src->mGL;
|
||||
|
||||
@ -40,10 +41,14 @@ void SharedSurface::ProdCopy(SharedSurface* src, SharedSurface* dest,
|
||||
UniquePtr<SharedSurface_Basic> tempSurf;
|
||||
tempSurf = SharedSurface_Basic::Create(gl, factory->mFormats, src->mSize,
|
||||
factory->mCaps.alpha);
|
||||
if (!tempSurf) {
|
||||
gfxCriticalNote << "Failed to allocate SharedSurface_Basic.";
|
||||
return false;
|
||||
}
|
||||
|
||||
ProdCopy(src, tempSurf.get(), factory);
|
||||
ProdCopy(tempSurf.get(), dest, factory);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (src->mAttachType == AttachmentType::Screen) {
|
||||
@ -72,8 +77,9 @@ void SharedSurface::ProdCopy(SharedSurface* src, SharedSurface* dest,
|
||||
GLuint destRB = dest->ProdRenderbuffer();
|
||||
ScopedFramebufferForRenderbuffer destWrapper(gl, destRB);
|
||||
|
||||
gl->BlitHelper()->BlitFramebufferToFramebuffer(0, destWrapper.FB(),
|
||||
src->mSize, dest->mSize);
|
||||
gl->BlitHelper()->BlitFramebufferToFramebuffer(
|
||||
0, destWrapper.FB(), gfx::IntRect({}, src->mSize),
|
||||
gfx::IntRect({}, dest->mSize));
|
||||
} else {
|
||||
MOZ_CRASH("GFX: Unhandled dest->mAttachType 1.");
|
||||
}
|
||||
@ -82,7 +88,7 @@ void SharedSurface::ProdCopy(SharedSurface* src, SharedSurface* dest,
|
||||
|
||||
if (origNeedsRelock) origLocked->LockProd();
|
||||
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (dest->mAttachType == AttachmentType::Screen) {
|
||||
@ -111,8 +117,9 @@ void SharedSurface::ProdCopy(SharedSurface* src, SharedSurface* dest,
|
||||
GLuint srcRB = src->ProdRenderbuffer();
|
||||
ScopedFramebufferForRenderbuffer srcWrapper(gl, srcRB);
|
||||
|
||||
gl->BlitHelper()->BlitFramebufferToFramebuffer(srcWrapper.FB(), 0,
|
||||
src->mSize, dest->mSize);
|
||||
gl->BlitHelper()->BlitFramebufferToFramebuffer(
|
||||
srcWrapper.FB(), 0, gfx::IntRect({}, src->mSize),
|
||||
gfx::IntRect({}, dest->mSize));
|
||||
} else {
|
||||
MOZ_CRASH("GFX: Unhandled src->mAttachType 2.");
|
||||
}
|
||||
@ -121,7 +128,7 @@ void SharedSurface::ProdCopy(SharedSurface* src, SharedSurface* dest,
|
||||
|
||||
if (origNeedsRelock) origLocked->LockProd();
|
||||
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Alright, done with cases involving Screen types.
|
||||
@ -138,7 +145,7 @@ void SharedSurface::ProdCopy(SharedSurface* src, SharedSurface* dest,
|
||||
gl->BlitHelper()->BlitTextureToTexture(
|
||||
srcTex, destTex, src->mSize, dest->mSize, srcTarget, destTarget);
|
||||
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (dest->mAttachType == AttachmentType::GLRenderbuffer) {
|
||||
@ -148,7 +155,7 @@ void SharedSurface::ProdCopy(SharedSurface* src, SharedSurface* dest,
|
||||
gl->BlitHelper()->BlitTextureToFramebuffer(srcTex, src->mSize,
|
||||
dest->mSize, srcTarget);
|
||||
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
MOZ_CRASH("GFX: Unhandled dest->mAttachType 3.");
|
||||
@ -166,7 +173,7 @@ void SharedSurface::ProdCopy(SharedSurface* src, SharedSurface* dest,
|
||||
gl->BlitHelper()->BlitFramebufferToTexture(destTex, src->mSize,
|
||||
dest->mSize, destTarget);
|
||||
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (dest->mAttachType == AttachmentType::GLRenderbuffer) {
|
||||
@ -174,9 +181,10 @@ void SharedSurface::ProdCopy(SharedSurface* src, SharedSurface* dest,
|
||||
ScopedFramebufferForRenderbuffer destWrapper(gl, destRB);
|
||||
|
||||
gl->BlitHelper()->BlitFramebufferToFramebuffer(
|
||||
srcWrapper.FB(), destWrapper.FB(), src->mSize, dest->mSize);
|
||||
srcWrapper.FB(), destWrapper.FB(), gfx::IntRect({}, src->mSize),
|
||||
gfx::IntRect({}, dest->mSize));
|
||||
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
MOZ_CRASH("GFX: Unhandled dest->mAttachType 4.");
|
||||
|
@ -53,7 +53,7 @@ class ShSurfHandle;
|
||||
|
||||
class SharedSurface {
|
||||
public:
|
||||
static void ProdCopy(SharedSurface* src, SharedSurface* dest,
|
||||
static bool ProdCopy(SharedSurface* src, SharedSurface* dest,
|
||||
SurfaceFactory* factory);
|
||||
|
||||
const SharedSurfaceType mType;
|
||||
|
@ -41,7 +41,8 @@ UniquePtr<SharedSurface_ANGLEShareHandle>
|
||||
SharedSurface_ANGLEShareHandle::Create(GLContext* gl, EGLConfig config,
|
||||
const gfx::IntSize& size,
|
||||
bool hasAlpha) {
|
||||
auto* egl = gl::GLLibraryEGL::Get();
|
||||
const auto& gle = GLContextEGL::Cast(gl);
|
||||
const auto& egl = gle->mEgl;
|
||||
MOZ_ASSERT(egl);
|
||||
MOZ_ASSERT(egl->IsExtensionSupported(
|
||||
GLLibraryEGL::ANGLE_surface_d3d_texture_2d_share_handle));
|
||||
@ -306,13 +307,14 @@ SurfaceFactory_ANGLEShareHandle::Create(
|
||||
GLContext* gl, const SurfaceCaps& caps,
|
||||
const RefPtr<layers::LayersIPCChannel>& allocator,
|
||||
const layers::TextureFlags& flags) {
|
||||
auto* egl = gl::GLLibraryEGL::Get();
|
||||
const auto& gle = GLContextEGL::Cast(gl);
|
||||
const auto& egl = gle->mEgl;
|
||||
if (!egl) return nullptr;
|
||||
|
||||
auto ext = GLLibraryEGL::ANGLE_surface_d3d_texture_2d_share_handle;
|
||||
if (!egl->IsExtensionSupported(ext)) return nullptr;
|
||||
|
||||
EGLConfig config = GLContextEGL::Cast(gl)->mConfig;
|
||||
const auto& config = gle->mConfig;
|
||||
|
||||
typedef SurfaceFactory_ANGLEShareHandle ptrT;
|
||||
UniquePtr<ptrT> ret(new ptrT(gl, caps, allocator, flags, egl, config));
|
||||
|
@ -19,7 +19,8 @@ namespace gl {
|
||||
UniquePtr<SharedSurface_EGLImage> SharedSurface_EGLImage::Create(
|
||||
GLContext* prodGL, const GLFormats& formats, const gfx::IntSize& size,
|
||||
bool hasAlpha, EGLContext context) {
|
||||
auto* egl = gl::GLLibraryEGL::Get();
|
||||
const auto& gle = GLContextEGL::Cast(prodGL);
|
||||
const auto& egl = gle->mEgl;
|
||||
MOZ_ASSERT(egl);
|
||||
MOZ_ASSERT(context);
|
||||
|
||||
@ -44,8 +45,8 @@ UniquePtr<SharedSurface_EGLImage> SharedSurface_EGLImage::Create(
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret.reset(new SharedSurface_EGLImage(prodGL, egl, size, hasAlpha, formats,
|
||||
prodTex, image));
|
||||
ret.reset(new SharedSurface_EGLImage(prodGL, size, hasAlpha, formats, prodTex,
|
||||
image));
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -56,7 +57,7 @@ bool SharedSurface_EGLImage::HasExtensions(GLLibraryEGL* egl, GLContext* gl) {
|
||||
gl->IsExtensionSupported(GLContext::OES_EGL_image));
|
||||
}
|
||||
|
||||
SharedSurface_EGLImage::SharedSurface_EGLImage(GLContext* gl, GLLibraryEGL* egl,
|
||||
SharedSurface_EGLImage::SharedSurface_EGLImage(GLContext* gl,
|
||||
const gfx::IntSize& size,
|
||||
bool hasAlpha,
|
||||
const GLFormats& formats,
|
||||
@ -67,19 +68,20 @@ SharedSurface_EGLImage::SharedSurface_EGLImage(GLContext* gl, GLLibraryEGL* egl,
|
||||
false) // Can't recycle, as mSync changes never update TextureHost.
|
||||
,
|
||||
mMutex("SharedSurface_EGLImage mutex"),
|
||||
mEGL(egl),
|
||||
mFormats(formats),
|
||||
mProdTex(prodTex),
|
||||
mImage(image),
|
||||
mSync(0) {}
|
||||
|
||||
SharedSurface_EGLImage::~SharedSurface_EGLImage() {
|
||||
mEGL->fDestroyImage(Display(), mImage);
|
||||
const auto& gle = GLContextEGL::Cast(mGL);
|
||||
const auto& egl = gle->mEgl;
|
||||
egl->fDestroyImage(egl->Display(), mImage);
|
||||
|
||||
if (mSync) {
|
||||
// We can't call this unless we have the ext, but we will always have
|
||||
// the ext if we have something to destroy.
|
||||
mEGL->fDestroySync(Display(), mSync);
|
||||
egl->fDestroySync(egl->Display(), mSync);
|
||||
mSync = 0;
|
||||
}
|
||||
|
||||
@ -90,18 +92,21 @@ SharedSurface_EGLImage::~SharedSurface_EGLImage() {
|
||||
}
|
||||
|
||||
void SharedSurface_EGLImage::ProducerReleaseImpl() {
|
||||
const auto& gle = GLContextEGL::Cast(mGL);
|
||||
const auto& egl = gle->mEgl;
|
||||
|
||||
MutexAutoLock lock(mMutex);
|
||||
mGL->MakeCurrent();
|
||||
|
||||
if (mEGL->IsExtensionSupported(GLLibraryEGL::KHR_fence_sync) &&
|
||||
if (egl->IsExtensionSupported(GLLibraryEGL::KHR_fence_sync) &&
|
||||
mGL->IsExtensionSupported(GLContext::OES_EGL_sync)) {
|
||||
if (mSync) {
|
||||
MOZ_RELEASE_ASSERT(false, "GFX: Non-recycleable should not Fence twice.");
|
||||
MOZ_ALWAYS_TRUE(mEGL->fDestroySync(Display(), mSync));
|
||||
MOZ_ALWAYS_TRUE(egl->fDestroySync(egl->Display(), mSync));
|
||||
mSync = 0;
|
||||
}
|
||||
|
||||
mSync = mEGL->fCreateSync(Display(), LOCAL_EGL_SYNC_FENCE, nullptr);
|
||||
mSync = egl->fCreateSync(egl->Display(), LOCAL_EGL_SYNC_FENCE, nullptr);
|
||||
if (mSync) {
|
||||
mGL->fFlush();
|
||||
return;
|
||||
@ -113,15 +118,15 @@ void SharedSurface_EGLImage::ProducerReleaseImpl() {
|
||||
}
|
||||
|
||||
void SharedSurface_EGLImage::ProducerReadAcquireImpl() {
|
||||
const auto& gle = GLContextEGL::Cast(mGL);
|
||||
const auto& egl = gle->mEgl;
|
||||
// Wait on the fence, because presumably we're going to want to read this
|
||||
// surface
|
||||
if (mSync) {
|
||||
mEGL->fClientWaitSync(Display(), mSync, 0, LOCAL_EGL_FOREVER);
|
||||
egl->fClientWaitSync(egl->Display(), mSync, 0, LOCAL_EGL_FOREVER);
|
||||
}
|
||||
}
|
||||
|
||||
EGLDisplay SharedSurface_EGLImage::Display() const { return mEGL->Display(); }
|
||||
|
||||
bool SharedSurface_EGLImage::ToSurfaceDescriptor(
|
||||
layers::SurfaceDescriptor* const out_descriptor) {
|
||||
*out_descriptor = layers::EGLImageDescriptor(
|
||||
@ -131,9 +136,10 @@ bool SharedSurface_EGLImage::ToSurfaceDescriptor(
|
||||
|
||||
bool SharedSurface_EGLImage::ReadbackBySharedHandle(
|
||||
gfx::DataSourceSurface* out_surface) {
|
||||
const auto& gle = GLContextEGL::Cast(mGL);
|
||||
const auto& egl = gle->mEgl;
|
||||
MOZ_ASSERT(out_surface);
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
auto* egl = gl::GLLibraryEGL::Get();
|
||||
return egl->ReadbackEGLImage(mImage, out_surface);
|
||||
}
|
||||
|
||||
@ -144,12 +150,13 @@ UniquePtr<SurfaceFactory_EGLImage> SurfaceFactory_EGLImage::Create(
|
||||
GLContext* prodGL, const SurfaceCaps& caps,
|
||||
const RefPtr<layers::LayersIPCChannel>& allocator,
|
||||
const layers::TextureFlags& flags) {
|
||||
EGLContext context = GLContextEGL::Cast(prodGL)->mContext;
|
||||
const auto& gle = GLContextEGL::Cast(prodGL);
|
||||
const auto& egl = gle->mEgl;
|
||||
const auto& context = gle->mContext;
|
||||
|
||||
typedef SurfaceFactory_EGLImage ptrT;
|
||||
UniquePtr<ptrT> ret;
|
||||
|
||||
auto* egl = gl::GLLibraryEGL::Get();
|
||||
if (SharedSurface_EGLImage::HasExtensions(egl, prodGL)) {
|
||||
ret.reset(new ptrT(prodGL, caps, allocator, flags, context));
|
||||
}
|
||||
@ -170,9 +177,9 @@ UniquePtr<SharedSurface_SurfaceTexture> SharedSurface_SurfaceTexture::Create(
|
||||
UniquePtr<SharedSurface_SurfaceTexture> ret;
|
||||
|
||||
AndroidNativeWindow window(surface);
|
||||
GLContextEGL* egl = GLContextEGL::Cast(prodGL);
|
||||
MOZ_ASSERT(egl);
|
||||
EGLSurface eglSurface = egl->CreateCompatibleSurface(window.NativeWindow());
|
||||
const auto& gle = GLContextEGL::Cast(prodGL);
|
||||
MOZ_ASSERT(gle);
|
||||
EGLSurface eglSurface = gle->CreateCompatibleSurface(window.NativeWindow());
|
||||
if (!eglSurface) {
|
||||
return ret;
|
||||
}
|
||||
|
@ -38,7 +38,6 @@ class SharedSurface_EGLImage : public SharedSurface {
|
||||
|
||||
protected:
|
||||
mutable Mutex mMutex;
|
||||
GLLibraryEGL* const mEGL;
|
||||
const GLFormats mFormats;
|
||||
GLuint mProdTex;
|
||||
|
||||
@ -48,12 +47,10 @@ class SharedSurface_EGLImage : public SharedSurface {
|
||||
protected:
|
||||
EGLSync mSync;
|
||||
|
||||
SharedSurface_EGLImage(GLContext* gl, GLLibraryEGL* egl,
|
||||
const gfx::IntSize& size, bool hasAlpha,
|
||||
SharedSurface_EGLImage(GLContext* gl, const gfx::IntSize& size, bool hasAlpha,
|
||||
const GLFormats& formats, GLuint prodTex,
|
||||
EGLImage image);
|
||||
|
||||
EGLDisplay Display() const;
|
||||
void UpdateProdTexture(const MutexAutoLock& curAutoLock);
|
||||
|
||||
public:
|
||||
|
@ -142,8 +142,9 @@ void TextureImageEGL::Resize(const gfx::IntSize& aSize) {
|
||||
bool TextureImageEGL::BindTexImage() {
|
||||
if (mBound && !ReleaseTexImage()) return false;
|
||||
|
||||
auto* egl = gl::GLLibraryEGL::Get();
|
||||
EGLBoolean success = egl->fBindTexImage(EGL_DISPLAY(), (EGLSurface)mSurface,
|
||||
const auto& gle = GLContextEGL::Cast(mGLContext);
|
||||
const auto& egl = gle->mEgl;
|
||||
EGLBoolean success = egl->fBindTexImage(egl->Display(), (EGLSurface)mSurface,
|
||||
LOCAL_EGL_BACK_BUFFER);
|
||||
|
||||
if (success == LOCAL_EGL_FALSE) return false;
|
||||
@ -155,9 +156,10 @@ bool TextureImageEGL::BindTexImage() {
|
||||
bool TextureImageEGL::ReleaseTexImage() {
|
||||
if (!mBound) return true;
|
||||
|
||||
auto* egl = gl::GLLibraryEGL::Get();
|
||||
const auto& gle = GLContextEGL::Cast(mGLContext);
|
||||
const auto& egl = gle->mEgl;
|
||||
EGLBoolean success = egl->fReleaseTexImage(
|
||||
EGL_DISPLAY(), (EGLSurface)mSurface, LOCAL_EGL_BACK_BUFFER);
|
||||
egl->Display(), (EGLSurface)mSurface, LOCAL_EGL_BACK_BUFFER);
|
||||
|
||||
if (success == LOCAL_EGL_FALSE) return false;
|
||||
|
||||
@ -168,8 +170,9 @@ bool TextureImageEGL::ReleaseTexImage() {
|
||||
void TextureImageEGL::DestroyEGLSurface(void) {
|
||||
if (!mSurface) return;
|
||||
|
||||
auto* egl = gl::GLLibraryEGL::Get();
|
||||
egl->fDestroySurface(EGL_DISPLAY(), mSurface);
|
||||
const auto& gle = GLContextEGL::Cast(mGLContext);
|
||||
const auto& egl = gle->mEgl;
|
||||
egl->fDestroySurface(egl->Display(), mSurface);
|
||||
mSurface = nullptr;
|
||||
}
|
||||
|
||||
|
@ -45,6 +45,7 @@ EXPORTS += [
|
||||
'GLTypes.h',
|
||||
'GLUploadHelpers.h',
|
||||
'HeapCopyOfStackArray.h',
|
||||
'MozFramebuffer.h',
|
||||
'ScopedGLHelpers.h',
|
||||
'SharedSurface.h',
|
||||
'SharedSurfaceEGL.h',
|
||||
@ -89,6 +90,10 @@ if gl_provider == 'CGL':
|
||||
SOURCES += [
|
||||
'SharedSurfaceIO.cpp',
|
||||
]
|
||||
OS_LIBS += [
|
||||
'-framework IOSurface',
|
||||
]
|
||||
|
||||
elif gl_provider == 'EAGL':
|
||||
# These files include ObjC headers that are unfriendly to unified builds
|
||||
SOURCES += [
|
||||
|
@ -18,7 +18,7 @@ RefPtr<VsyncBridgeParent> VsyncBridgeParent::Start(
|
||||
RefPtr<Runnable> task = NewRunnableMethod<Endpoint<PVsyncBridgeParent>&&>(
|
||||
"gfx::VsyncBridgeParent::Open", parent, &VsyncBridgeParent::Open,
|
||||
std::move(aEndpoint));
|
||||
CompositorThread()->Dispatch(task.forget());
|
||||
CompositorThreadHolder::Loop()->PostTask(task.forget());
|
||||
|
||||
return parent;
|
||||
}
|
||||
@ -46,10 +46,10 @@ mozilla::ipc::IPCResult VsyncBridgeParent::RecvNotifyVsync(
|
||||
}
|
||||
|
||||
void VsyncBridgeParent::Shutdown() {
|
||||
if (!CompositorThreadHolder::IsInCompositorThread()) {
|
||||
CompositorThread()->Dispatch(
|
||||
NewRunnableMethod("gfx::VsyncBridgeParent::ShutdownImpl", this,
|
||||
&VsyncBridgeParent::ShutdownImpl));
|
||||
MessageLoop* ccloop = CompositorThreadHolder::Loop();
|
||||
if (MessageLoop::current() != ccloop) {
|
||||
ccloop->PostTask(NewRunnableMethod("gfx::VsyncBridgeParent::ShutdownImpl",
|
||||
this, &VsyncBridgeParent::ShutdownImpl));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "mozilla/layers/TextureHost.h"
|
||||
#include "mozilla/layers/CompositorThread.h"
|
||||
#include "mozilla/mozalloc.h" // for operator delete, etc
|
||||
#include "GeckoProfiler.h"
|
||||
#include "gfx2DGlue.h"
|
||||
#include "nsAppRunner.h"
|
||||
#include "LayersHelpers.h"
|
||||
@ -75,6 +76,8 @@ Compositor::Compositor(widget::CompositorWidget* aWidget,
|
||||
Compositor::~Compositor() { ReadUnlockTextures(); }
|
||||
|
||||
void Compositor::Destroy() {
|
||||
mWidget = nullptr;
|
||||
|
||||
TextureSourceProvider::Destroy();
|
||||
mIsDestroyed = true;
|
||||
}
|
||||
@ -593,5 +596,14 @@ already_AddRefed<RecordedFrame> Compositor::RecordFrame(
|
||||
return MakeAndAddRef<CompositorRecordedFrame>(aTimeStamp, std::move(buffer));
|
||||
}
|
||||
|
||||
bool Compositor::ShouldRecordFrames() const {
|
||||
#ifdef MOZ_GECKO_PROFILER
|
||||
if (profiler_feature_active(ProfilerFeature::Screenshots)) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return mRecordFrames;
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
@ -128,6 +128,9 @@ class DataTextureSource;
|
||||
class CompositingRenderTarget;
|
||||
class CompositorBridgeParent;
|
||||
class LayerManagerComposite;
|
||||
#ifdef XP_MACOSX
|
||||
class NativeLayer;
|
||||
#endif
|
||||
class CompositorOGL;
|
||||
class CompositorD3D9;
|
||||
class CompositorD3D11;
|
||||
@ -170,8 +173,9 @@ enum SurfaceInitMode { INIT_MODE_NONE, INIT_MODE_CLEAR };
|
||||
* call DrawQuad,
|
||||
* call EndFrame.
|
||||
*
|
||||
* By default, the compositor will render to the screen, to render to a target,
|
||||
* call SetTargetContext or SetRenderTarget, the latter with a target created
|
||||
* By default, the compositor will render to the screen if BeginFrameForWindow
|
||||
* is called. To render to a target, call BeginFrameForTarget or
|
||||
* or SetRenderTarget, the latter with a target created
|
||||
* by CreateRenderTarget or CreateRenderTargetFromSource.
|
||||
*
|
||||
* The target and viewport methods can be called before any DrawQuad call and
|
||||
@ -189,8 +193,6 @@ class Compositor : public TextureSourceProvider {
|
||||
void Destroy() override;
|
||||
bool IsDestroyed() const { return mIsDestroyed; }
|
||||
|
||||
virtual void DetachWidget() { mWidget = nullptr; }
|
||||
|
||||
/**
|
||||
* Request a texture host identifier that may be used for creating textures
|
||||
* across process or thread boundaries that are compatible with this
|
||||
@ -203,20 +205,6 @@ class Compositor : public TextureSourceProvider {
|
||||
*/
|
||||
virtual bool CanUseCanvasLayerForSize(const gfx::IntSize& aSize) = 0;
|
||||
|
||||
/**
|
||||
* Set the target for rendering. Results will have been written to aTarget by
|
||||
* the time that EndFrame returns.
|
||||
*
|
||||
* If this method is not used, or we pass in nullptr, we target the
|
||||
* compositor's usual swap chain and render to the screen.
|
||||
*/
|
||||
void SetTargetContext(gfx::DrawTarget* aTarget, const gfx::IntRect& aRect) {
|
||||
mTarget = aTarget;
|
||||
mTargetBounds = aRect;
|
||||
}
|
||||
gfx::DrawTarget* GetTargetContext() const { return mTarget; }
|
||||
void ClearTargetContext() { mTarget = nullptr; }
|
||||
|
||||
typedef uint32_t MakeCurrentFlags;
|
||||
static const MakeCurrentFlags ForceMakeCurrent = 0x1;
|
||||
/**
|
||||
@ -398,37 +386,121 @@ class Compositor : public TextureSourceProvider {
|
||||
virtual void ClearRect(const gfx::Rect& aRect) = 0;
|
||||
|
||||
/**
|
||||
* Start a new frame.
|
||||
* Start a new frame for rendering to the window.
|
||||
* Needs to be paired with a call to EndFrame() if the return value is not
|
||||
* Nothing().
|
||||
*
|
||||
* aInvalidRect is the invalid region of the screen; it can be ignored for
|
||||
* compositors where the performance for compositing the entire window is
|
||||
* sufficient.
|
||||
* aInvalidRegion is the invalid region of the window.
|
||||
* aClipRect is the clip rect for all drawing (optional).
|
||||
* aRenderBounds is the bounding rect for rendering.
|
||||
* aOpaqueRegion is the area that contains opaque content.
|
||||
* All coordinates are in window space.
|
||||
*
|
||||
* aClipRectIn is the clip rect for the window in window space (optional).
|
||||
* aTransform is the transform from user space to window space.
|
||||
* aRenderBounds bounding rect for rendering, in user space.
|
||||
*
|
||||
* If aClipRectIn is null, this method sets *aClipRectOut to the clip rect
|
||||
* actually used for rendering (if aClipRectIn is non-null, we will use that
|
||||
* for the clip rect).
|
||||
*
|
||||
* If aRenderBoundsOut is non-null, it will be set to the render bounds
|
||||
* actually used by the compositor in window space. If aRenderBoundsOut
|
||||
* is returned empty, composition should be aborted.
|
||||
*
|
||||
* If aOpaque is true, then all of aInvalidRegion will be drawn to with
|
||||
* opaque content.
|
||||
* Returns the non-empty render bounds actually used by the compositor in
|
||||
* window space, or Nothing() if composition should be aborted.
|
||||
*/
|
||||
virtual void BeginFrame(const nsIntRegion& aInvalidRegion,
|
||||
const gfx::IntRect* aClipRectIn,
|
||||
const gfx::IntRect& aRenderBounds,
|
||||
const nsIntRegion& aOpaqueRegion,
|
||||
gfx::IntRect* aClipRectOut = nullptr,
|
||||
gfx::IntRect* aRenderBoundsOut = nullptr) = 0;
|
||||
virtual Maybe<gfx::IntRect> BeginFrameForWindow(
|
||||
const nsIntRegion& aInvalidRegion, const Maybe<gfx::IntRect>& aClipRect,
|
||||
const gfx::IntRect& aRenderBounds, const nsIntRegion& aOpaqueRegion) = 0;
|
||||
|
||||
/**
|
||||
* Start a new frame for rendering to a DrawTarget. Rendering can happen
|
||||
* directly into the DrawTarget, or it can happen in an offscreen GPU buffer
|
||||
* and read back into the DrawTarget in EndFrame, or it can happen inside the
|
||||
* window and read back into the DrawTarget in EndFrame.
|
||||
* Needs to be paired with a call to EndFrame() if the return value is not
|
||||
* Nothing().
|
||||
*
|
||||
* aInvalidRegion is the invalid region in the target.
|
||||
* aClipRect is the clip rect for all drawing (optional).
|
||||
* aRenderBounds is the bounding rect for rendering.
|
||||
* aOpaqueRegion is the area that contains opaque content.
|
||||
* aTarget is the DrawTarget which should contain the rendering after
|
||||
* EndFrame() has been called.
|
||||
* aTargetBounds are the DrawTarget's bounds.
|
||||
* All coordinates are in window space.
|
||||
*
|
||||
* Returns the non-empty render bounds actually used by the compositor in
|
||||
* window space, or Nothing() if composition should be aborted.
|
||||
*
|
||||
* If BeginFrame succeeds, the compositor keeps a reference to aTarget until
|
||||
* EndFrame is called.
|
||||
*/
|
||||
virtual Maybe<gfx::IntRect> BeginFrameForTarget(
|
||||
const nsIntRegion& aInvalidRegion, const Maybe<gfx::IntRect>& aClipRect,
|
||||
const gfx::IntRect& aRenderBounds, const nsIntRegion& aOpaqueRegion,
|
||||
gfx::DrawTarget* aTarget, const gfx::IntRect& aTargetBounds) = 0;
|
||||
|
||||
/**
|
||||
* Start a new frame for rendering to one or more native layers. Needs to be
|
||||
* paired with a call to EndFrame().
|
||||
*
|
||||
* This puts the compositor in a state where offscreen rendering is allowed.
|
||||
* Rendering an actual native layer is only possible via a call to
|
||||
* BeginRenderingToNativeLayer(), after BeginFrameForNativeLayers() has run.
|
||||
*
|
||||
* The following is true for the entire time between
|
||||
* BeginFrameForNativeLayers() and EndFrame(), even outside pairs of calls to
|
||||
* Begin/EndRenderingToNativeLayer():
|
||||
* - GetCurrentRenderTarget() will return something non-null.
|
||||
* - CreateRenderTarget() and SetRenderTarget() can be called, in order to
|
||||
* facilitate offscreen rendering.
|
||||
* The render target that this method sets as the current render target is not
|
||||
* useful. Do not render to it. It exists so that calls of the form
|
||||
* SetRenderTarget(previousTarget) do not crash.
|
||||
*
|
||||
* Do not call on platforms that do not support native layers.
|
||||
*/
|
||||
#ifdef XP_MACOSX
|
||||
virtual void BeginFrameForNativeLayers() = 0;
|
||||
|
||||
/**
|
||||
* Start rendering into aNativeLayer.
|
||||
* Needs to be paired with a call to EndRenderingToNativeLayer() if the return
|
||||
* value is not Nothing().
|
||||
*
|
||||
* Must be called between BeginFrameForNativeLayers() and EndFrame().
|
||||
*
|
||||
* aInvalidRegion is the invalid region in the native layer.
|
||||
* aClipRect is the clip rect for all drawing (optional).
|
||||
* aOpaqueRegion is the area that contains opaque content.
|
||||
* aNativeLayer is the native layer.
|
||||
* All coordinates, including aNativeLayer->GetRect(), are in window space.
|
||||
*
|
||||
* Returns the non-empty layer rect, or Nothing() if rendering to this layer
|
||||
* should be skipped.
|
||||
*
|
||||
* If BeginRenderingToNativeLayer succeeds, the compositor keeps a reference
|
||||
* to aNativeLayer until EndRenderingToNativeLayer is called.
|
||||
*
|
||||
* Do not call on platforms that do not support native layers.
|
||||
*/
|
||||
virtual Maybe<gfx::IntRect> BeginRenderingToNativeLayer(
|
||||
const nsIntRegion& aInvalidRegion, const Maybe<gfx::IntRect>& aClipRect,
|
||||
const nsIntRegion& aOpaqueRegion, NativeLayer* aNativeLayer) = 0;
|
||||
|
||||
/**
|
||||
* Stop rendering to the native layer and submit the rendering as the layer's
|
||||
* new content.
|
||||
*
|
||||
* Do not call on platforms that do not support native layers.
|
||||
*/
|
||||
virtual void EndRenderingToNativeLayer() = 0;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Notification that we've finished issuing draw commands for normal
|
||||
* layers (as opposed to the diagnostic overlay which comes after).
|
||||
* This is called between BeginFrame* and EndFrame, and it's called before
|
||||
* GetWindowRenderTarget() is called for the purposes of screenshot capturing.
|
||||
* That next call to GetWindowRenderTarget() expects up-to-date contents for
|
||||
* the current frame.
|
||||
* When rendering to native layers, this should be called for every layer,
|
||||
* between BeginRenderingToNativeLayer and EndRenderingToNativeLayer, at a
|
||||
* time at which the current render target is the one that
|
||||
* BeginRenderingToNativeLayer has put in place.
|
||||
* When not rendering to native layers, this should be called at a time when
|
||||
* the current render target is the one that BeginFrameForWindow put in place.
|
||||
*/
|
||||
virtual void NormalDrawingDone() {}
|
||||
|
||||
@ -441,6 +513,8 @@ class Compositor : public TextureSourceProvider {
|
||||
|
||||
virtual void CancelFrame(bool aNeedFlush = true) { ReadUnlockTextures(); }
|
||||
|
||||
virtual void WaitForGPU() {}
|
||||
|
||||
/**
|
||||
* Whether textures created by this compositor can receive partial updates.
|
||||
*/
|
||||
@ -526,7 +600,9 @@ class Compositor : public TextureSourceProvider {
|
||||
*
|
||||
* This is a noop on |CompositorOGL|.
|
||||
*/
|
||||
virtual void RequestAllowFrameRecording(bool aWillRecord) {}
|
||||
virtual void RequestAllowFrameRecording(bool aWillRecord) {
|
||||
mRecordFrames = aWillRecord;
|
||||
}
|
||||
|
||||
/**
|
||||
* Record the current frame for readback by the |CompositionRecorder|.
|
||||
@ -579,6 +655,18 @@ class Compositor : public TextureSourceProvider {
|
||||
const gfx::Matrix4x4& aTransform,
|
||||
const gfx::Rect& aVisibleRect);
|
||||
|
||||
/**
|
||||
* Whether or not the compositor should be prepared to record frames. While
|
||||
* this returns true, compositors are expected to maintain a full window
|
||||
* render target that they return from GetWindowRenderTarget() between
|
||||
* NormalDrawingDone() and EndFrame().
|
||||
*
|
||||
* This will be true when either we are recording a profile with screenshots
|
||||
* enabled or the |LayerManagerComposite| has requested us to record frames
|
||||
* for the |CompositionRecorder|.
|
||||
*/
|
||||
bool ShouldRecordFrames() const;
|
||||
|
||||
/**
|
||||
* Last Composition end time.
|
||||
*/
|
||||
@ -597,9 +685,6 @@ class Compositor : public TextureSourceProvider {
|
||||
|
||||
ScreenRotation mScreenRotation;
|
||||
|
||||
RefPtr<gfx::DrawTarget> mTarget;
|
||||
gfx::IntRect mTargetBounds;
|
||||
|
||||
widget::CompositorWidget* mWidget;
|
||||
|
||||
bool mIsDestroyed;
|
||||
@ -607,6 +692,8 @@ class Compositor : public TextureSourceProvider {
|
||||
gfx::Color mClearColor;
|
||||
gfx::Color mDefaultClearColor;
|
||||
|
||||
bool mRecordFrames = false;
|
||||
|
||||
private:
|
||||
static LayersBackend sBackend;
|
||||
};
|
||||
|
@ -174,6 +174,7 @@ struct TextureFactoryIdentifier {
|
||||
bool mSupportsTextureDirectMapping;
|
||||
bool mCompositorUseANGLE;
|
||||
bool mCompositorUseDComp;
|
||||
bool mUseCompositorWnd;
|
||||
bool mSupportsTextureBlitting;
|
||||
bool mSupportsPartialUploads;
|
||||
bool mSupportsComponentAlpha;
|
||||
@ -186,7 +187,7 @@ struct TextureFactoryIdentifier {
|
||||
int32_t aMaxTextureSize = 4096,
|
||||
bool aSupportsTextureDirectMapping = false,
|
||||
bool aCompositorUseANGLE = false, bool aCompositorUseDComp = false,
|
||||
bool aSupportsTextureBlitting = false,
|
||||
bool aUseCompositorWnd = false, bool aSupportsTextureBlitting = false,
|
||||
bool aSupportsPartialUploads = false, bool aSupportsComponentAlpha = true,
|
||||
SyncHandle aSyncHandle = 0)
|
||||
: mParentBackend(aLayersBackend),
|
||||
@ -195,6 +196,7 @@ struct TextureFactoryIdentifier {
|
||||
mSupportsTextureDirectMapping(aSupportsTextureDirectMapping),
|
||||
mCompositorUseANGLE(aCompositorUseANGLE),
|
||||
mCompositorUseDComp(aCompositorUseDComp),
|
||||
mUseCompositorWnd(aUseCompositorWnd),
|
||||
mSupportsTextureBlitting(aSupportsTextureBlitting),
|
||||
mSupportsPartialUploads(aSupportsPartialUploads),
|
||||
mSupportsComponentAlpha(aSupportsComponentAlpha),
|
||||
@ -209,6 +211,7 @@ struct TextureFactoryIdentifier {
|
||||
aOther.mSupportsTextureDirectMapping &&
|
||||
mCompositorUseANGLE == aOther.mCompositorUseANGLE &&
|
||||
mCompositorUseDComp == aOther.mCompositorUseDComp &&
|
||||
mUseCompositorWnd == aOther.mUseCompositorWnd &&
|
||||
mSupportsTextureBlitting == aOther.mSupportsTextureBlitting &&
|
||||
mSupportsPartialUploads == aOther.mSupportsPartialUploads &&
|
||||
mSupportsComponentAlpha == aOther.mSupportsComponentAlpha &&
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user