зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to inbound. a=merge CLOSED TREE
This commit is contained in:
Коммит
e6319bab61
|
@ -6,6 +6,7 @@
|
|||
**/crashtests/**
|
||||
# Also ignore reftest - specially crafted to produce expected output.
|
||||
**/reftest/**
|
||||
**/reftests/**
|
||||
|
||||
# Exclude expected objdirs.
|
||||
obj*/**
|
||||
|
@ -14,7 +15,6 @@ obj*/**
|
|||
# If you are enabling a directory, please add directory specific exclusions
|
||||
# below.
|
||||
docshell/**
|
||||
editor/**
|
||||
extensions/cookie/**
|
||||
extensions/spellcheck/**
|
||||
extensions/universalchardet/**
|
||||
|
@ -258,6 +258,9 @@ dom/xul/**
|
|||
# Third-party
|
||||
dom/media/webvtt/**
|
||||
|
||||
# Third-party
|
||||
editor/libeditor/tests/browserscope/**
|
||||
|
||||
# Third-party
|
||||
gfx/ots/**
|
||||
gfx/skia/**
|
||||
|
|
|
@ -34,10 +34,10 @@ class LinkHandlerChild extends ActorChild {
|
|||
Services.prefs.getBoolPref("browser.chrome.site_icons", true)) {
|
||||
// Inject the default icon. Use documentURIObject so that we do the right
|
||||
// thing with about:-style error pages. See bug 453442
|
||||
let baseURI = this.content.document.documentURIObject;
|
||||
if (["http", "https"].includes(baseURI.scheme)) {
|
||||
let pageURI = this.content.document.documentURIObject;
|
||||
if (["http", "https"].includes(pageURI.scheme)) {
|
||||
this.seenTabIcon = true;
|
||||
this.iconLoader.addDefaultIcon(baseURI);
|
||||
this.iconLoader.addDefaultIcon(pageURI);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -137,13 +137,11 @@ class LinkHandlerChild extends ActorChild {
|
|||
return;
|
||||
}
|
||||
|
||||
let iconInfo = FaviconLoader.makeFaviconFromLink(link, isRichIcon);
|
||||
if (iconInfo) {
|
||||
if (this.iconLoader.addIconFromLink(link, isRichIcon)) {
|
||||
iconAdded = true;
|
||||
if (!isRichIcon) {
|
||||
this.seenTabIcon = true;
|
||||
}
|
||||
this.iconLoader.addIcon(iconInfo);
|
||||
}
|
||||
break;
|
||||
case "search":
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<blocklist lastupdate="1536186868443" xmlns="http://www.mozilla.org/2006/addons-blocklist">
|
||||
<blocklist lastupdate="1536613417349" xmlns="http://www.mozilla.org/2006/addons-blocklist">
|
||||
<emItems>
|
||||
<emItem blockID="i334" id="{0F827075-B026-42F3-885D-98981EE7B1AE}">
|
||||
<prefs/>
|
||||
|
@ -2412,15 +2412,15 @@
|
|||
<infoURL>https://get.adobe.com/shockwave/</infoURL>
|
||||
<versionRange maxVersion="12.2.0.162" minVersion="0" severity="0" vulnerabilitystatus="1"/>
|
||||
</pluginItem>
|
||||
<pluginItem blockID="832dc9ff-3314-4df2-abcf-7bd65a645371">
|
||||
<match exp="(NPSWF32.*\.dll)|(NPSWF64.*\.dll)|(Flash\ Player\.plugin)" name="filename"/>
|
||||
<infoURL>https://get.adobe.com/flashplayer/</infoURL>
|
||||
<versionRange maxVersion="27.0.0.159" minVersion="0" severity="0" vulnerabilitystatus="1"/>
|
||||
</pluginItem>
|
||||
<pluginItem blockID="49b843cc-a8fc-4ede-be0c-a0da56d0214f" os="Linux">
|
||||
<match exp="libflashplayer\.so" name="filename"/>
|
||||
<infoURL>https://get.adobe.com/flashplayer/</infoURL>
|
||||
<versionRange maxVersion="27.0.0.159" minVersion="0" severity="0" vulnerabilitystatus="1"/>
|
||||
<versionRange maxVersion="30.0.0.113" minVersion="0" severity="0" vulnerabilitystatus="1"/>
|
||||
</pluginItem>
|
||||
<pluginItem blockID="832dc9ff-3314-4df2-abcf-7bd65a645371">
|
||||
<match exp="(NPSWF32.*\.dll)|(NPSWF64.*\.dll)|(Flash\ Player\.plugin)" name="filename"/>
|
||||
<infoURL>https://get.adobe.com/flashplayer/</infoURL>
|
||||
<versionRange maxVersion="30.0.0.113" minVersion="0" severity="0" vulnerabilitystatus="1"/>
|
||||
</pluginItem>
|
||||
</pluginItems>
|
||||
<gfxItems>
|
||||
|
|
|
@ -3681,7 +3681,8 @@ const DOMEventHandler = {
|
|||
break;
|
||||
|
||||
case "Link:SetIcon":
|
||||
this.setIconFromLink(aMsg.target, aMsg.data.originalURL, aMsg.data.canUseForTab,
|
||||
this.setIconFromLink(aMsg.target, aMsg.data.pageURL,
|
||||
aMsg.data.originalURL, aMsg.data.canUseForTab,
|
||||
aMsg.data.expiration, aMsg.data.iconURL);
|
||||
break;
|
||||
|
||||
|
@ -3719,14 +3720,15 @@ const DOMEventHandler = {
|
|||
tab.removeAttribute("pendingicon");
|
||||
},
|
||||
|
||||
setIconFromLink(aBrowser, aOriginalURL, aCanUseForTab, aExpiration, aIconURL) {
|
||||
setIconFromLink(aBrowser, aPageURL, aOriginalURL, aCanUseForTab, aExpiration, aIconURL) {
|
||||
let tab = gBrowser.getTabForBrowser(aBrowser);
|
||||
if (!tab)
|
||||
if (!tab) {
|
||||
return false;
|
||||
|
||||
}
|
||||
try {
|
||||
PlacesUIUtils.loadFavicon(aBrowser, Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
makeURI(aOriginalURL), aExpiration, makeURI(aIconURL));
|
||||
makeURI(aPageURL), makeURI(aOriginalURL),
|
||||
aExpiration, makeURI(aIconURL));
|
||||
} catch (ex) {
|
||||
Cu.reportError(ex);
|
||||
}
|
||||
|
|
|
@ -2,15 +2,15 @@
|
|||
* Bug 1277803 - A test caes for testing favicon loading across different userContextId.
|
||||
*/
|
||||
|
||||
const CC = Components.Constructor;
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "Promise",
|
||||
"resource://gre/modules/Promise.jsm");
|
||||
|
||||
let EventUtils = {};
|
||||
Services.scriptloader.loadSubScript(
|
||||
"chrome://mochikit/content/tests/SimpleTest/EventUtils.js", EventUtils);
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "PromiseUtils",
|
||||
"resource://gre/modules/PromiseUtils.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "PlacesTestUtils",
|
||||
"resource://testing-common/PlacesTestUtils.jsm");
|
||||
|
||||
const TEST_SITE = "http://example.net";
|
||||
const TEST_THIRD_PARTY_SITE = "http://mochi.test:8888";
|
||||
|
||||
|
@ -27,7 +27,6 @@ const USER_CONTEXT_ID_PERSONAL = 1;
|
|||
const USER_CONTEXT_ID_WORK = 2;
|
||||
|
||||
let systemPrincipal = Services.scriptSecurityManager.getSystemPrincipal();
|
||||
let makeURI = ChromeUtils.import("resource://gre/modules/BrowserUtils.jsm", {}).BrowserUtils.makeURI;
|
||||
|
||||
function clearAllImageCaches() {
|
||||
var tools = SpecialPowers.Cc["@mozilla.org/image/tools;1"]
|
||||
|
@ -110,7 +109,7 @@ FaviconObserver.prototype = {
|
|||
this._expectedPrincipal = Services.scriptSecurityManager
|
||||
.createCodebasePrincipal(aPageURI, { userContextId: aUserContextId });
|
||||
this._faviconURL = aFaviconURL;
|
||||
this._faviconLoaded = new Promise.defer();
|
||||
this._faviconLoaded = PromiseUtils.defer();
|
||||
},
|
||||
|
||||
get promise() {
|
||||
|
@ -119,20 +118,11 @@ FaviconObserver.prototype = {
|
|||
};
|
||||
|
||||
function waitOnFaviconLoaded(aFaviconURL) {
|
||||
return new Promise(resolve => {
|
||||
let observer = {
|
||||
onPageChanged(uri, attr, value, id) {
|
||||
|
||||
if (attr === Ci.nsINavHistoryObserver.ATTRIBUTE_FAVICON &&
|
||||
value === aFaviconURL) {
|
||||
resolve();
|
||||
PlacesUtils.history.removeObserver(observer, false);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
PlacesUtils.history.addObserver(observer);
|
||||
});
|
||||
return PlacesTestUtils.waitForNotification(
|
||||
"onPageChanged",
|
||||
(uri, attr, value, id) => attr === Ci.nsINavHistoryObserver.ATTRIBUTE_FAVICON &&
|
||||
value === aFaviconURL,
|
||||
"history");
|
||||
}
|
||||
|
||||
async function generateCookies(aHost) {
|
||||
|
|
|
@ -163,9 +163,9 @@ let InternalFaviconLoader = {
|
|||
});
|
||||
},
|
||||
|
||||
loadFavicon(browser, principal, uri, expiration, iconURI) {
|
||||
loadFavicon(browser, principal, pageURI, uri, expiration, iconURI) {
|
||||
this.ensureInitialized();
|
||||
let win = browser.ownerGlobal;
|
||||
let {ownerGlobal: win, innerWindowID} = browser;
|
||||
if (!gFaviconLoadDataMap.has(win)) {
|
||||
gFaviconLoadDataMap.set(win, []);
|
||||
let unloadHandler = event => {
|
||||
|
@ -179,8 +179,6 @@ let InternalFaviconLoader = {
|
|||
win.addEventListener("unload", unloadHandler, true);
|
||||
}
|
||||
|
||||
let {innerWindowID, currentURI} = browser;
|
||||
|
||||
// First we do the actual setAndFetch call:
|
||||
let loadType = PrivateBrowsingUtils.isWindowPrivate(win)
|
||||
? PlacesUtils.favicons.FAVICON_LOAD_PRIVATE
|
||||
|
@ -193,8 +191,8 @@ let InternalFaviconLoader = {
|
|||
expiration, principal);
|
||||
}
|
||||
|
||||
let request = PlacesUtils.favicons.setAndFetchFaviconForPage(currentURI, uri, false,
|
||||
loadType, callback, principal);
|
||||
let request = PlacesUtils.favicons.setAndFetchFaviconForPage(
|
||||
pageURI, uri, false, loadType, callback, principal);
|
||||
|
||||
// Now register the result so we can cancel it if/when necessary.
|
||||
if (!request) {
|
||||
|
@ -313,15 +311,16 @@ var PlacesUIUtils = {
|
|||
* set and fetch a favicon. Can only be used from the parent process.
|
||||
* @param browser {Browser} The XUL browser element for which we're fetching a favicon.
|
||||
* @param principal {Principal} The loading principal to use for the fetch.
|
||||
* @pram pageURI {URI} The page URI associated to this favicon load.
|
||||
* @param uri {URI} The URI to fetch.
|
||||
* @param expiration {Number} An optional expiration time.
|
||||
* @param iconURI {URI} An optional data: URI holding the icon's data.
|
||||
*/
|
||||
loadFavicon(browser, principal, uri, expiration = 0, iconURI = null) {
|
||||
loadFavicon(browser, principal, pageURI, uri, expiration = 0, iconURI = null) {
|
||||
if (gInContentProcess) {
|
||||
throw new Error("Can't track loads from within the child process!");
|
||||
}
|
||||
InternalFaviconLoader.loadFavicon(browser, principal, uri, expiration, iconURI);
|
||||
InternalFaviconLoader.loadFavicon(browser, principal, pageURI, uri, expiration, iconURI);
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -377,6 +377,7 @@ class IconLoader {
|
|||
|
||||
if (LOCAL_FAVICON_SCHEMES.includes(iconInfo.iconUri.scheme)) {
|
||||
this.mm.sendAsyncMessage("Link:SetIcon", {
|
||||
pageURL: iconInfo.pageUri.spec,
|
||||
originalURL: iconInfo.iconUri.spec,
|
||||
canUseForTab: !iconInfo.isRichIcon,
|
||||
expiration: undefined,
|
||||
|
@ -396,6 +397,7 @@ class IconLoader {
|
|||
let { dataURL, expiration } = await this._loader.load();
|
||||
|
||||
this.mm.sendAsyncMessage("Link:SetIcon", {
|
||||
pageURL: iconInfo.pageUri.spec,
|
||||
originalURL: iconInfo.iconUri.spec,
|
||||
canUseForTab: !iconInfo.isRichIcon,
|
||||
expiration,
|
||||
|
@ -453,21 +455,28 @@ class FaviconLoader {
|
|||
}
|
||||
}
|
||||
|
||||
addIcon(iconInfo) {
|
||||
this.iconInfos.push(iconInfo);
|
||||
this.iconTask.arm();
|
||||
addIconFromLink(aLink, aIsRichIcon) {
|
||||
let iconInfo = makeFaviconFromLink(aLink, aIsRichIcon);
|
||||
if (iconInfo) {
|
||||
this.iconInfos.push(iconInfo);
|
||||
this.iconTask.arm();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
addDefaultIcon(baseURI) {
|
||||
addDefaultIcon(pageUri) {
|
||||
// Currently ImageDocuments will just load the default favicon, see bug
|
||||
// 403651 for discussion.
|
||||
this.addIcon({
|
||||
iconUri: baseURI.mutate().setPathQueryRef("/favicon.ico").finalize(),
|
||||
this.iconInfos.push({
|
||||
pageUri,
|
||||
iconUri: pageUri.mutate().setPathQueryRef("/favicon.ico").finalize(),
|
||||
width: -1,
|
||||
isRichIcon: false,
|
||||
type: TYPE_ICO,
|
||||
node: this.mm.content.document,
|
||||
});
|
||||
this.iconTask.arm();
|
||||
}
|
||||
|
||||
onPageShow() {
|
||||
|
@ -485,21 +494,22 @@ class FaviconLoader {
|
|||
this.iconTask.disarm();
|
||||
this.iconInfos = [];
|
||||
}
|
||||
|
||||
static makeFaviconFromLink(aLink, aIsRichIcon) {
|
||||
let iconUri = getLinkIconURI(aLink);
|
||||
if (!iconUri)
|
||||
return null;
|
||||
|
||||
// Extract the size type and width.
|
||||
let width = extractIconSize(aLink.sizes);
|
||||
|
||||
return {
|
||||
iconUri,
|
||||
width,
|
||||
isRichIcon: aIsRichIcon,
|
||||
type: aLink.type,
|
||||
node: aLink,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function makeFaviconFromLink(aLink, aIsRichIcon) {
|
||||
let iconUri = getLinkIconURI(aLink);
|
||||
if (!iconUri)
|
||||
return null;
|
||||
|
||||
// Extract the size type and width.
|
||||
let width = extractIconSize(aLink.sizes);
|
||||
|
||||
return {
|
||||
pageUri: aLink.ownerDocument.documentURIObject,
|
||||
iconUri,
|
||||
width,
|
||||
isRichIcon: aIsRichIcon,
|
||||
type: aLink.type,
|
||||
node: aLink,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -5,10 +5,19 @@ ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
|
|||
|
||||
const TEST_WINDOW = window;
|
||||
|
||||
function windowActivated(win) {
|
||||
if (Services.ww.activeWindow == win) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return BrowserTestUtils.waitForEvent(win, "activate");
|
||||
}
|
||||
|
||||
async function withOpenWindows(amount, cont) {
|
||||
let windows = [];
|
||||
for (let i = 0; i < amount; ++i) {
|
||||
windows.push(await BrowserTestUtils.openNewBrowserWindow());
|
||||
let win = await BrowserTestUtils.openNewBrowserWindow();
|
||||
await windowActivated(win);
|
||||
windows.push(win);
|
||||
}
|
||||
await cont(windows);
|
||||
await Promise.all(windows.map(window => BrowserTestUtils.closeWindow(window)));
|
||||
|
@ -67,6 +76,7 @@ add_task(async function test_getTopWindow() {
|
|||
content.window.open("about:blank", "_blank", features);
|
||||
});
|
||||
let popupWindow = await popupWindowPromise;
|
||||
await windowActivated(popupWindow);
|
||||
window = BrowserWindowTracker.getTopWindow({ allowPopups: true });
|
||||
Assert.equal(window, popupWindow,
|
||||
"The popup window should be the most recent one, when requested.");
|
||||
|
|
|
@ -44,8 +44,6 @@ class MainFrame extends Component {
|
|||
}
|
||||
|
||||
componentWillMount() {
|
||||
// Need inspector for many things such as dom node preview etc.
|
||||
gToolbox.loadTool("inspector");
|
||||
this.props.accessibility.on("init", this.resetAccessibility);
|
||||
this.props.accessibility.on("shutdown", this.resetAccessibility);
|
||||
this.props.walker.on("document-ready", this.resetAccessibility);
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { createFactory, PureComponent } = require("devtools/client/shared/vendor/react");
|
||||
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||
|
||||
const FontPropertyValue = createFactory(require("./FontPropertyValue"));
|
||||
|
||||
const Types = require("../types");
|
||||
|
||||
class FontAxis extends PureComponent {
|
||||
static get propTypes() {
|
||||
return {
|
||||
axis: PropTypes.shape(Types.fontVariationAxis),
|
||||
onChange: PropTypes.func.isRequired,
|
||||
value: PropTypes.string.isRequired,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Naive implementation to get increment step for variable font axis that ensures
|
||||
* fine grained control based on range of values between min and max.
|
||||
*
|
||||
* @param {Number} min
|
||||
* Minumum value for range.
|
||||
* @param {Number} max
|
||||
* Maximum value for range.
|
||||
* @return {Number}
|
||||
* Step value used in range input for font axis.
|
||||
*/
|
||||
getAxisStep(min, max) {
|
||||
let step = 1;
|
||||
const delta = parseInt(max, 10) - parseInt(min, 10);
|
||||
|
||||
if (delta <= 1) {
|
||||
step = 0.001;
|
||||
} else if (delta <= 10) {
|
||||
step = 0.01;
|
||||
} else if (delta <= 100) {
|
||||
step = 0.1;
|
||||
}
|
||||
|
||||
return step;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { axis, value, onChange } = this.props;
|
||||
|
||||
return FontPropertyValue({
|
||||
className: "font-control-axis",
|
||||
label: axis.name,
|
||||
min: axis.minValue,
|
||||
max: axis.maxValue,
|
||||
name: axis.tag,
|
||||
nameLabel: true,
|
||||
onChange,
|
||||
step: this.getAxisStep(axis.minValue, axis.maxValue),
|
||||
value,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = FontAxis;
|
|
@ -8,8 +8,8 @@ const { createFactory, PureComponent } = require("devtools/client/shared/vendor/
|
|||
const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
||||
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||
|
||||
const FontAxis = createFactory(require("./FontAxis"));
|
||||
const FontName = createFactory(require("./FontName"));
|
||||
const FontPropertyValue = createFactory(require("./FontPropertyValue"));
|
||||
const FontSize = createFactory(require("./FontSize"));
|
||||
const FontStyle = createFactory(require("./FontStyle"));
|
||||
const FontWeight = createFactory(require("./FontWeight"));
|
||||
|
@ -33,42 +33,15 @@ class FontEditor extends PureComponent {
|
|||
}
|
||||
|
||||
/**
|
||||
* Naive implementation to get increment step for variable font axis that ensures
|
||||
* a wide spectrum of precision based on range of values between min and max.
|
||||
*
|
||||
* @param {Number|String} min
|
||||
* Minumum value for range.
|
||||
* @param {Number|String} max
|
||||
* Maximum value for range.
|
||||
* @return {String}
|
||||
* Step value used in range input for font axis.
|
||||
*/
|
||||
getAxisStep(min, max) {
|
||||
let step = 1;
|
||||
const delta = parseInt(max, 10) - parseInt(min, 10);
|
||||
|
||||
if (delta <= 1) {
|
||||
step = 0.001;
|
||||
} else if (delta <= 10) {
|
||||
step = 0.01;
|
||||
} else if (delta <= 100) {
|
||||
step = 0.1;
|
||||
}
|
||||
|
||||
return step.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array of FontPropertyValue components with editing controls
|
||||
* for of the given variable font axes. If no axes were given, return null.
|
||||
* If an axis has a value in the fontEditor store (i.e.: it was declared in CSS or
|
||||
* it was changed using the font editor), use its value, otherwise use the font axis
|
||||
* default.
|
||||
* Get an array of FontAxis components with editing controls for of the given variable
|
||||
* font axes. If no axes were given, return null.
|
||||
* If an axis' value was declared on the font-variation-settings CSS property or was
|
||||
* changed using the font editor, use that value, otherwise use the axis default.
|
||||
*
|
||||
* @param {Array} fontAxes
|
||||
* Array of font axis instances
|
||||
* @param {Object} editedAxes
|
||||
* Object with axes and values edited by the user or predefined in the CSS
|
||||
* Object with axes and values edited by the user or defined in the CSS
|
||||
* declaration for font-variation-settings.
|
||||
* @return {Array|null}
|
||||
*/
|
||||
|
@ -78,16 +51,10 @@ class FontEditor extends PureComponent {
|
|||
}
|
||||
|
||||
return fontAxes.map(axis => {
|
||||
return FontPropertyValue({
|
||||
return FontAxis({
|
||||
key: axis.tag,
|
||||
className: "font-control-axis",
|
||||
label: axis.name,
|
||||
min: axis.minValue,
|
||||
max: axis.maxValue,
|
||||
name: axis.tag,
|
||||
axis,
|
||||
onChange: this.props.onPropertyChange,
|
||||
step: this.getAxisStep(axis.minValue, axis.maxValue),
|
||||
unit: null,
|
||||
value: editedAxes[axis.tag] || axis.defaultValue,
|
||||
});
|
||||
});
|
||||
|
|
|
@ -4,7 +4,11 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const { PureComponent } = require("devtools/client/shared/vendor/react");
|
||||
const {
|
||||
createElement,
|
||||
Fragment,
|
||||
PureComponent,
|
||||
} = require("devtools/client/shared/vendor/react");
|
||||
const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
||||
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||
const { KeyCodes } = require("devtools/client/shared/keycodes");
|
||||
|
@ -17,14 +21,15 @@ class FontPropertyValue extends PureComponent {
|
|||
return {
|
||||
autoIncrement: PropTypes.bool,
|
||||
className: PropTypes.string,
|
||||
defaultValue: PropTypes.oneOfType([ PropTypes.string, PropTypes.number ]),
|
||||
defaultValue: PropTypes.number,
|
||||
label: PropTypes.string.isRequired,
|
||||
min: PropTypes.number.isRequired,
|
||||
max: PropTypes.number.isRequired,
|
||||
name: PropTypes.string.isRequired,
|
||||
nameLabel: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
|
||||
onChange: PropTypes.func.isRequired,
|
||||
step: PropTypes.number,
|
||||
unit: PropTypes.oneOfType([ PropTypes.string, null ]),
|
||||
unit: PropTypes.string,
|
||||
unitOptions: PropTypes.array,
|
||||
value: PropTypes.number,
|
||||
};
|
||||
|
@ -34,7 +39,9 @@ class FontPropertyValue extends PureComponent {
|
|||
return {
|
||||
autoIncrement: false,
|
||||
className: "",
|
||||
nameLabel: false,
|
||||
step: 1,
|
||||
unit: null,
|
||||
unitOptions: []
|
||||
};
|
||||
}
|
||||
|
@ -357,6 +364,37 @@ class FontPropertyValue extends PureComponent {
|
|||
);
|
||||
}
|
||||
|
||||
renderLabelContent() {
|
||||
const {
|
||||
label,
|
||||
name,
|
||||
nameLabel,
|
||||
} = this.props;
|
||||
|
||||
const labelEl = dom.span(
|
||||
{
|
||||
className: "font-control-label-text",
|
||||
"aria-describedby": nameLabel ? `detail-${name}` : null,
|
||||
},
|
||||
label
|
||||
);
|
||||
|
||||
// If this.props.nameLabel is boolean true, the detail label text is the property
|
||||
// name. If it's a string, use that. Otherwise, do not show the additional label text.
|
||||
const detailEl = nameLabel ?
|
||||
dom.span(
|
||||
{
|
||||
className: "font-control-label-detail",
|
||||
id: `detail-${name}`
|
||||
},
|
||||
typeof nameLabel === "boolean" ? name : nameLabel
|
||||
)
|
||||
:
|
||||
null;
|
||||
|
||||
return createElement(Fragment, null, labelEl, detailEl);
|
||||
}
|
||||
|
||||
render() {
|
||||
// Guard against bad axis data.
|
||||
if (this.props.min === this.props.max) {
|
||||
|
@ -409,11 +447,12 @@ class FontPropertyValue extends PureComponent {
|
|||
{
|
||||
className: `font-control ${this.props.className}`,
|
||||
},
|
||||
dom.span(
|
||||
dom.div(
|
||||
{
|
||||
className: "font-control-label",
|
||||
title: this.props.label,
|
||||
},
|
||||
this.props.label
|
||||
this.renderLabelContent()
|
||||
),
|
||||
dom.div(
|
||||
{
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
DevToolsModules(
|
||||
'Font.js',
|
||||
'FontAxis.js',
|
||||
'FontEditor.js',
|
||||
'FontList.js',
|
||||
'FontName.js',
|
||||
|
|
|
@ -221,11 +221,25 @@
|
|||
display: inline-block;
|
||||
flex: 1;
|
||||
font-size: 12px;
|
||||
max-width: 70px;
|
||||
min-width: 70px;
|
||||
margin-right: 10px;
|
||||
text-transform: capitalize;
|
||||
-moz-user-select: none;
|
||||
}
|
||||
|
||||
.font-control-label-text {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.font-control-label-detail {
|
||||
color: var(--grey-45);
|
||||
font-size: smaller;
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
.font-value-input {
|
||||
margin-left: 10px;
|
||||
text-align: right;
|
||||
|
|
|
@ -1296,27 +1296,31 @@ FetchDriver::AsyncOnChannelRedirect(nsIChannel* aOldChannel,
|
|||
// However, ignore internal redirects here. We don't want to flip
|
||||
// Response.redirected to true if an internal redirect occurs. These
|
||||
// should be transparent to script.
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
MOZ_ALWAYS_SUCCEEDS(aNewChannel->GetURI(getter_AddRefs(uri)));
|
||||
|
||||
nsCOMPtr<nsIURI> uriClone;
|
||||
nsresult rv = NS_GetURIWithoutRef(uri, getter_AddRefs(uriClone));
|
||||
if(NS_WARN_IF(NS_FAILED(rv))){
|
||||
return rv;
|
||||
}
|
||||
nsCString spec;
|
||||
rv = uriClone->GetSpec(spec);
|
||||
if(NS_WARN_IF(NS_FAILED(rv))){
|
||||
return rv;
|
||||
}
|
||||
nsCString fragment;
|
||||
rv = uri->GetRef(fragment);
|
||||
if(NS_WARN_IF(NS_FAILED(rv))){
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (!(aFlags & nsIChannelEventSink::REDIRECT_INTERNAL)) {
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
MOZ_ALWAYS_SUCCEEDS(aNewChannel->GetURI(getter_AddRefs(uri)));
|
||||
|
||||
nsCOMPtr<nsIURI> uriClone;
|
||||
nsresult rv = NS_GetURIWithoutRef(uri, getter_AddRefs(uriClone));
|
||||
if(NS_WARN_IF(NS_FAILED(rv))){
|
||||
return rv;
|
||||
}
|
||||
nsCString spec;
|
||||
rv = uriClone->GetSpec(spec);
|
||||
if(NS_WARN_IF(NS_FAILED(rv))){
|
||||
return rv;
|
||||
}
|
||||
nsCString fragment;
|
||||
rv = uri->GetRef(fragment);
|
||||
if(NS_WARN_IF(NS_FAILED(rv))){
|
||||
return rv;
|
||||
}
|
||||
|
||||
mRequest->AddURL(spec, fragment);
|
||||
} else {
|
||||
// Overwrite the URL only when the request is redirected by a service
|
||||
// worker.
|
||||
mRequest->SetURLForInternalRedirect(aFlags, spec, fragment);
|
||||
}
|
||||
|
||||
NS_ConvertUTF8toUTF16 tRPHeaderValue(tRPHeaderCValue);
|
||||
|
|
|
@ -133,6 +133,20 @@ public:
|
|||
|
||||
return mURLList.LastElement();
|
||||
}
|
||||
|
||||
// A safe guard for ensuring that request's URL is only allowed to be set in a
|
||||
// sw internal redirect.
|
||||
void
|
||||
SetURLForInternalRedirect(const uint32_t aFlag,
|
||||
const nsACString& aURL,
|
||||
const nsACString& aFragment)
|
||||
{
|
||||
// Only check in debug build to prevent it from being used unexpectedly.
|
||||
MOZ_ASSERT(aFlag & nsIChannelEventSink::REDIRECT_INTERNAL);
|
||||
|
||||
return SetURL(aURL, aFragment);
|
||||
}
|
||||
|
||||
// AddURL should append the url into url list.
|
||||
// Normally we strip the fragment from the URL in Request::Constructor and
|
||||
// pass the fragment as the second argument into it.
|
||||
|
@ -578,6 +592,18 @@ private:
|
|||
static bool
|
||||
IsWorkerContentPolicy(nsContentPolicyType aContentPolicyType);
|
||||
|
||||
// It should only be called while there is a service-worker-internal-redirect.
|
||||
void
|
||||
SetURL(const nsACString& aURL, const nsACString& aFragment)
|
||||
{
|
||||
MOZ_ASSERT(!aURL.IsEmpty());
|
||||
MOZ_ASSERT(!aURL.Contains('#'));
|
||||
MOZ_ASSERT(mURLList.Length() > 0);
|
||||
|
||||
mURLList.LastElement() = aURL;
|
||||
mFragment.Assign(aFragment);
|
||||
}
|
||||
|
||||
nsCString mMethod;
|
||||
// mURLList: a list of one or more fetch URLs
|
||||
nsTArray<nsCString> mURLList;
|
||||
|
|
|
@ -4493,18 +4493,6 @@ CreateStorageConnection(nsIFile* aDBFile,
|
|||
nsresult rv;
|
||||
bool exists;
|
||||
|
||||
if (IndexedDatabaseManager::InLowDiskSpaceMode()) {
|
||||
rv = aDBFile->Exists(&exists);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (!exists) {
|
||||
NS_WARNING("Refusing to create database because disk space is low!");
|
||||
return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFileURL> dbFileUrl;
|
||||
rv = GetDatabaseFileURL(aDBFile,
|
||||
aPersistenceType,
|
||||
|
@ -18897,23 +18885,6 @@ DatabaseMaintenance::DetermineMaintenanceAction(
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
bool lowDiskSpace = IndexedDatabaseManager::InLowDiskSpaceMode();
|
||||
|
||||
if (QuotaManager::IsRunningXPCShellTests()) {
|
||||
// If we're running XPCShell then we want to test both the low disk space
|
||||
// and normal disk space code paths so pick semi-randomly based on the
|
||||
// current time.
|
||||
lowDiskSpace = ((PR_Now() / PR_USEC_PER_MSEC) % 2) == 0;
|
||||
}
|
||||
|
||||
// If we're low on disk space then the best we can hope for is that an
|
||||
// incremental vacuum might free some space. That is a journaled operation so
|
||||
// it may not be possible even then.
|
||||
if (lowDiskSpace) {
|
||||
*aMaintenanceAction = MaintenanceAction::IncrementalVacuum;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// This method shouldn't make any permanent changes to the database, so make
|
||||
// sure everything gets rolled back when we leave.
|
||||
mozStorageTransaction transaction(aConnection,
|
||||
|
@ -24005,11 +23976,6 @@ CreateFileOp::DoDatabaseWork()
|
|||
|
||||
AUTO_PROFILER_LABEL("CreateFileOp::DoDatabaseWork", DOM);
|
||||
|
||||
if (NS_WARN_IF(IndexedDatabaseManager::InLowDiskSpaceMode())) {
|
||||
NS_WARNING("Refusing to create file because disk space is low!");
|
||||
return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(QuotaManager::IsShuttingDown()) || !OperationMayProceed()) {
|
||||
IDB_REPORT_INTERNAL_ERR();
|
||||
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
|
@ -24148,10 +24114,6 @@ CreateObjectStoreOp::DoDatabaseWork(DatabaseConnection* aConnection)
|
|||
|
||||
AUTO_PROFILER_LABEL("CreateObjectStoreOp::DoDatabaseWork", DOM);
|
||||
|
||||
if (NS_WARN_IF(IndexedDatabaseManager::InLowDiskSpaceMode())) {
|
||||
return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
// Make sure that we're not creating an object store with the same name as
|
||||
|
@ -24471,10 +24433,6 @@ RenameObjectStoreOp::DoDatabaseWork(DatabaseConnection* aConnection)
|
|||
|
||||
AUTO_PROFILER_LABEL("RenameObjectStoreOp::DoDatabaseWork", DOM);
|
||||
|
||||
if (NS_WARN_IF(IndexedDatabaseManager::InLowDiskSpaceMode())) {
|
||||
return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
// Make sure that we're not renaming an object store with the same name as
|
||||
|
@ -24562,7 +24520,6 @@ CreateIndexOp::InsertDataFromObjectStore(DatabaseConnection* aConnection)
|
|||
{
|
||||
MOZ_ASSERT(aConnection);
|
||||
aConnection->AssertIsOnConnectionThread();
|
||||
MOZ_ASSERT(!IndexedDatabaseManager::InLowDiskSpaceMode());
|
||||
MOZ_ASSERT(mMaybeUniqueIndexTable);
|
||||
|
||||
AUTO_PROFILER_LABEL("CreateIndexOp::InsertDataFromObjectStore", DOM);
|
||||
|
@ -24601,7 +24558,6 @@ CreateIndexOp::InsertDataFromObjectStoreInternal(
|
|||
{
|
||||
MOZ_ASSERT(aConnection);
|
||||
aConnection->AssertIsOnConnectionThread();
|
||||
MOZ_ASSERT(!IndexedDatabaseManager::InLowDiskSpaceMode());
|
||||
MOZ_ASSERT(mMaybeUniqueIndexTable);
|
||||
|
||||
DebugOnly<void*> storageConnection = aConnection->GetStorageConnection();
|
||||
|
@ -24657,10 +24613,6 @@ CreateIndexOp::DoDatabaseWork(DatabaseConnection* aConnection)
|
|||
|
||||
AUTO_PROFILER_LABEL("CreateIndexOp::DoDatabaseWork", DOM);
|
||||
|
||||
if (NS_WARN_IF(IndexedDatabaseManager::InLowDiskSpaceMode())) {
|
||||
return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
// Make sure that we're not creating an index with the same name and object
|
||||
|
@ -25425,10 +25377,6 @@ RenameIndexOp::DoDatabaseWork(DatabaseConnection* aConnection)
|
|||
|
||||
AUTO_PROFILER_LABEL("RenameIndexOp::DoDatabaseWork", DOM);
|
||||
|
||||
if (NS_WARN_IF(IndexedDatabaseManager::InLowDiskSpaceMode())) {
|
||||
return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
// Make sure that we're not renaming an index with the same name as another
|
||||
|
@ -25926,10 +25874,6 @@ ObjectStoreAddOrPutRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
|
|||
|
||||
AUTO_PROFILER_LABEL("ObjectStoreAddOrPutRequestOp::DoDatabaseWork", DOM);
|
||||
|
||||
if (NS_WARN_IF(IndexedDatabaseManager::InLowDiskSpaceMode())) {
|
||||
return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
|
||||
}
|
||||
|
||||
DatabaseConnection::AutoSavepoint autoSave;
|
||||
nsresult rv = autoSave.Start(Transaction());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
|
|
|
@ -8,11 +8,9 @@
|
|||
|
||||
#include "chrome/common/ipc_channel.h" // for IPC::Channel::kMaximumMessageSize
|
||||
#include "nsIConsoleService.h"
|
||||
#include "nsIDiskSpaceWatcher.h"
|
||||
#include "nsIDOMWindow.h"
|
||||
#include "nsIEventTarget.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIScriptError.h"
|
||||
#include "nsIScriptGlobalObject.h"
|
||||
|
||||
|
@ -63,11 +61,6 @@
|
|||
|
||||
#define IDB_STR "indexedDB"
|
||||
|
||||
// The two possible values for the data argument when receiving the disk space
|
||||
// observer notification.
|
||||
#define LOW_DISK_SPACE_DATA_FULL "full"
|
||||
#define LOW_DISK_SPACE_DATA_FREE "free"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace indexedDB {
|
||||
|
@ -313,8 +306,6 @@ Atomic<IndexedDatabaseManager::LoggingMode>
|
|||
IndexedDatabaseManager::sLoggingMode(
|
||||
IndexedDatabaseManager::Logging_Disabled);
|
||||
|
||||
mozilla::Atomic<bool> IndexedDatabaseManager::sLowDiskSpaceMode(false);
|
||||
|
||||
// static
|
||||
IndexedDatabaseManager*
|
||||
IndexedDatabaseManager::GetOrCreate()
|
||||
|
@ -329,24 +320,6 @@ IndexedDatabaseManager::GetOrCreate()
|
|||
if (!gDBManager) {
|
||||
sIsMainProcess = XRE_IsParentProcess();
|
||||
|
||||
if (sIsMainProcess && Preferences::GetBool("disk_space_watcher.enabled", false)) {
|
||||
// See if we're starting up in low disk space conditions.
|
||||
nsCOMPtr<nsIDiskSpaceWatcher> watcher =
|
||||
do_GetService(DISKSPACEWATCHER_CONTRACTID);
|
||||
if (watcher) {
|
||||
bool isDiskFull;
|
||||
if (NS_SUCCEEDED(watcher->GetIsDiskFull(&isDiskFull))) {
|
||||
sLowDiskSpaceMode = isDiskFull;
|
||||
}
|
||||
else {
|
||||
NS_WARNING("GetIsDiskFull failed!");
|
||||
}
|
||||
}
|
||||
else {
|
||||
NS_WARNING("No disk space watcher component available!");
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<IndexedDatabaseManager> instance(new IndexedDatabaseManager());
|
||||
|
||||
nsresult rv = instance->Init();
|
||||
|
@ -380,13 +353,6 @@ IndexedDatabaseManager::Init()
|
|||
// During Init() we can't yet call IsMainProcess(), just check sIsMainProcess
|
||||
// directly.
|
||||
if (sIsMainProcess) {
|
||||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
||||
NS_ENSURE_STATE(obs);
|
||||
|
||||
nsresult rv =
|
||||
obs->AddObserver(this, DISKSPACEWATCHER_OBSERVER_TOPIC, false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mDeleteTimer = NS_NewTimer();
|
||||
NS_ENSURE_STATE(mDeleteTimer);
|
||||
|
||||
|
@ -694,16 +660,6 @@ IndexedDatabaseManager::IsMainProcess()
|
|||
return sIsMainProcess;
|
||||
}
|
||||
|
||||
//static
|
||||
bool
|
||||
IndexedDatabaseManager::InLowDiskSpaceMode()
|
||||
{
|
||||
NS_ASSERTION(gDBManager,
|
||||
"InLowDiskSpaceMode() called before indexedDB has been "
|
||||
"initialized!");
|
||||
return sLowDiskSpaceMode;
|
||||
}
|
||||
|
||||
// static
|
||||
IndexedDatabaseManager::LoggingMode
|
||||
IndexedDatabaseManager::GetLoggingMode()
|
||||
|
@ -1109,37 +1065,7 @@ IndexedDatabaseManager::GetLocale()
|
|||
|
||||
NS_IMPL_ADDREF(IndexedDatabaseManager)
|
||||
NS_IMPL_RELEASE_WITH_DESTROY(IndexedDatabaseManager, Destroy())
|
||||
NS_IMPL_QUERY_INTERFACE(IndexedDatabaseManager, nsIObserver, nsITimerCallback,
|
||||
nsINamed)
|
||||
|
||||
NS_IMETHODIMP
|
||||
IndexedDatabaseManager::Observe(nsISupports* aSubject, const char* aTopic,
|
||||
const char16_t* aData)
|
||||
{
|
||||
NS_ASSERTION(IsMainProcess(), "Wrong process!");
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
if (!strcmp(aTopic, DISKSPACEWATCHER_OBSERVER_TOPIC)) {
|
||||
NS_ASSERTION(aData, "No data?!");
|
||||
|
||||
const nsDependentString data(aData);
|
||||
|
||||
if (data.EqualsLiteral(LOW_DISK_SPACE_DATA_FULL)) {
|
||||
sLowDiskSpaceMode = true;
|
||||
}
|
||||
else if (data.EqualsLiteral(LOW_DISK_SPACE_DATA_FREE)) {
|
||||
sLowDiskSpaceMode = false;
|
||||
}
|
||||
else {
|
||||
MOZ_ASSERT_UNREACHABLE("Unknown data value!");
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MOZ_ASSERT_UNREACHABLE("Unknown topic!");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
NS_IMPL_QUERY_INTERFACE(IndexedDatabaseManager, nsITimerCallback, nsINamed)
|
||||
|
||||
NS_IMETHODIMP
|
||||
IndexedDatabaseManager::Notify(nsITimer* aTimer)
|
||||
|
|
|
@ -7,8 +7,6 @@
|
|||
#ifndef mozilla_dom_indexeddatabasemanager_h__
|
||||
#define mozilla_dom_indexeddatabasemanager_h__
|
||||
|
||||
#include "nsIObserver.h"
|
||||
|
||||
#include "js/TypeDecls.h"
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/dom/quota/PersistenceType.h"
|
||||
|
@ -44,8 +42,7 @@ class FileManagerInfo;
|
|||
} // namespace indexedDB
|
||||
|
||||
class IndexedDatabaseManager final
|
||||
: public nsIObserver
|
||||
, public nsITimerCallback
|
||||
: public nsITimerCallback
|
||||
, public nsINamed
|
||||
{
|
||||
typedef mozilla::dom::quota::PersistenceType PersistenceType;
|
||||
|
@ -64,7 +61,6 @@ public:
|
|||
};
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
NS_DECL_NSITIMERCALLBACK
|
||||
NS_DECL_NSINAMED
|
||||
|
||||
|
@ -89,16 +85,6 @@ public:
|
|||
}
|
||||
#endif
|
||||
|
||||
static bool
|
||||
InLowDiskSpaceMode()
|
||||
#ifdef DEBUG
|
||||
;
|
||||
#else
|
||||
{
|
||||
return !!sLowDiskSpaceMode;
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool
|
||||
InTestingMode();
|
||||
|
||||
|
@ -247,7 +233,6 @@ private:
|
|||
static bool sFullSynchronousMode;
|
||||
static LazyLogModule sLoggingModule;
|
||||
static Atomic<LoggingMode> sLoggingMode;
|
||||
static mozilla::Atomic<bool> sLowDiskSpaceMode;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -212,10 +212,6 @@ if (!window.runTest) {
|
|||
|
||||
function finishTest()
|
||||
{
|
||||
SpecialPowers.notifyObserversInParentProcess(null,
|
||||
"disk-space-watcher",
|
||||
"free");
|
||||
|
||||
SimpleTest.executeSoon(function() {
|
||||
clearAllDatabases(function() { SimpleTest.finish(); });
|
||||
});
|
||||
|
|
|
@ -65,7 +65,6 @@ support-files =
|
|||
unit/test_locale_aware_indexes.js
|
||||
unit/test_locale_aware_index_getAll.js
|
||||
unit/test_locale_aware_index_getAllObjects.js
|
||||
unit/test_lowDiskSpace.js
|
||||
unit/test_maximal_serialized_object_size.js
|
||||
unit/test_multientry.js
|
||||
unit/test_names_sorted.js
|
||||
|
@ -210,8 +209,6 @@ skip-if = true
|
|||
[test_key_requirements.html]
|
||||
[test_keys.html]
|
||||
[test_leaving_page.html]
|
||||
[test_lowDiskSpace.html]
|
||||
skip-if = toolkit == 'android' && debug # Bug 1328321
|
||||
[test_maximal_serialized_object_size.html]
|
||||
[test_message_manager_ipc.html]
|
||||
# This test is only supposed to run in the main process.
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>Indexed Database Low Disk Space Test</title>
|
||||
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
|
||||
<script type="text/javascript" src="unit/test_lowDiskSpace.js"></script>
|
||||
<script type="text/javascript" src="helpers.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="runTest();"></body>
|
||||
|
||||
</html>
|
|
@ -1,753 +0,0 @@
|
|||
/**
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
var disableWorkerTest = "This test uses SpecialPowers";
|
||||
|
||||
var self = this;
|
||||
|
||||
var testGenerator = testSteps();
|
||||
|
||||
function* testSteps()
|
||||
{
|
||||
const dbName = self.window ? window.location.pathname : "test_lowDiskSpace";
|
||||
const dbVersion = 1;
|
||||
|
||||
const objectStoreName = "foo";
|
||||
const objectStoreOptions = { keyPath: "foo" };
|
||||
|
||||
const indexName = "bar";
|
||||
const indexOptions = { unique: true };
|
||||
|
||||
const dbData = [
|
||||
{ foo: 0, bar: 0 },
|
||||
{ foo: 1, bar: 10 },
|
||||
{ foo: 2, bar: 20 },
|
||||
{ foo: 3, bar: 30 },
|
||||
{ foo: 4, bar: 40 },
|
||||
{ foo: 5, bar: 50 },
|
||||
{ foo: 6, bar: 60 },
|
||||
{ foo: 7, bar: 70 },
|
||||
{ foo: 8, bar: 80 },
|
||||
{ foo: 9, bar: 90 }
|
||||
];
|
||||
|
||||
let lowDiskMode = false;
|
||||
function setLowDiskMode(val) {
|
||||
let data = val ? "full" : "free";
|
||||
|
||||
if (val == lowDiskMode) {
|
||||
info("Low disk mode is: " + data);
|
||||
}
|
||||
else {
|
||||
info("Changing low disk mode to: " + data);
|
||||
SpecialPowers.notifyObserversInParentProcess(null, "disk-space-watcher",
|
||||
data);
|
||||
lowDiskMode = val;
|
||||
}
|
||||
}
|
||||
|
||||
{ // Make sure opening works from the beginning.
|
||||
info("Test 1");
|
||||
|
||||
setLowDiskMode(false);
|
||||
|
||||
let request = indexedDB.open(dbName, dbVersion);
|
||||
request.onerror = errorHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
let event = yield undefined;
|
||||
|
||||
is(event.type, "success", "Opened database without setting low disk mode");
|
||||
|
||||
let db = event.target.result;
|
||||
db.close();
|
||||
}
|
||||
|
||||
{ // Make sure delete works in low disk mode.
|
||||
info("Test 2");
|
||||
|
||||
setLowDiskMode(true);
|
||||
|
||||
let request = indexedDB.deleteDatabase(dbName);
|
||||
request.onerror = errorHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
let event = yield undefined;
|
||||
|
||||
is(event.type, "success", "Deleted database after setting low disk mode");
|
||||
}
|
||||
|
||||
{ // Make sure creating a db in low disk mode fails.
|
||||
info("Test 3");
|
||||
|
||||
setLowDiskMode(true);
|
||||
|
||||
let request = indexedDB.open(dbName, dbVersion);
|
||||
request.onerror = expectedErrorHandler("QuotaExceededError");
|
||||
request.onupgradeneeded = unexpectedSuccessHandler;
|
||||
request.onsuccess = unexpectedSuccessHandler;
|
||||
let event = yield undefined;
|
||||
|
||||
is(event.type, "error", "Didn't create new database in low disk mode");
|
||||
}
|
||||
|
||||
{ // Make sure opening an already-existing db in low disk mode succeeds.
|
||||
info("Test 4");
|
||||
|
||||
setLowDiskMode(false);
|
||||
|
||||
let request = indexedDB.open(dbName, dbVersion);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = grabEventAndContinueHandler;
|
||||
request.onsuccess = unexpectedSuccessHandler;
|
||||
let event = yield undefined;
|
||||
|
||||
is(event.type, "upgradeneeded", "Upgrading database");
|
||||
|
||||
let db = event.target.result;
|
||||
db.onerror = errorHandler;
|
||||
|
||||
request.onupgradeneeded = unexpectedSuccessHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield undefined;
|
||||
|
||||
is(event.type, "success", "Created database");
|
||||
ok(event.target.result === db, "Got the same database");
|
||||
|
||||
db.close();
|
||||
|
||||
setLowDiskMode(true);
|
||||
|
||||
request = indexedDB.open(dbName);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = unexpectedSuccessHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield undefined;
|
||||
|
||||
is(event.type, "success", "Opened existing database in low disk mode");
|
||||
|
||||
db = event.target.result;
|
||||
db.close();
|
||||
}
|
||||
|
||||
{ // Make sure upgrading an already-existing db in low disk mode succeeds.
|
||||
info("Test 5");
|
||||
|
||||
setLowDiskMode(true);
|
||||
|
||||
let request = indexedDB.open(dbName, dbVersion + 1);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = grabEventAndContinueHandler;
|
||||
request.onsuccess = unexpectedSuccessHandler;
|
||||
|
||||
let event = yield undefined;
|
||||
|
||||
is(event.type, "upgradeneeded", "Upgrading database");
|
||||
|
||||
let db = event.target.result;
|
||||
db.onerror = errorHandler;
|
||||
|
||||
request.onupgradeneeded = unexpectedSuccessHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield undefined;
|
||||
|
||||
is(event.type, "success", "Created database");
|
||||
ok(event.target.result === db, "Got the same database");
|
||||
|
||||
db.close();
|
||||
}
|
||||
|
||||
{ // Make sure creating objectStores in low disk mode fails.
|
||||
info("Test 6");
|
||||
|
||||
setLowDiskMode(true);
|
||||
|
||||
let request = indexedDB.open(dbName, dbVersion + 2);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = grabEventAndContinueHandler;
|
||||
request.onsuccess = unexpectedSuccessHandler;
|
||||
|
||||
let event = yield undefined;
|
||||
|
||||
is(event.type, "upgradeneeded", "Upgrading database");
|
||||
|
||||
let db = event.target.result;
|
||||
db.onerror = errorHandler;
|
||||
|
||||
let txn = event.target.transaction;
|
||||
txn.onerror = expectedErrorHandler("AbortError");
|
||||
txn.onabort = grabEventAndContinueHandler;
|
||||
|
||||
db.createObjectStore(objectStoreName, objectStoreOptions);
|
||||
|
||||
request.onupgradeneeded = unexpectedSuccessHandler;
|
||||
event = yield undefined;
|
||||
|
||||
is(event.type, "abort", "Got correct event type");
|
||||
is(event.target.error.name, "QuotaExceededError", "Got correct error type");
|
||||
|
||||
request.onerror = expectedErrorHandler("AbortError");
|
||||
event = yield undefined;
|
||||
}
|
||||
|
||||
{ // Make sure creating indexes in low disk mode fails.
|
||||
info("Test 7");
|
||||
|
||||
setLowDiskMode(false);
|
||||
|
||||
let request = indexedDB.open(dbName, dbVersion + 2);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = grabEventAndContinueHandler;
|
||||
request.onsuccess = unexpectedSuccessHandler;
|
||||
|
||||
let event = yield undefined;
|
||||
|
||||
is(event.type, "upgradeneeded", "Upgrading database");
|
||||
|
||||
let db = event.target.result;
|
||||
db.onerror = errorHandler;
|
||||
|
||||
let objectStore = db.createObjectStore(objectStoreName, objectStoreOptions);
|
||||
|
||||
request.onupgradeneeded = unexpectedSuccessHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield undefined;
|
||||
|
||||
is(event.type, "success", "Upgraded database");
|
||||
ok(event.target.result === db, "Got the same database");
|
||||
|
||||
db.close();
|
||||
|
||||
setLowDiskMode(true);
|
||||
|
||||
request = indexedDB.open(dbName, dbVersion + 3);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = grabEventAndContinueHandler;
|
||||
request.onsuccess = unexpectedSuccessHandler;
|
||||
event = yield undefined;
|
||||
|
||||
is(event.type, "upgradeneeded", "Upgrading database");
|
||||
|
||||
db = event.target.result;
|
||||
db.onerror = errorHandler;
|
||||
let txn = event.target.transaction;
|
||||
txn.onerror = expectedErrorHandler("AbortError");
|
||||
txn.onabort = grabEventAndContinueHandler;
|
||||
|
||||
objectStore = event.target.transaction.objectStore(objectStoreName);
|
||||
objectStore.createIndex(indexName, indexName, indexOptions);
|
||||
|
||||
request.onupgradeneeded = unexpectedSuccessHandler;
|
||||
event = yield undefined;
|
||||
|
||||
is(event.type, "abort", "Got correct event type");
|
||||
is(event.target.error.name, "QuotaExceededError", "Got correct error type");
|
||||
|
||||
request.onerror = expectedErrorHandler("AbortError");
|
||||
event = yield undefined;
|
||||
}
|
||||
|
||||
{ // Make sure deleting indexes in low disk mode succeeds.
|
||||
info("Test 8");
|
||||
|
||||
setLowDiskMode(false);
|
||||
|
||||
let request = indexedDB.open(dbName, dbVersion + 3);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = grabEventAndContinueHandler;
|
||||
request.onsuccess = unexpectedSuccessHandler;
|
||||
|
||||
let event = yield undefined;
|
||||
|
||||
is(event.type, "upgradeneeded", "Upgrading database");
|
||||
|
||||
let db = event.target.result;
|
||||
db.onerror = errorHandler;
|
||||
|
||||
let objectStore = event.target.transaction.objectStore(objectStoreName);
|
||||
objectStore.createIndex(indexName, indexName, indexOptions);
|
||||
|
||||
request.onupgradeneeded = unexpectedSuccessHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield undefined;
|
||||
|
||||
is(event.type, "success", "Upgraded database");
|
||||
ok(event.target.result === db, "Got the same database");
|
||||
|
||||
db.close();
|
||||
|
||||
setLowDiskMode(true);
|
||||
|
||||
request = indexedDB.open(dbName, dbVersion + 4);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = grabEventAndContinueHandler;
|
||||
request.onsuccess = unexpectedSuccessHandler;
|
||||
event = yield undefined;
|
||||
|
||||
is(event.type, "upgradeneeded", "Upgrading database");
|
||||
|
||||
db = event.target.result;
|
||||
db.onerror = errorHandler;
|
||||
|
||||
objectStore = event.target.transaction.objectStore(objectStoreName);
|
||||
objectStore.deleteIndex(indexName);
|
||||
|
||||
request.onupgradeneeded = unexpectedSuccessHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield undefined;
|
||||
|
||||
is(event.type, "success", "Upgraded database");
|
||||
ok(event.target.result === db, "Got the same database");
|
||||
|
||||
db.close();
|
||||
}
|
||||
|
||||
{ // Make sure deleting objectStores in low disk mode succeeds.
|
||||
info("Test 9");
|
||||
|
||||
setLowDiskMode(true);
|
||||
|
||||
let request = indexedDB.open(dbName, dbVersion + 5);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = grabEventAndContinueHandler;
|
||||
request.onsuccess = unexpectedSuccessHandler;
|
||||
|
||||
let event = yield undefined;
|
||||
|
||||
is(event.type, "upgradeneeded", "Upgrading database");
|
||||
|
||||
let db = event.target.result;
|
||||
db.onerror = errorHandler;
|
||||
|
||||
db.deleteObjectStore(objectStoreName);
|
||||
|
||||
request.onupgradeneeded = unexpectedSuccessHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield undefined;
|
||||
|
||||
is(event.type, "success", "Upgraded database");
|
||||
ok(event.target.result === db, "Got the same database");
|
||||
|
||||
db.close();
|
||||
|
||||
// Reset everything.
|
||||
indexedDB.deleteDatabase(dbName);
|
||||
}
|
||||
|
||||
|
||||
{ // Add data that the rest of the tests will use.
|
||||
info("Adding test data");
|
||||
|
||||
setLowDiskMode(false);
|
||||
|
||||
let request = indexedDB.open(dbName, dbVersion);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = grabEventAndContinueHandler;
|
||||
request.onsuccess = unexpectedSuccessHandler;
|
||||
let event = yield undefined;
|
||||
|
||||
is(event.type, "upgradeneeded", "Upgrading database");
|
||||
|
||||
let db = event.target.result;
|
||||
db.onerror = errorHandler;
|
||||
|
||||
let objectStore = db.createObjectStore(objectStoreName, objectStoreOptions);
|
||||
objectStore.createIndex(indexName, indexName, indexOptions);
|
||||
|
||||
for (let data of dbData) {
|
||||
objectStore.add(data);
|
||||
}
|
||||
|
||||
request.onupgradeneeded = unexpectedSuccessHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield undefined;
|
||||
|
||||
is(event.type, "success", "Upgraded database");
|
||||
ok(event.target.result === db, "Got the same database");
|
||||
|
||||
db.close();
|
||||
}
|
||||
|
||||
{ // Make sure read operations in readonly transactions succeed in low disk
|
||||
// mode.
|
||||
info("Test 10");
|
||||
|
||||
setLowDiskMode(true);
|
||||
|
||||
let request = indexedDB.open(dbName, dbVersion);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = unexpectedSuccessHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
let event = yield undefined;
|
||||
|
||||
let db = event.target.result;
|
||||
db.onerror = errorHandler;
|
||||
|
||||
let transaction = db.transaction(objectStoreName);
|
||||
let objectStore = transaction.objectStore(objectStoreName);
|
||||
let index = objectStore.index(indexName);
|
||||
|
||||
let data = dbData[0];
|
||||
|
||||
let requestCounter = new RequestCounter();
|
||||
|
||||
objectStore.get(data.foo).onsuccess = requestCounter.handler();
|
||||
objectStore.mozGetAll().onsuccess = requestCounter.handler();
|
||||
objectStore.count().onsuccess = requestCounter.handler();
|
||||
index.get(data.bar).onsuccess = requestCounter.handler();
|
||||
index.mozGetAll().onsuccess = requestCounter.handler();
|
||||
index.getKey(data.bar).onsuccess = requestCounter.handler();
|
||||
index.mozGetAllKeys().onsuccess = requestCounter.handler();
|
||||
index.count().onsuccess = requestCounter.handler();
|
||||
|
||||
let objectStoreDataCount = 0;
|
||||
|
||||
request = objectStore.openCursor();
|
||||
request.onsuccess = function(event) {
|
||||
let cursor = event.target.result;
|
||||
if (cursor) {
|
||||
objectStoreDataCount++;
|
||||
objectStoreDataCount % 2 ? cursor.continue() : cursor.advance(1);
|
||||
}
|
||||
else {
|
||||
is(objectStoreDataCount, dbData.length, "Saw all data");
|
||||
requestCounter.decr();
|
||||
}
|
||||
};
|
||||
requestCounter.incr();
|
||||
|
||||
let indexDataCount = 0;
|
||||
|
||||
request = index.openCursor();
|
||||
request.onsuccess = function(event) {
|
||||
let cursor = event.target.result;
|
||||
if (cursor) {
|
||||
indexDataCount++;
|
||||
indexDataCount % 2 ? cursor.continue() : cursor.advance(1);
|
||||
}
|
||||
else {
|
||||
is(indexDataCount, dbData.length, "Saw all data");
|
||||
requestCounter.decr();
|
||||
}
|
||||
};
|
||||
requestCounter.incr();
|
||||
|
||||
let indexKeyDataCount = 0;
|
||||
|
||||
request = index.openCursor();
|
||||
request.onsuccess = function(event) {
|
||||
let cursor = event.target.result;
|
||||
if (cursor) {
|
||||
indexKeyDataCount++;
|
||||
indexKeyDataCount % 2 ? cursor.continue() : cursor.advance(1);
|
||||
}
|
||||
else {
|
||||
is(indexKeyDataCount, dbData.length, "Saw all data");
|
||||
requestCounter.decr();
|
||||
}
|
||||
};
|
||||
requestCounter.incr();
|
||||
|
||||
// Wait for all requests.
|
||||
yield undefined;
|
||||
|
||||
transaction.oncomplete = grabEventAndContinueHandler;
|
||||
event = yield undefined;
|
||||
|
||||
is(event.type, "complete", "Transaction succeeded");
|
||||
|
||||
db.close();
|
||||
}
|
||||
|
||||
{ // Make sure read operations in readwrite transactions succeed in low disk
|
||||
// mode.
|
||||
info("Test 11");
|
||||
|
||||
setLowDiskMode(true);
|
||||
|
||||
let request = indexedDB.open(dbName, dbVersion);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = unexpectedSuccessHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
let event = yield undefined;
|
||||
|
||||
let db = event.target.result;
|
||||
db.onerror = errorHandler;
|
||||
|
||||
let transaction = db.transaction(objectStoreName, "readwrite");
|
||||
let objectStore = transaction.objectStore(objectStoreName);
|
||||
let index = objectStore.index(indexName);
|
||||
|
||||
let data = dbData[0];
|
||||
|
||||
let requestCounter = new RequestCounter();
|
||||
|
||||
objectStore.get(data.foo).onsuccess = requestCounter.handler();
|
||||
objectStore.mozGetAll().onsuccess = requestCounter.handler();
|
||||
objectStore.count().onsuccess = requestCounter.handler();
|
||||
index.get(data.bar).onsuccess = requestCounter.handler();
|
||||
index.mozGetAll().onsuccess = requestCounter.handler();
|
||||
index.getKey(data.bar).onsuccess = requestCounter.handler();
|
||||
index.mozGetAllKeys().onsuccess = requestCounter.handler();
|
||||
index.count().onsuccess = requestCounter.handler();
|
||||
|
||||
let objectStoreDataCount = 0;
|
||||
|
||||
request = objectStore.openCursor();
|
||||
request.onsuccess = function(event) {
|
||||
let cursor = event.target.result;
|
||||
if (cursor) {
|
||||
objectStoreDataCount++;
|
||||
objectStoreDataCount % 2 ? cursor.continue() : cursor.advance(1);
|
||||
}
|
||||
else {
|
||||
is(objectStoreDataCount, dbData.length, "Saw all data");
|
||||
requestCounter.decr();
|
||||
}
|
||||
};
|
||||
requestCounter.incr();
|
||||
|
||||
let indexDataCount = 0;
|
||||
|
||||
request = index.openCursor();
|
||||
request.onsuccess = function(event) {
|
||||
let cursor = event.target.result;
|
||||
if (cursor) {
|
||||
indexDataCount++;
|
||||
indexDataCount % 2 ? cursor.continue() : cursor.advance(1);
|
||||
}
|
||||
else {
|
||||
is(indexDataCount, dbData.length, "Saw all data");
|
||||
requestCounter.decr();
|
||||
}
|
||||
};
|
||||
requestCounter.incr();
|
||||
|
||||
let indexKeyDataCount = 0;
|
||||
|
||||
request = index.openCursor();
|
||||
request.onsuccess = function(event) {
|
||||
let cursor = event.target.result;
|
||||
if (cursor) {
|
||||
indexKeyDataCount++;
|
||||
indexKeyDataCount % 2 ? cursor.continue() : cursor.advance(1);
|
||||
}
|
||||
else {
|
||||
is(indexKeyDataCount, dbData.length, "Saw all data");
|
||||
requestCounter.decr();
|
||||
}
|
||||
};
|
||||
requestCounter.incr();
|
||||
|
||||
// Wait for all requests.
|
||||
yield undefined;
|
||||
|
||||
transaction.oncomplete = grabEventAndContinueHandler;
|
||||
event = yield undefined;
|
||||
|
||||
is(event.type, "complete", "Transaction succeeded");
|
||||
|
||||
db.close();
|
||||
}
|
||||
|
||||
{ // Make sure write operations in readwrite transactions fail in low disk
|
||||
// mode.
|
||||
info("Test 12");
|
||||
|
||||
setLowDiskMode(true);
|
||||
|
||||
let request = indexedDB.open(dbName, dbVersion);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = unexpectedSuccessHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
let event = yield undefined;
|
||||
|
||||
let db = event.target.result;
|
||||
db.onerror = errorHandler;
|
||||
|
||||
let transaction = db.transaction(objectStoreName, "readwrite");
|
||||
let objectStore = transaction.objectStore(objectStoreName);
|
||||
let index = objectStore.index(indexName);
|
||||
|
||||
let data = dbData[0];
|
||||
let newData = { foo: 999, bar: 999 };
|
||||
|
||||
let requestCounter = new RequestCounter();
|
||||
|
||||
objectStore.add(newData).onerror = requestCounter.errorHandler();
|
||||
objectStore.put(newData).onerror = requestCounter.errorHandler();
|
||||
|
||||
objectStore.get(data.foo).onsuccess = requestCounter.handler();
|
||||
objectStore.mozGetAll().onsuccess = requestCounter.handler();
|
||||
objectStore.count().onsuccess = requestCounter.handler();
|
||||
index.get(data.bar).onsuccess = requestCounter.handler();
|
||||
index.mozGetAll().onsuccess = requestCounter.handler();
|
||||
index.getKey(data.bar).onsuccess = requestCounter.handler();
|
||||
index.mozGetAllKeys().onsuccess = requestCounter.handler();
|
||||
index.count().onsuccess = requestCounter.handler();
|
||||
|
||||
let objectStoreDataCount = 0;
|
||||
|
||||
request = objectStore.openCursor();
|
||||
request.onsuccess = function(event) {
|
||||
let cursor = event.target.result;
|
||||
if (cursor) {
|
||||
objectStoreDataCount++;
|
||||
cursor.update(cursor.value).onerror = requestCounter.errorHandler();
|
||||
objectStoreDataCount % 2 ? cursor.continue() : cursor.advance(1);
|
||||
}
|
||||
else {
|
||||
is(objectStoreDataCount, dbData.length, "Saw all data");
|
||||
requestCounter.decr();
|
||||
}
|
||||
};
|
||||
requestCounter.incr();
|
||||
|
||||
let indexDataCount = 0;
|
||||
|
||||
request = index.openCursor();
|
||||
request.onsuccess = function(event) {
|
||||
let cursor = event.target.result;
|
||||
if (cursor) {
|
||||
indexDataCount++;
|
||||
cursor.update(cursor.value).onerror = requestCounter.errorHandler();
|
||||
indexDataCount % 2 ? cursor.continue() : cursor.advance(1);
|
||||
}
|
||||
else {
|
||||
is(indexDataCount, dbData.length, "Saw all data");
|
||||
requestCounter.decr();
|
||||
}
|
||||
};
|
||||
requestCounter.incr();
|
||||
|
||||
let indexKeyDataCount = 0;
|
||||
|
||||
request = index.openCursor();
|
||||
request.onsuccess = function(event) {
|
||||
let cursor = event.target.result;
|
||||
if (cursor) {
|
||||
indexKeyDataCount++;
|
||||
cursor.update(cursor.value).onerror = requestCounter.errorHandler();
|
||||
indexKeyDataCount % 2 ? cursor.continue() : cursor.advance(1);
|
||||
}
|
||||
else {
|
||||
is(indexKeyDataCount, dbData.length, "Saw all data");
|
||||
requestCounter.decr();
|
||||
}
|
||||
};
|
||||
requestCounter.incr();
|
||||
|
||||
// Wait for all requests.
|
||||
yield undefined;
|
||||
|
||||
transaction.oncomplete = grabEventAndContinueHandler;
|
||||
event = yield undefined;
|
||||
|
||||
is(event.type, "complete", "Transaction succeeded");
|
||||
|
||||
db.close();
|
||||
}
|
||||
|
||||
{ // Make sure deleting operations in readwrite transactions succeed in low
|
||||
// disk mode.
|
||||
info("Test 13");
|
||||
|
||||
setLowDiskMode(true);
|
||||
|
||||
let request = indexedDB.open(dbName, dbVersion);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = unexpectedSuccessHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
let event = yield undefined;
|
||||
|
||||
let db = event.target.result;
|
||||
db.onerror = errorHandler;
|
||||
|
||||
let transaction = db.transaction(objectStoreName, "readwrite");
|
||||
let objectStore = transaction.objectStore(objectStoreName);
|
||||
let index = objectStore.index(indexName);
|
||||
|
||||
let dataIndex = 0;
|
||||
let data = dbData[dataIndex++];
|
||||
|
||||
let requestCounter = new RequestCounter();
|
||||
|
||||
objectStore.delete(data.foo).onsuccess = requestCounter.handler();
|
||||
|
||||
objectStore.openCursor().onsuccess = function(event) {
|
||||
let cursor = event.target.result;
|
||||
if (cursor) {
|
||||
cursor.delete().onsuccess = requestCounter.handler();
|
||||
}
|
||||
requestCounter.decr();
|
||||
};
|
||||
requestCounter.incr();
|
||||
|
||||
index.openCursor(null, "prev").onsuccess = function(event) {
|
||||
let cursor = event.target.result;
|
||||
if (cursor) {
|
||||
cursor.delete().onsuccess = requestCounter.handler();
|
||||
}
|
||||
requestCounter.decr();
|
||||
};
|
||||
requestCounter.incr();
|
||||
|
||||
yield undefined;
|
||||
|
||||
objectStore.count().onsuccess = grabEventAndContinueHandler;
|
||||
event = yield undefined;
|
||||
|
||||
is(event.target.result, dbData.length - 3, "Actually deleted something");
|
||||
|
||||
objectStore.clear();
|
||||
objectStore.count().onsuccess = grabEventAndContinueHandler;
|
||||
event = yield undefined;
|
||||
|
||||
is(event.target.result, 0, "Actually cleared");
|
||||
|
||||
transaction.oncomplete = grabEventAndContinueHandler;
|
||||
event = yield undefined;
|
||||
|
||||
is(event.type, "complete", "Transaction succeeded");
|
||||
|
||||
db.close();
|
||||
}
|
||||
|
||||
finishTest();
|
||||
}
|
||||
|
||||
function RequestCounter(expectedType) {
|
||||
this._counter = 0;
|
||||
}
|
||||
RequestCounter.prototype = {
|
||||
incr() {
|
||||
this._counter++;
|
||||
},
|
||||
|
||||
decr() {
|
||||
if (!--this._counter) {
|
||||
continueToNextStepSync();
|
||||
}
|
||||
},
|
||||
|
||||
handler(type, preventDefault) {
|
||||
this.incr();
|
||||
return event => {
|
||||
is(event.type, type || "success", "Correct type");
|
||||
this.decr();
|
||||
};
|
||||
},
|
||||
|
||||
errorHandler(eventType, errorName) {
|
||||
this.incr();
|
||||
return event => {
|
||||
is(event.type, eventType || "error", "Correct type");
|
||||
is(event.target.error.name, errorName || "QuotaExceededError",
|
||||
"Correct error name");
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
this.decr();
|
||||
};
|
||||
}
|
||||
};
|
|
@ -61,9 +61,6 @@ function finishTest()
|
|||
if (SpecialPowers.isMainProcess()) {
|
||||
resetExperimental();
|
||||
resetTesting();
|
||||
|
||||
SpecialPowers.notifyObserversInParentProcess(null, "disk-space-watcher",
|
||||
"free");
|
||||
}
|
||||
|
||||
SpecialPowers.removeFiles();
|
||||
|
|
|
@ -47,7 +47,6 @@ skip-if = toolkit == 'android'
|
|||
[test_invalidate.js]
|
||||
# disabled for the moment.
|
||||
skip-if = true
|
||||
[test_lowDiskSpace.js]
|
||||
[test_maximal_serialized_object_size.js]
|
||||
[test_metadata2Restore.js]
|
||||
[test_metadataRestore.js]
|
||||
|
|
|
@ -69,20 +69,20 @@ public:
|
|||
{
|
||||
}
|
||||
|
||||
cdm::Status Decrypt(const cdm::InputBuffer& aEncryptedBuffer,
|
||||
cdm::Status Decrypt(const cdm::InputBuffer_1& aEncryptedBuffer,
|
||||
cdm::DecryptedBlock* aDecryptedBuffer) override
|
||||
{
|
||||
return cdm::Status::kDecodeError;
|
||||
}
|
||||
|
||||
cdm::Status InitializeAudioDecoder(
|
||||
const cdm::AudioDecoderConfig& aAudioDecoderConfig) override
|
||||
const cdm::AudioDecoderConfig_1& aAudioDecoderConfig) override
|
||||
{
|
||||
return cdm::Status::kDecodeError;
|
||||
}
|
||||
|
||||
cdm::Status InitializeVideoDecoder(
|
||||
const cdm::VideoDecoderConfig& aVideoDecoderConfig) override
|
||||
const cdm::VideoDecoderConfig_1& aVideoDecoderConfig) override
|
||||
{
|
||||
return cdm::Status::kDecodeError;
|
||||
}
|
||||
|
@ -95,15 +95,14 @@ public:
|
|||
{
|
||||
}
|
||||
|
||||
cdm::Status DecryptAndDecodeFrame(
|
||||
const cdm::InputBuffer& aEncryptedBuffer,
|
||||
cdm::VideoFrame* aVideoFrame) override
|
||||
cdm::Status DecryptAndDecodeFrame(const cdm::InputBuffer_1& aEncryptedBuffer,
|
||||
cdm::VideoFrame* aVideoFrame) override
|
||||
{
|
||||
return cdm::Status::kDecodeError;
|
||||
}
|
||||
|
||||
cdm::Status DecryptAndDecodeSamples(
|
||||
const cdm::InputBuffer& aEncryptedBuffer,
|
||||
const cdm::InputBuffer_1& aEncryptedBuffer,
|
||||
cdm::AudioFrames* aAudioFrame) override
|
||||
{
|
||||
return cdm::Status::kDecodeError;
|
||||
|
|
|
@ -54,8 +54,8 @@ void*
|
|||
ChromiumCdmHost(int aHostInterfaceVersion, void* aUserData)
|
||||
{
|
||||
GMP_LOG("ChromiumCdmHostFunc(%d, %p)", aHostInterfaceVersion, aUserData);
|
||||
if (aHostInterfaceVersion != cdm::Host_8::kVersion &&
|
||||
aHostInterfaceVersion != cdm::Host_9::kVersion) {
|
||||
if (aHostInterfaceVersion != cdm::Host_9::kVersion &&
|
||||
aHostInterfaceVersion != cdm::Host_10::kVersion) {
|
||||
return nullptr;
|
||||
}
|
||||
return aUserData;
|
||||
|
@ -122,9 +122,9 @@ ChromiumCDMAdapter::GMPGetAPI(const char* aAPIName,
|
|||
aPluginAPI,
|
||||
aDecryptorId,
|
||||
this);
|
||||
bool isCDM9 = !strcmp(aAPIName, CHROMIUM_CDM_API);
|
||||
bool isCDM8 = !strcmp(aAPIName, CHROMIUM_CDM_API_BACKWARD_COMPAT);
|
||||
if (isCDM8 || isCDM9) {
|
||||
bool isCDM10 = !strcmp(aAPIName, CHROMIUM_CDM_API);
|
||||
bool isCDM9 = !strcmp(aAPIName, CHROMIUM_CDM_API_BACKWARD_COMPAT);
|
||||
if (isCDM9 || isCDM10) {
|
||||
auto create = reinterpret_cast<decltype(::CreateCdmInstance)*>(
|
||||
PR_FindFunctionSymbol(mLib, "CreateCdmInstance"));
|
||||
if (!create) {
|
||||
|
@ -138,8 +138,8 @@ ChromiumCDMAdapter::GMPGetAPI(const char* aAPIName,
|
|||
return GMPGenericErr;
|
||||
}
|
||||
|
||||
int version = isCDM8 ? cdm::ContentDecryptionModule_8::kVersion :
|
||||
cdm::ContentDecryptionModule_9::kVersion;
|
||||
int version = isCDM9 ? cdm::ContentDecryptionModule_9::kVersion
|
||||
: cdm::ContentDecryptionModule_10::kVersion;
|
||||
void* cdm =
|
||||
create(version,
|
||||
kEMEKeySystemWidevine.get(),
|
||||
|
@ -183,10 +183,10 @@ ChromiumCDMAdapter::Supports(int32_t aModuleVersion,
|
|||
int32_t aHostVersion)
|
||||
{
|
||||
return aModuleVersion == CDM_MODULE_VERSION &&
|
||||
(aInterfaceVersion == cdm::ContentDecryptionModule_8::kVersion ||
|
||||
aInterfaceVersion == cdm::ContentDecryptionModule_9::kVersion) &&
|
||||
(aHostVersion == cdm::Host_8::kVersion ||
|
||||
aHostVersion == cdm::Host_9::kVersion);
|
||||
(aInterfaceVersion == cdm::ContentDecryptionModule_9::kVersion ||
|
||||
aInterfaceVersion == cdm::ContentDecryptionModule_10::kVersion) &&
|
||||
(aHostVersion == cdm::Host_9::kVersion ||
|
||||
aHostVersion == cdm::Host_10::kVersion);
|
||||
}
|
||||
|
||||
#ifdef XP_WIN
|
||||
|
|
|
@ -43,10 +43,6 @@ public:
|
|||
|
||||
virtual void SessionClosed(const nsCString& aSessionId) = 0;
|
||||
|
||||
virtual void LegacySessionError(const nsCString& aSessionId,
|
||||
nsresult aError,
|
||||
uint32_t aSystemCode,
|
||||
const nsCString& aMessage) = 0;
|
||||
virtual void Terminated() = 0;
|
||||
|
||||
virtual void Shutdown() = 0;
|
||||
|
|
|
@ -55,13 +55,13 @@ ChromiumCDMCallbackProxy::ResolvePromise(uint32_t aPromiseId)
|
|||
|
||||
void
|
||||
ChromiumCDMCallbackProxy::RejectPromise(uint32_t aPromiseId,
|
||||
nsresult aError,
|
||||
nsresult aException,
|
||||
const nsCString& aErrorMessage)
|
||||
{
|
||||
DispatchToMainThread("ChromiumCDMProxy::RejectPromise",
|
||||
&ChromiumCDMProxy::RejectPromise,
|
||||
aPromiseId,
|
||||
aError,
|
||||
aException,
|
||||
aErrorMessage);
|
||||
}
|
||||
|
||||
|
@ -76,6 +76,8 @@ ToDOMMessageType(uint32_t aMessageType)
|
|||
return dom::MediaKeyMessageType::License_renewal;
|
||||
case cdm::kLicenseRelease:
|
||||
return dom::MediaKeyMessageType::License_release;
|
||||
case cdm::kIndividualizationRequest:
|
||||
return dom::MediaKeyMessageType::Individualization_request;
|
||||
}
|
||||
MOZ_ASSERT_UNREACHABLE("Invalid cdm::MessageType enum value.");
|
||||
return dom::MediaKeyMessageType::License_request;
|
||||
|
@ -167,20 +169,6 @@ ChromiumCDMCallbackProxy::SessionClosed(const nsCString& aSessionId)
|
|||
NS_ConvertUTF8toUTF16(aSessionId));
|
||||
}
|
||||
|
||||
void
|
||||
ChromiumCDMCallbackProxy::LegacySessionError(const nsCString& aSessionId,
|
||||
nsresult aError,
|
||||
uint32_t aSystemCode,
|
||||
const nsCString& aMessage)
|
||||
{
|
||||
DispatchToMainThread("ChromiumCDMProxy::OnSessionError",
|
||||
&ChromiumCDMProxy::OnSessionError ,
|
||||
NS_ConvertUTF8toUTF16(aSessionId),
|
||||
aError,
|
||||
aSystemCode,
|
||||
NS_ConvertUTF8toUTF16(aMessage));
|
||||
}
|
||||
|
||||
void
|
||||
ChromiumCDMCallbackProxy::Terminated()
|
||||
{
|
||||
|
|
|
@ -33,7 +33,7 @@ public:
|
|||
void ResolvePromise(uint32_t aPromiseId) override;
|
||||
|
||||
void RejectPromise(uint32_t aPromiseId,
|
||||
nsresult aError,
|
||||
nsresult aException,
|
||||
const nsCString& aErrorMessage) override;
|
||||
|
||||
void SessionMessage(const nsACString& aSessionId,
|
||||
|
@ -48,10 +48,6 @@ public:
|
|||
|
||||
void SessionClosed(const nsCString& aSessionId) override;
|
||||
|
||||
void LegacySessionError(const nsCString& aSessionId,
|
||||
nsresult aError,
|
||||
uint32_t aSystemCode,
|
||||
const nsCString& aMessage) override;
|
||||
void Terminated() override;
|
||||
|
||||
void Shutdown() override;
|
||||
|
|
|
@ -28,7 +28,8 @@ ChromiumCDMChild::ChromiumCDMChild(GMPContentChild* aPlugin)
|
|||
}
|
||||
|
||||
void
|
||||
ChromiumCDMChild::Init(cdm::ContentDecryptionModule_9* aCDM, const nsCString& aStorageId)
|
||||
ChromiumCDMChild::Init(cdm::ContentDecryptionModule_10* aCDM,
|
||||
const nsCString& aStorageId)
|
||||
{
|
||||
MOZ_ASSERT(IsOnMessageLoopThread());
|
||||
mCDM = aCDM;
|
||||
|
@ -224,7 +225,6 @@ ChromiumCDMChild::CallOnMessageLoopThread(const char* const aName,
|
|||
}
|
||||
}
|
||||
|
||||
// cdm::Host_9 interface
|
||||
void
|
||||
ChromiumCDMChild::OnResolveKeyStatusPromise(uint32_t aPromiseId,
|
||||
cdm::KeyStatus aKeyStatus) {
|
||||
|
@ -284,46 +284,6 @@ void ChromiumCDMChild::OnResolvePromise(uint32_t aPromiseId)
|
|||
aPromiseId);
|
||||
}
|
||||
|
||||
// Align with spec, the Exceptions used by CDM to reject promises .
|
||||
// https://w3c.github.io/encrypted-media/#exceptions
|
||||
cdm::Exception
|
||||
ConvertCDMErrorToCDMException(cdm::Error error) {
|
||||
switch (error) {
|
||||
case cdm::kNotSupportedError:
|
||||
return cdm::Exception::kExceptionNotSupportedError;
|
||||
case cdm::kInvalidStateError:
|
||||
return cdm::Exception::kExceptionInvalidStateError;
|
||||
case cdm::kInvalidAccessError:
|
||||
return cdm::Exception::kExceptionTypeError;
|
||||
case cdm::kQuotaExceededError:
|
||||
return cdm::Exception::kExceptionQuotaExceededError;
|
||||
|
||||
// cdm8 only error
|
||||
case cdm::kUnknownError:
|
||||
case cdm::kClientError:
|
||||
case cdm::kOutputError:
|
||||
break;
|
||||
}
|
||||
|
||||
return cdm::Exception::kExceptionInvalidStateError;
|
||||
}
|
||||
|
||||
// cdm::Host_8 only interface
|
||||
void
|
||||
ChromiumCDMChild::OnRejectPromise(uint32_t aPromiseId,
|
||||
cdm::Error aError,
|
||||
uint32_t aSystemCode,
|
||||
const char* aErrorMessage,
|
||||
uint32_t aErrorMessageSize)
|
||||
{
|
||||
OnRejectPromise(aPromiseId,
|
||||
ConvertCDMErrorToCDMException(aError),
|
||||
aSystemCode,
|
||||
aErrorMessage,
|
||||
aErrorMessageSize);
|
||||
}
|
||||
|
||||
// cdm::Host_9 interface
|
||||
void
|
||||
ChromiumCDMChild::OnRejectPromise(uint32_t aPromiseId,
|
||||
cdm::Exception aException,
|
||||
|
@ -345,20 +305,6 @@ ChromiumCDMChild::OnRejectPromise(uint32_t aPromiseId,
|
|||
nsCString(aErrorMessage, aErrorMessageSize));
|
||||
}
|
||||
|
||||
// cdm::Host_8 only interface
|
||||
void
|
||||
ChromiumCDMChild::OnSessionMessage(const char* aSessionId,
|
||||
uint32_t aSessionIdSize,
|
||||
cdm::MessageType aMessageType,
|
||||
const char* aMessage,
|
||||
uint32_t aMessageSize,
|
||||
const char* aLegacyDestinationUrl,
|
||||
uint32_t aLegacyDestinationUrlLength)
|
||||
{
|
||||
OnSessionMessage(aSessionId, aSessionIdSize, aMessageType, aMessage, aMessageSize);
|
||||
}
|
||||
|
||||
// cdm::Host_9 interface
|
||||
void
|
||||
ChromiumCDMChild::OnSessionMessage(const char* aSessionId,
|
||||
uint32_t aSessionIdSize,
|
||||
|
@ -446,27 +392,6 @@ ChromiumCDMChild::OnSessionClosed(const char* aSessionId,
|
|||
nsCString(aSessionId, aSessionIdSize));
|
||||
}
|
||||
|
||||
void
|
||||
ChromiumCDMChild::OnLegacySessionError(const char* aSessionId,
|
||||
uint32_t aSessionIdLength,
|
||||
cdm::Error aError,
|
||||
uint32_t aSystemCode,
|
||||
const char* aErrorMessage,
|
||||
uint32_t aErrorMessageLength)
|
||||
{
|
||||
GMP_LOG("ChromiumCDMChild::OnLegacySessionError(sid=%s, error=%" PRIu32
|
||||
" msg='%s')",
|
||||
aSessionId,
|
||||
aError,
|
||||
aErrorMessage);
|
||||
CallOnMessageLoopThread("gmp::ChromiumCDMChild::OnLegacySessionError",
|
||||
&ChromiumCDMChild::SendOnLegacySessionError,
|
||||
nsCString(aSessionId, aSessionIdLength),
|
||||
ConvertCDMErrorToCDMException(aError),
|
||||
aSystemCode,
|
||||
nsCString(aErrorMessage, aErrorMessageLength));
|
||||
}
|
||||
|
||||
cdm::FileIO*
|
||||
ChromiumCDMChild::CreateFileIO(cdm::FileIOClient * aClient)
|
||||
{
|
||||
|
@ -532,12 +457,15 @@ ChromiumCDMChild::RecvInit(const bool& aAllowDistinctiveIdentifier,
|
|||
const bool& aAllowPersistentState)
|
||||
{
|
||||
MOZ_ASSERT(IsOnMessageLoopThread());
|
||||
GMP_LOG("ChromiumCDMChild::RecvInit(distinctiveId=%d, persistentState=%d)",
|
||||
aAllowDistinctiveIdentifier,
|
||||
aAllowPersistentState);
|
||||
GMP_LOG("ChromiumCDMChild::RecvInit(distinctiveId=%s, persistentState=%s)",
|
||||
aAllowDistinctiveIdentifier ? "true" : "false",
|
||||
aAllowPersistentState ? "true" : "false");
|
||||
mPersistentStateAllowed = aAllowPersistentState;
|
||||
if (mCDM) {
|
||||
mCDM->Initialize(aAllowDistinctiveIdentifier, aAllowPersistentState);
|
||||
mCDM->Initialize(aAllowDistinctiveIdentifier,
|
||||
aAllowPersistentState,
|
||||
// We do not yet support hardware secure codecs
|
||||
false);
|
||||
}
|
||||
return IPC_OK();
|
||||
}
|
||||
|
@ -703,8 +631,6 @@ ChromiumCDMChild::RecvGetStatusForPolicy(const uint32_t& aPromiseId,
|
|||
cdm::Policy policy;
|
||||
// We didn't check the return value of ToCDMHdcpVersion.
|
||||
// Let CDM to handle the cdm::HdcpVersion::kHdcpVersionNone case.
|
||||
// ChromiumCDM8BackwardsCompat::GetStatusForPolicy will reject the promise
|
||||
// since this API is only supported by CDM version 9.
|
||||
// CDM will callback by OnResolveKeyStatusPromise when it successfully executes.
|
||||
policy.min_hdcp_version = ToCDMHdcpVersion(aMinHdcpVersion);
|
||||
mCDM->GetStatusForPolicy(aPromiseId, policy);
|
||||
|
@ -712,15 +638,35 @@ ChromiumCDMChild::RecvGetStatusForPolicy(const uint32_t& aPromiseId,
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
static cdm::EncryptionScheme
|
||||
ConvertToCdmEncryptionScheme(const GMPEncryptionScheme& aEncryptionScheme)
|
||||
{
|
||||
switch (aEncryptionScheme) {
|
||||
case GMPEncryptionScheme::kGMPEncryptionNone:
|
||||
return cdm::EncryptionScheme::kUnencrypted;
|
||||
case GMPEncryptionScheme::kGMPEncryptionCenc:
|
||||
return cdm::EncryptionScheme::kCenc;
|
||||
case GMPEncryptionScheme::kGMPEncryptionCbcs:
|
||||
return cdm::EncryptionScheme::kCbcs;
|
||||
default:
|
||||
MOZ_ASSERT_UNREACHABLE("Cannot convert invalid encryption scheme!");
|
||||
return cdm::EncryptionScheme::kUnencrypted;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
InitInputBuffer(const CDMInputBuffer& aBuffer,
|
||||
nsTArray<cdm::SubsampleEntry>& aSubSamples,
|
||||
cdm::InputBuffer& aInputBuffer)
|
||||
cdm::InputBuffer_2& aInputBuffer)
|
||||
{
|
||||
aInputBuffer.data = aBuffer.mData().get<uint8_t>();
|
||||
aInputBuffer.data_size = aBuffer.mData().Size<uint8_t>();
|
||||
|
||||
if (aBuffer.mIsEncrypted()) {
|
||||
if (aBuffer.mEncryptionScheme() > GMPEncryptionScheme::kGMPEncryptionNone) {
|
||||
// Cbcs is not yet supported, so we expect only cenc if the buffer us
|
||||
// encrypted
|
||||
MOZ_ASSERT(aBuffer.mEncryptionScheme() ==
|
||||
GMPEncryptionScheme::kGMPEncryptionCenc);
|
||||
aInputBuffer.key_id = aBuffer.mKeyId().Elements();
|
||||
aInputBuffer.key_id_size = aBuffer.mKeyId().Length();
|
||||
|
||||
|
@ -729,11 +675,13 @@ InitInputBuffer(const CDMInputBuffer& aBuffer,
|
|||
|
||||
aSubSamples.SetCapacity(aBuffer.mClearBytes().Length());
|
||||
for (size_t i = 0; i < aBuffer.mCipherBytes().Length(); i++) {
|
||||
aSubSamples.AppendElement(cdm::SubsampleEntry(aBuffer.mClearBytes()[i],
|
||||
aBuffer.mCipherBytes()[i]));
|
||||
aSubSamples.AppendElement(cdm::SubsampleEntry{
|
||||
aBuffer.mClearBytes()[i], aBuffer.mCipherBytes()[i] });
|
||||
}
|
||||
aInputBuffer.subsamples = aSubSamples.Elements();
|
||||
aInputBuffer.num_subsamples = aSubSamples.Length();
|
||||
aInputBuffer.encryption_scheme =
|
||||
ConvertToCdmEncryptionScheme(aBuffer.mEncryptionScheme());
|
||||
}
|
||||
aInputBuffer.timestamp = aBuffer.mTimestamp();
|
||||
}
|
||||
|
@ -790,7 +738,7 @@ ChromiumCDMChild::RecvDecrypt(const uint32_t& aId,
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
cdm::InputBuffer input;
|
||||
cdm::InputBuffer_2 input = {};
|
||||
nsTArray<cdm::SubsampleEntry> subsamples;
|
||||
InitInputBuffer(aBuffer, subsamples, input);
|
||||
|
||||
|
@ -831,17 +779,17 @@ ChromiumCDMChild::RecvInitializeVideoDecoder(
|
|||
Unused << SendOnDecoderInitDone(cdm::kInitializationError);
|
||||
return IPC_OK();
|
||||
}
|
||||
cdm::VideoDecoderConfig config;
|
||||
config.codec =
|
||||
static_cast<cdm::VideoDecoderConfig::VideoCodec>(aConfig.mCodec());
|
||||
config.profile =
|
||||
static_cast<cdm::VideoDecoderConfig::VideoCodecProfile>(aConfig.mProfile());
|
||||
cdm::VideoDecoderConfig_2 config = {};
|
||||
config.codec = static_cast<cdm::VideoCodec>(aConfig.mCodec());
|
||||
config.profile = static_cast<cdm::VideoCodecProfile>(aConfig.mProfile());
|
||||
config.format = static_cast<cdm::VideoFormat>(aConfig.mFormat());
|
||||
config.coded_size =
|
||||
mCodedSize = { aConfig.mImageWidth(), aConfig.mImageHeight() };
|
||||
nsTArray<uint8_t> extraData(aConfig.mExtraData());
|
||||
config.extra_data = extraData.Elements();
|
||||
config.extra_data_size = extraData.Length();
|
||||
config.encryption_scheme =
|
||||
ConvertToCdmEncryptionScheme(aConfig.mEncryptionScheme());
|
||||
cdm::Status status = mCDM->InitializeVideoDecoder(config);
|
||||
GMP_LOG("ChromiumCDMChild::RecvInitializeVideoDecoder() status=%u", status);
|
||||
Unused << SendOnDecoderInitDone(status);
|
||||
|
@ -901,7 +849,7 @@ ChromiumCDMChild::RecvDecryptAndDecodeFrame(const CDMInputBuffer& aBuffer)
|
|||
// on output.
|
||||
mFrameDurations.Insert(aBuffer.mTimestamp(), aBuffer.mDuration());
|
||||
|
||||
cdm::InputBuffer input;
|
||||
cdm::InputBuffer_2 input = {};
|
||||
nsTArray<cdm::SubsampleEntry> subsamples;
|
||||
InitInputBuffer(aBuffer, subsamples, input);
|
||||
|
||||
|
@ -988,7 +936,7 @@ ChromiumCDMChild::RecvDrain()
|
|||
return IPC_OK();
|
||||
}
|
||||
WidevineVideoFrame frame;
|
||||
cdm::InputBuffer sample;
|
||||
cdm::InputBuffer_2 sample = {};
|
||||
cdm::Status rv = mCDM->DecryptAndDecodeFrame(sample, &frame);
|
||||
GMP_LOG("ChromiumCDMChild::RecvDrain(); DecryptAndDecodeFrame() rv=%d", rv);
|
||||
if (rv == cdm::kSuccess) {
|
||||
|
|
|
@ -16,37 +16,35 @@ namespace gmp {
|
|||
|
||||
class GMPContentChild;
|
||||
|
||||
class ChromiumCDMChild : public PChromiumCDMChild
|
||||
, public cdm::Host_8
|
||||
, public cdm::Host_9
|
||||
class ChromiumCDMChild
|
||||
: public PChromiumCDMChild
|
||||
, public cdm::Host_9
|
||||
, public cdm::Host_10
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ChromiumCDMChild);
|
||||
|
||||
explicit ChromiumCDMChild(GMPContentChild* aPlugin);
|
||||
|
||||
void Init(cdm::ContentDecryptionModule_9* aCDM, const nsCString& aStorageId);
|
||||
void Init(cdm::ContentDecryptionModule_10* aCDM, const nsCString& aStorageId);
|
||||
|
||||
void TimerExpired(void* aContext);
|
||||
|
||||
// cdm::Host_9 implementation
|
||||
// Shared cdm::Host_9 and cdm::Host10 implementation
|
||||
cdm::Buffer* Allocate(uint32_t aCapacity) override;
|
||||
void SetTimer(int64_t aDelayMs, void* aContext) override;
|
||||
cdm::Time GetCurrentWallTime() override;
|
||||
// cdm::Host_9 interface
|
||||
void OnResolveKeyStatusPromise(uint32_t aPromiseId,
|
||||
cdm::KeyStatus aKeyStatus) override;
|
||||
void OnResolveNewSessionPromise(uint32_t aPromiseId,
|
||||
const char* aSessionId,
|
||||
uint32_t aSessionIdSize) override;
|
||||
void OnResolvePromise(uint32_t aPromiseId) override;
|
||||
// cdm::Host_9 interface
|
||||
void OnRejectPromise(uint32_t aPromiseId,
|
||||
cdm::Exception aException,
|
||||
uint32_t aSystemCode,
|
||||
const char* aErrorMessage,
|
||||
uint32_t aErrorMessageSize) override;
|
||||
// cdm::Host_9 interface
|
||||
void OnSessionMessage(const char* aSessionId,
|
||||
uint32_t aSessionIdSize,
|
||||
cdm::MessageType aMessageType,
|
||||
|
@ -70,29 +68,12 @@ public:
|
|||
void QueryOutputProtectionStatus() override {}
|
||||
void OnDeferredInitializationDone(cdm::StreamType aStreamType,
|
||||
cdm::Status aDecoderStatus) override {}
|
||||
// cdm::Host_9 interface
|
||||
void RequestStorageId(uint32_t aVersion) override;
|
||||
cdm::FileIO* CreateFileIO(cdm::FileIOClient* aClient) override;
|
||||
|
||||
// cdm::Host_8 implementation
|
||||
void OnSessionMessage(const char* aSessionId,
|
||||
uint32_t aSessionIdSize,
|
||||
cdm::MessageType aMessageType,
|
||||
const char* aMessage,
|
||||
uint32_t aMessageSize,
|
||||
const char* aLegacyDestinationUrl,
|
||||
uint32_t aLegacyDestinationUrlLength) override;
|
||||
void OnRejectPromise(uint32_t aPromiseId,
|
||||
cdm::Error aError,
|
||||
uint32_t aSystemCode,
|
||||
const char* aErrorMessage,
|
||||
uint32_t aErrorMessageSize) override;
|
||||
void OnLegacySessionError(const char* aSessionId,
|
||||
uint32_t aSessionIdLength,
|
||||
cdm::Error aError,
|
||||
uint32_t aSystemCode,
|
||||
const char* aErrorMessage,
|
||||
uint32_t aErrorMessageLength) override;
|
||||
// End shared cdm::Host_9 and cdm::Host10 implementation
|
||||
// cdm::Host_10 specific
|
||||
void OnInitialized(bool success) override {}
|
||||
// end cdm::Host_10 specific
|
||||
|
||||
void GiveBuffer(ipc::Shmem&& aBuffer);
|
||||
|
||||
|
@ -150,13 +131,13 @@ protected:
|
|||
void CallOnMessageLoopThread(const char* const, MethodType, ParamType&&...);
|
||||
|
||||
GMPContentChild* mPlugin = nullptr;
|
||||
cdm::ContentDecryptionModule_9* mCDM = nullptr;
|
||||
cdm::ContentDecryptionModule_10* mCDM = nullptr;
|
||||
|
||||
typedef SimpleMap<uint64_t> DurationMap;
|
||||
DurationMap mFrameDurations;
|
||||
nsTArray<uint32_t> mLoadSessionPromiseIds;
|
||||
|
||||
cdm::Size mCodedSize;
|
||||
cdm::Size mCodedSize = { 0, 0 };
|
||||
nsTArray<ipc::Shmem> mBuffers;
|
||||
|
||||
bool mDecoderInitialized = false;
|
||||
|
|
|
@ -66,7 +66,8 @@ ChromiumCDMParent::Init(ChromiumCDMCallback* aCDMCallback,
|
|||
mCDMCallback = aCDMCallback;
|
||||
mMainThread = aMainThread;
|
||||
|
||||
if (SendInit(aAllowDistinctiveIdentifier, aAllowPersistentState)) {
|
||||
if (SendInit(aAllowDistinctiveIdentifier,
|
||||
aAllowPersistentState)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -253,7 +254,14 @@ ChromiumCDMParent::InitCDMInputBuffer(gmp::CDMInputBuffer& aBuffer,
|
|||
aSample->mDuration.ToMicroseconds(),
|
||||
crypto.mPlainSizes,
|
||||
crypto.mEncryptedSizes,
|
||||
crypto.mValid);
|
||||
crypto.mValid
|
||||
? GMPEncryptionScheme::kGMPEncryptionCenc
|
||||
: GMPEncryptionScheme::kGMPEncryptionNone);
|
||||
MOZ_ASSERT(
|
||||
aBuffer.mEncryptionScheme() == GMPEncryptionScheme::kGMPEncryptionNone ||
|
||||
aBuffer.mEncryptionScheme() == GMPEncryptionScheme::kGMPEncryptionCenc,
|
||||
"aBuffer should use either no encryption or cenc, other kinds are not yet "
|
||||
"supported");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -406,7 +414,7 @@ ChromiumCDMParent::RecvOnResolvePromise(const uint32_t& aPromiseId)
|
|||
|
||||
void
|
||||
ChromiumCDMParent::RejectPromise(uint32_t aPromiseId,
|
||||
nsresult aError,
|
||||
nsresult aException,
|
||||
const nsCString& aErrorMessage)
|
||||
{
|
||||
GMP_LOG(
|
||||
|
@ -417,7 +425,7 @@ ChromiumCDMParent::RejectPromise(uint32_t aPromiseId,
|
|||
return;
|
||||
}
|
||||
|
||||
mCDMCallback->RejectPromise(aPromiseId, aError, aErrorMessage);
|
||||
mCDMCallback->RejectPromise(aPromiseId, aException, aErrorMessage);
|
||||
}
|
||||
|
||||
static nsresult
|
||||
|
@ -439,11 +447,11 @@ ToNsresult(uint32_t aException)
|
|||
|
||||
ipc::IPCResult
|
||||
ChromiumCDMParent::RecvOnRejectPromise(const uint32_t& aPromiseId,
|
||||
const uint32_t& aError,
|
||||
const uint32_t& aException,
|
||||
const uint32_t& aSystemCode,
|
||||
const nsCString& aErrorMessage)
|
||||
{
|
||||
RejectPromise(aPromiseId, ToNsresult(aError), aErrorMessage);
|
||||
RejectPromise(aPromiseId, ToNsresult(aException), aErrorMessage);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
|
@ -504,26 +512,10 @@ ChromiumCDMParent::RecvOnSessionClosed(const nsCString& aSessionId)
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
ipc::IPCResult
|
||||
ChromiumCDMParent::RecvOnLegacySessionError(const nsCString& aSessionId,
|
||||
const uint32_t& aError,
|
||||
const uint32_t& aSystemCode,
|
||||
const nsCString& aMessage)
|
||||
{
|
||||
GMP_LOG("ChromiumCDMParent::RecvOnLegacySessionError(this=%p)", this);
|
||||
if (!mCDMCallback || mIsShutdown) {
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mCDMCallback->LegacySessionError(
|
||||
aSessionId, ToNsresult(aError), aSystemCode, aMessage);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
DecryptStatus
|
||||
ToDecryptStatus(uint32_t aError)
|
||||
ToDecryptStatus(uint32_t aStatus)
|
||||
{
|
||||
switch (static_cast<cdm::Status>(aError)) {
|
||||
switch (static_cast<cdm::Status>(aStatus)) {
|
||||
case cdm::kSuccess:
|
||||
return DecryptStatus::Ok;
|
||||
case cdm::kNoKey:
|
||||
|
@ -941,12 +933,11 @@ ChromiumCDMParent::InitializeVideoDecoder(
|
|||
__func__);
|
||||
}
|
||||
|
||||
mMaxRefFrames =
|
||||
(aConfig.mCodec() == cdm::VideoDecoderConfig::kCodecH264)
|
||||
? H264::HasSPS(aInfo.mExtraData)
|
||||
? H264::ComputeMaxRefFrames(aInfo.mExtraData)
|
||||
: 16
|
||||
: 0;
|
||||
mMaxRefFrames = (aConfig.mCodec() == cdm::VideoCodec::kCodecH264)
|
||||
? H264::HasSPS(aInfo.mExtraData)
|
||||
? H264::ComputeMaxRefFrames(aInfo.mExtraData)
|
||||
: 16
|
||||
: 0;
|
||||
|
||||
mVideoDecoderInitialized = true;
|
||||
mImageContainer = aImageContainer;
|
||||
|
|
|
@ -118,10 +118,6 @@ protected:
|
|||
const nsCString& aSessionId,
|
||||
const double& aSecondsSinceEpoch) override;
|
||||
ipc::IPCResult RecvOnSessionClosed(const nsCString& aSessionId) override;
|
||||
ipc::IPCResult RecvOnLegacySessionError(const nsCString& aSessionId,
|
||||
const uint32_t& aError,
|
||||
const uint32_t& aSystemCode,
|
||||
const nsCString& aMessage) override;
|
||||
ipc::IPCResult RecvDecrypted(const uint32_t& aId,
|
||||
const uint32_t& aStatus,
|
||||
ipc::Shmem&& aData) override;
|
||||
|
|
|
@ -129,41 +129,37 @@ GMPContentChild::RecvPGMPVideoEncoderConstructor(PGMPVideoEncoderChild* aActor)
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
|
||||
class ChromiumCDM8BackwardsCompat : public cdm::ContentDecryptionModule_9
|
||||
// Convert CDM10 calls to CDM9 calls, massage args where needed
|
||||
class ChromiumCDM9BackwardsCompat : public cdm::ContentDecryptionModule_10
|
||||
{
|
||||
public:
|
||||
explicit ChromiumCDM8BackwardsCompat(
|
||||
cdm::Host_9* aHost,
|
||||
cdm::ContentDecryptionModule_8* aCDM)
|
||||
: mCDM(aCDM),
|
||||
mHost(aHost) { }
|
||||
explicit ChromiumCDM9BackwardsCompat(cdm::Host_10* aHost,
|
||||
cdm::ContentDecryptionModule_9* aCDM)
|
||||
: mCDM(aCDM)
|
||||
, mHost(aHost)
|
||||
{
|
||||
}
|
||||
|
||||
void Initialize(bool aAllowDistinctiveIdentifier,
|
||||
bool aAllowPersistentState) override
|
||||
bool aAllowPersistentState,
|
||||
bool /* aUseHardwareSecureCodec */) override
|
||||
{
|
||||
// aUseHardwareSecureCodec is not used by CDM9
|
||||
mCDM->Initialize(aAllowDistinctiveIdentifier, aAllowPersistentState);
|
||||
}
|
||||
|
||||
void GetStatusForPolicy(uint32_t aPromiseId,
|
||||
const cdm::Policy& policy) override
|
||||
{
|
||||
mCDM->GetStatusForPolicy(aPromiseId, policy);
|
||||
}
|
||||
|
||||
void SetServerCertificate(uint32_t aPromiseId,
|
||||
const uint8_t* aServerCertificateData,
|
||||
uint32_t aServerCertificateDataSize) override
|
||||
{
|
||||
mCDM->SetServerCertificate(aPromiseId,
|
||||
aServerCertificateData,
|
||||
aServerCertificateDataSize);
|
||||
}
|
||||
|
||||
void GetStatusForPolicy(uint32_t aPromiseId,
|
||||
const cdm::Policy& policy) override
|
||||
{
|
||||
//Only support on version 9 CDM, so rejecting the promise.
|
||||
mHost->OnRejectPromise(aPromiseId,
|
||||
cdm::Exception::kExceptionNotSupportedError,
|
||||
0,
|
||||
nullptr,
|
||||
0);
|
||||
|
||||
mCDM->SetServerCertificate(
|
||||
aPromiseId, aServerCertificateData, aServerCertificateDataSize);
|
||||
}
|
||||
|
||||
void CreateSessionAndGenerateRequest(uint32_t aPromiseId,
|
||||
|
@ -190,11 +186,8 @@ public:
|
|||
const uint8_t* aResponse,
|
||||
uint32_t aResponseSize) override
|
||||
{
|
||||
mCDM->UpdateSession(aPromiseId,
|
||||
aSessionId,
|
||||
aSessionIdSize,
|
||||
aResponse,
|
||||
aResponseSize);
|
||||
mCDM->UpdateSession(
|
||||
aPromiseId, aSessionId, aSessionIdSize, aResponse, aResponseSize);
|
||||
}
|
||||
|
||||
void CloseSession(uint32_t aPromiseId,
|
||||
|
@ -213,22 +206,40 @@ public:
|
|||
|
||||
void TimerExpired(void* aContext) override { mCDM->TimerExpired(aContext); }
|
||||
|
||||
cdm::Status Decrypt(const cdm::InputBuffer& aEncryptedBuffer,
|
||||
cdm::Status Decrypt(const cdm::InputBuffer_2& aEncryptedBuffer,
|
||||
cdm::DecryptedBlock* aDecryptedBuffer) override
|
||||
{
|
||||
return mCDM->Decrypt(aEncryptedBuffer, aDecryptedBuffer);
|
||||
// Handle possible encryption mismatch
|
||||
if (!IsEncryptionSchemeSupported(aEncryptedBuffer.encryption_scheme)) {
|
||||
return cdm::Status::kDecryptError;
|
||||
}
|
||||
|
||||
return mCDM->Decrypt(ConvertToInputBuffer_1(aEncryptedBuffer),
|
||||
aDecryptedBuffer);
|
||||
}
|
||||
|
||||
cdm::Status InitializeAudioDecoder(
|
||||
const cdm::AudioDecoderConfig& aAudioDecoderConfig) override
|
||||
const cdm::AudioDecoderConfig_2& aAudioDecoderConfig) override
|
||||
{
|
||||
return mCDM->InitializeAudioDecoder(aAudioDecoderConfig);
|
||||
// Handle possible encryption mismatch
|
||||
if (!IsEncryptionSchemeSupported(aAudioDecoderConfig.encryption_scheme)) {
|
||||
return cdm::Status::kInitializationError;
|
||||
}
|
||||
|
||||
return mCDM->InitializeAudioDecoder(
|
||||
ConverToAudioDecoderConfig_1(aAudioDecoderConfig));
|
||||
}
|
||||
|
||||
cdm::Status InitializeVideoDecoder(
|
||||
const cdm::VideoDecoderConfig& aVideoDecoderConfig) override
|
||||
const cdm::VideoDecoderConfig_2& aVideoDecoderConfig) override
|
||||
{
|
||||
return mCDM->InitializeVideoDecoder(aVideoDecoderConfig);
|
||||
// Handle possible encryption mismatch
|
||||
if (!IsEncryptionSchemeSupported(aVideoDecoderConfig.encryption_scheme)) {
|
||||
return cdm::Status::kInitializationError;
|
||||
}
|
||||
|
||||
return mCDM->InitializeVideoDecoder(
|
||||
ConvertToVideoDecoderConfig_1(aVideoDecoderConfig));
|
||||
}
|
||||
|
||||
void DeinitializeDecoder(cdm::StreamType aDecoderType) override
|
||||
|
@ -241,20 +252,33 @@ public:
|
|||
mCDM->ResetDecoder(aDecoderType);
|
||||
}
|
||||
|
||||
cdm::Status DecryptAndDecodeFrame(const cdm::InputBuffer& aEncryptedBuffer,
|
||||
cdm::Status DecryptAndDecodeFrame(const cdm::InputBuffer_2& aEncryptedBuffer,
|
||||
cdm::VideoFrame* aVideoFrame) override
|
||||
{
|
||||
return mCDM->DecryptAndDecodeFrame(aEncryptedBuffer, aVideoFrame);
|
||||
// Handle possible encryption mismatch
|
||||
if (!IsEncryptionSchemeSupported(aEncryptedBuffer.encryption_scheme)) {
|
||||
return cdm::Status::kDecryptError;
|
||||
}
|
||||
|
||||
return mCDM->DecryptAndDecodeFrame(ConvertToInputBuffer_1(aEncryptedBuffer),
|
||||
aVideoFrame);
|
||||
}
|
||||
|
||||
cdm::Status DecryptAndDecodeSamples(const cdm::InputBuffer& aEncryptedBuffer,
|
||||
cdm::AudioFrames* aAudioFrames) override
|
||||
cdm::Status DecryptAndDecodeSamples(
|
||||
const cdm::InputBuffer_2& aEncryptedBuffer,
|
||||
cdm::AudioFrames* aAudioFrames) override
|
||||
{
|
||||
return mCDM->DecryptAndDecodeSamples(aEncryptedBuffer, aAudioFrames);
|
||||
// Handle possible encryption mismatch
|
||||
if (!IsEncryptionSchemeSupported(aEncryptedBuffer.encryption_scheme)) {
|
||||
return cdm::Status::kDecryptError;
|
||||
}
|
||||
|
||||
return mCDM->DecryptAndDecodeSamples(
|
||||
ConvertToInputBuffer_1(aEncryptedBuffer), aAudioFrames);
|
||||
}
|
||||
|
||||
void OnPlatformChallengeResponse(
|
||||
const cdm::PlatformChallengeResponse& aResponse) override
|
||||
const cdm::PlatformChallengeResponse& aResponse) override
|
||||
{
|
||||
mCDM->OnPlatformChallengeResponse(aResponse);
|
||||
}
|
||||
|
@ -263,14 +287,15 @@ public:
|
|||
uint32_t aLinkMask,
|
||||
uint32_t aOutputProtectionMask) override
|
||||
{
|
||||
mCDM->OnQueryOutputProtectionStatus(aResult, aLinkMask, aOutputProtectionMask);
|
||||
mCDM->OnQueryOutputProtectionStatus(
|
||||
aResult, aLinkMask, aOutputProtectionMask);
|
||||
}
|
||||
|
||||
void OnStorageId(uint32_t aVersion,
|
||||
const uint8_t* aStorageId,
|
||||
uint32_t aStorageIdSize) override
|
||||
{
|
||||
//Only support on version 9 CDM.
|
||||
mCDM->OnStorageId(aVersion, aStorageId, aStorageIdSize);
|
||||
}
|
||||
|
||||
void Destroy() override
|
||||
|
@ -278,34 +303,81 @@ public:
|
|||
mCDM->Destroy();
|
||||
delete this;
|
||||
}
|
||||
cdm::ContentDecryptionModule_8* mCDM;
|
||||
cdm::Host_9* mHost;
|
||||
}; // class ChromiumCDM8BackwardsCompat
|
||||
|
||||
cdm::ContentDecryptionModule_9* mCDM;
|
||||
cdm::Host_10* mHost;
|
||||
|
||||
private:
|
||||
// CDM9 supports non-encrypted or cenc encrypted media, anything else should
|
||||
// be rejected.
|
||||
static bool IsEncryptionSchemeSupported(
|
||||
const cdm::EncryptionScheme& aEncryptionScheme)
|
||||
{
|
||||
return aEncryptionScheme == cdm::EncryptionScheme::kUnencrypted ||
|
||||
aEncryptionScheme == cdm::EncryptionScheme::kCenc;
|
||||
}
|
||||
|
||||
// Conversion functions that drop the encryption scheme member. CDMs prior to
|
||||
// 10 assumed no encryption or cenc encryption (if encryption is present). So
|
||||
// we can drop the scheme member if we check to make sure it was one of these
|
||||
// two options.
|
||||
static cdm::InputBuffer_1 ConvertToInputBuffer_1(
|
||||
const cdm::InputBuffer_2& aInputBuffer)
|
||||
{
|
||||
MOZ_ASSERT(
|
||||
IsEncryptionSchemeSupported(aInputBuffer.encryption_scheme),
|
||||
"Encryption scheme should be checked before attempting conversion!");
|
||||
return { aInputBuffer.data, aInputBuffer.data_size,
|
||||
aInputBuffer.key_id, aInputBuffer.key_id_size,
|
||||
aInputBuffer.iv, aInputBuffer.iv_size,
|
||||
aInputBuffer.subsamples, aInputBuffer.num_subsamples,
|
||||
aInputBuffer.timestamp };
|
||||
}
|
||||
|
||||
static cdm::AudioDecoderConfig_1 ConverToAudioDecoderConfig_1(
|
||||
const cdm::AudioDecoderConfig_2& aAudioConfig)
|
||||
{
|
||||
MOZ_ASSERT(
|
||||
IsEncryptionSchemeSupported(aAudioConfig.encryption_scheme),
|
||||
"Encryption scheme should be checked before attempting conversion!");
|
||||
return { aAudioConfig.codec,
|
||||
aAudioConfig.channel_count,
|
||||
aAudioConfig.bits_per_channel,
|
||||
aAudioConfig.samples_per_second,
|
||||
aAudioConfig.extra_data,
|
||||
aAudioConfig.extra_data_size };
|
||||
}
|
||||
|
||||
static cdm::VideoDecoderConfig_1 ConvertToVideoDecoderConfig_1(
|
||||
const cdm::VideoDecoderConfig_2& aVideoConfig)
|
||||
{
|
||||
MOZ_ASSERT(
|
||||
IsEncryptionSchemeSupported(aVideoConfig.encryption_scheme),
|
||||
"Encryption scheme should be checked before attempting conversion!");
|
||||
return { aVideoConfig.codec, aVideoConfig.profile,
|
||||
aVideoConfig.format, aVideoConfig.coded_size,
|
||||
aVideoConfig.extra_data, aVideoConfig.extra_data_size };
|
||||
}
|
||||
}; // class ChromiumCDM9BackwardsCompat
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
GMPContentChild::RecvPChromiumCDMConstructor(PChromiumCDMChild* aActor)
|
||||
{
|
||||
ChromiumCDMChild* child = static_cast<ChromiumCDMChild*>(aActor);
|
||||
// TODO: Once we support CDM10, create one here, for now try and create CDM9
|
||||
cdm::Host_9* host9 = child;
|
||||
|
||||
void* cdm = nullptr;
|
||||
// Create version 9 CDM first.
|
||||
GMPErr err = mGMPChild->GetAPI(CHROMIUM_CDM_API, host9, &cdm);
|
||||
GMPErr err = mGMPChild->GetAPI(CHROMIUM_CDM_API_BACKWARD_COMPAT, host9, &cdm);
|
||||
if (err != GMPNoErr || !cdm) {
|
||||
// Try to create older version 8 CDM.
|
||||
cdm::Host_8* host8 = child;
|
||||
err = mGMPChild->GetAPI(CHROMIUM_CDM_API_BACKWARD_COMPAT, host8, &cdm);
|
||||
if (err != GMPNoErr) {
|
||||
NS_WARNING("GMPGetAPI call failed trying to get CDM.");
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
cdm =
|
||||
new ChromiumCDM8BackwardsCompat(
|
||||
host9,
|
||||
static_cast<cdm::ContentDecryptionModule_8*>(cdm));
|
||||
NS_WARNING("GMPGetAPI call failed trying to get CDM.");
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
cdm::Host_10* host10 = child;
|
||||
cdm = new ChromiumCDM9BackwardsCompat(
|
||||
host10, static_cast<cdm::ContentDecryptionModule_9*>(cdm));
|
||||
|
||||
child->Init(static_cast<cdm::ContentDecryptionModule_9*>(cdm),
|
||||
child->Init(static_cast<cdm::ContentDecryptionModule_10*>(cdm),
|
||||
mGMPChild->mStorageId);
|
||||
|
||||
return IPC_OK();
|
||||
|
|
|
@ -12,56 +12,69 @@
|
|||
|
||||
namespace IPC {
|
||||
|
||||
template <>
|
||||
template<>
|
||||
struct ParamTraits<GMPErr>
|
||||
: public ContiguousEnumSerializer<GMPErr,
|
||||
GMPNoErr,
|
||||
GMPLastErr>
|
||||
{};
|
||||
: public ContiguousEnumSerializer<GMPErr, GMPNoErr, GMPLastErr>
|
||||
{
|
||||
};
|
||||
|
||||
template <>
|
||||
template<>
|
||||
struct ParamTraits<GMPVideoFrameType>
|
||||
: public ContiguousEnumSerializer<GMPVideoFrameType,
|
||||
kGMPKeyFrame,
|
||||
kGMPVideoFrameInvalid>
|
||||
{};
|
||||
: public ContiguousEnumSerializer<GMPVideoFrameType,
|
||||
kGMPKeyFrame,
|
||||
kGMPVideoFrameInvalid>
|
||||
{
|
||||
};
|
||||
|
||||
template <>
|
||||
template<>
|
||||
struct ParamTraits<GMPVideoCodecComplexity>
|
||||
: public ContiguousEnumSerializer<GMPVideoCodecComplexity,
|
||||
kGMPComplexityNormal,
|
||||
kGMPComplexityInvalid>
|
||||
{};
|
||||
: public ContiguousEnumSerializer<GMPVideoCodecComplexity,
|
||||
kGMPComplexityNormal,
|
||||
kGMPComplexityInvalid>
|
||||
{
|
||||
};
|
||||
|
||||
template <>
|
||||
template<>
|
||||
struct ParamTraits<GMPVP8ResilienceMode>
|
||||
: public ContiguousEnumSerializer<GMPVP8ResilienceMode,
|
||||
kResilienceOff,
|
||||
kResilienceInvalid>
|
||||
{};
|
||||
: public ContiguousEnumSerializer<GMPVP8ResilienceMode,
|
||||
kResilienceOff,
|
||||
kResilienceInvalid>
|
||||
{
|
||||
};
|
||||
|
||||
template <>
|
||||
template<>
|
||||
struct ParamTraits<GMPVideoCodecType>
|
||||
: public ContiguousEnumSerializer<GMPVideoCodecType,
|
||||
kGMPVideoCodecVP8,
|
||||
kGMPVideoCodecInvalid>
|
||||
{};
|
||||
: public ContiguousEnumSerializer<GMPVideoCodecType,
|
||||
kGMPVideoCodecVP8,
|
||||
kGMPVideoCodecInvalid>
|
||||
{
|
||||
};
|
||||
|
||||
template <>
|
||||
template<>
|
||||
struct ParamTraits<GMPVideoCodecMode>
|
||||
: public ContiguousEnumSerializer<GMPVideoCodecMode,
|
||||
kGMPRealtimeVideo,
|
||||
kGMPCodecModeInvalid>
|
||||
{};
|
||||
: public ContiguousEnumSerializer<GMPVideoCodecMode,
|
||||
kGMPRealtimeVideo,
|
||||
kGMPCodecModeInvalid>
|
||||
{
|
||||
};
|
||||
|
||||
template <>
|
||||
template<>
|
||||
struct ParamTraits<GMPBufferType>
|
||||
: public ContiguousEnumSerializer<GMPBufferType,
|
||||
GMP_BufferSingle,
|
||||
GMP_BufferInvalid>
|
||||
{};
|
||||
: public ContiguousEnumSerializer<GMPBufferType,
|
||||
GMP_BufferSingle,
|
||||
GMP_BufferInvalid>
|
||||
{
|
||||
};
|
||||
|
||||
template <>
|
||||
template<>
|
||||
struct ParamTraits<GMPEncryptionScheme>
|
||||
: public ContiguousEnumSerializer<GMPEncryptionScheme,
|
||||
GMPEncryptionScheme::kGMPEncryptionNone,
|
||||
GMPEncryptionScheme::kGMPEncryptionInvalid>
|
||||
{
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ParamTraits<GMPSimulcastStream>
|
||||
{
|
||||
typedef GMPSimulcastStream paramType;
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
include "GMPMessageUtils.h";
|
||||
|
||||
using GMPBufferType from "gmp-video-codec.h";
|
||||
using GMPEncryptionScheme from "gmp-video-codec.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
@ -55,7 +56,7 @@ struct CDMInputBuffer {
|
|||
int64_t mDuration;
|
||||
uint16_t[] mClearBytes;
|
||||
uint32_t[] mCipherBytes;
|
||||
bool mIsEncrypted;
|
||||
GMPEncryptionScheme mEncryptionScheme;
|
||||
};
|
||||
|
||||
struct CDMVideoDecoderConfig {
|
||||
|
@ -65,6 +66,7 @@ struct CDMVideoDecoderConfig {
|
|||
int32_t mImageWidth;
|
||||
int32_t mImageHeight;
|
||||
uint8_t[] mExtraData;
|
||||
GMPEncryptionScheme mEncryptionScheme;
|
||||
};
|
||||
|
||||
struct CDMKeyInformation {
|
||||
|
|
|
@ -14,8 +14,9 @@
|
|||
#include "nsCOMPtr.h"
|
||||
#include "nsClassHashtable.h"
|
||||
|
||||
#define CHROMIUM_CDM_API_BACKWARD_COMPAT "chromium-cdm8-host4"
|
||||
#define CHROMIUM_CDM_API "chromium-cdm9-host4"
|
||||
#define CHROMIUM_CDM_API_BACKWARD_COMPAT "chromium-cdm9-host4"
|
||||
// TODO: The following should be used as we switch to cdm10
|
||||
#define CHROMIUM_CDM_API "chromium-cdm10-host4"
|
||||
|
||||
class nsIFile;
|
||||
class nsIDirectoryEnumerator;
|
||||
|
|
|
@ -14,10 +14,13 @@ async protocol PChromiumCDM
|
|||
manager PGMPContent;
|
||||
child:
|
||||
|
||||
// cdm::ContentDecryptionModule8
|
||||
// cdm::ContentDecryptionModule9+10
|
||||
async Init(bool aAllowDistinctiveIdentifier,
|
||||
bool aAllowPersistentState);
|
||||
|
||||
async GetStatusForPolicy(uint32_t aPromiseId,
|
||||
nsCString aMinHdcpVersion);
|
||||
|
||||
async SetServerCertificate(uint32_t aPromiseId,
|
||||
uint8_t[] aServerCert);
|
||||
|
||||
|
@ -57,24 +60,20 @@ child:
|
|||
async GiveBuffer(Shmem aShmem);
|
||||
|
||||
async PurgeShmems();
|
||||
|
||||
// cdm::ContentDecryptionModule9
|
||||
async GetStatusForPolicy(uint32_t aPromiseId,
|
||||
nsCString aMinHdcpVersion);
|
||||
|
||||
|
||||
parent:
|
||||
async __delete__();
|
||||
|
||||
// cdm::Host9
|
||||
// cdm::Host9+10
|
||||
async OnResolvePromiseWithKeyStatus(uint32_t aPromiseId, uint32_t aKeyStatus);
|
||||
|
||||
// cdm::Host8
|
||||
async OnResolveNewSessionPromise(uint32_t aPromiseId, nsCString aSessionId);
|
||||
|
||||
async OnResolvePromise(uint32_t aPromiseId);
|
||||
|
||||
async OnRejectPromise(uint32_t aPromiseId,
|
||||
uint32_t aError,
|
||||
uint32_t aException,
|
||||
uint32_t aSystemCode,
|
||||
nsCString aErrorMessage);
|
||||
|
||||
|
@ -90,20 +89,15 @@ parent:
|
|||
|
||||
async OnSessionClosed(nsCString aSessionId);
|
||||
|
||||
async OnLegacySessionError(nsCString aSessionId,
|
||||
uint32_t aError,
|
||||
uint32_t aSystemCode,
|
||||
nsCString aMessage);
|
||||
|
||||
async ResolveLoadSessionPromise(uint32_t aPromiseId, bool aSuccessful);
|
||||
|
||||
// Return values of cdm::ContentDecryptionModule8::Decrypt
|
||||
// Return values of cdm::ContentDecryptionModule9::Decrypt
|
||||
async Decrypted(uint32_t aId, uint32_t aStatus, Shmem aDecryptedData);
|
||||
async DecryptFailed(uint32_t aId, uint32_t aStatus);
|
||||
|
||||
async OnDecoderInitDone(uint32_t aStatus);
|
||||
|
||||
// Return values of cdm::ContentDecryptionModule8::DecryptAndDecodeFrame
|
||||
// Return values of cdm::ContentDecryptionModule9::DecryptAndDecodeFrame
|
||||
async DecodedShmem(CDMVideoFrame aFrame, Shmem aData);
|
||||
async DecodedData(CDMVideoFrame aFrame, uint8_t[] aData);
|
||||
async DecodeFailed(uint32_t aStatus);
|
||||
|
|
|
@ -223,4 +223,14 @@ struct GMPCodecSpecificInfo
|
|||
GMPCodecSpecificInfoUnion mCodecSpecific;
|
||||
};
|
||||
|
||||
// The encryption scheme used. Historically Widevine only supported none or
|
||||
// cenc, but starting at interface version 10 the CDM should also support cbcs.
|
||||
enum class GMPEncryptionScheme : uint8_t
|
||||
{
|
||||
kGMPEncryptionNone = 0,
|
||||
kGMPEncryptionCenc = 1,
|
||||
kGMPEncryptionCbcs = 2,
|
||||
kGMPEncryptionInvalid = 3,
|
||||
};
|
||||
|
||||
#endif // GMP_VIDEO_CODEC_h_
|
||||
|
|
|
@ -63,6 +63,7 @@ EXPORTS += [
|
|||
'widevine-adapter/content_decryption_module.h',
|
||||
'widevine-adapter/content_decryption_module_export.h',
|
||||
'widevine-adapter/content_decryption_module_ext.h',
|
||||
'widevine-adapter/content_decryption_module_proxy.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
|
|
|
@ -15,10 +15,11 @@ namespace mozilla {
|
|||
|
||||
WidevineVideoFrame::WidevineVideoFrame()
|
||||
: mFormat(kUnknownVideoFormat)
|
||||
, mSize(0,0)
|
||||
, mSize{ 0, 0 }
|
||||
, mBuffer(nullptr)
|
||||
, mTimestamp(0)
|
||||
{
|
||||
MOZ_ASSERT(mSize.height == 0 && mSize.width == 0, "Size should be zeroed");
|
||||
GMP_LOG("WidevineVideoFrame::WidevineVideoFrame() this=%p", this);
|
||||
memset(mPlaneOffsets, 0, sizeof(mPlaneOffsets));
|
||||
memset(mPlaneStrides, 0, sizeof(mPlaneStrides));
|
||||
|
@ -136,8 +137,12 @@ WidevineVideoFrame::Timestamp() const
|
|||
}
|
||||
|
||||
bool
|
||||
WidevineVideoFrame::InitToBlack(uint32_t aWidth, uint32_t aHeight, int64_t aTimeStamp)
|
||||
WidevineVideoFrame::InitToBlack(int32_t aWidth,
|
||||
int32_t aHeight,
|
||||
int64_t aTimeStamp)
|
||||
{
|
||||
MOZ_ASSERT(aWidth >= 0 && aHeight >= 0,
|
||||
"Frame dimensions should be positive");
|
||||
CheckedInt<size_t> ySizeChk = aWidth;
|
||||
ySizeChk *= aHeight;
|
||||
// If w*h didn't overflow, half of them won't.
|
||||
|
@ -156,7 +161,7 @@ WidevineVideoFrame::InitToBlack(uint32_t aWidth, uint32_t aHeight, int64_t aTime
|
|||
mBuffer = nullptr;
|
||||
}
|
||||
SetFormat(VideoFormat::kI420);
|
||||
SetSize(cdm::Size(aWidth, aHeight));
|
||||
SetSize(cdm::Size{ aWidth, aHeight });
|
||||
SetFrameBuffer(buffer);
|
||||
SetPlaneOffset(VideoFrame::kYPlane, 0);
|
||||
SetStride(VideoFrame::kYPlane, aWidth);
|
||||
|
|
|
@ -37,7 +37,9 @@ public:
|
|||
void SetTimestamp(int64_t aTimestamp) override;
|
||||
int64_t Timestamp() const override;
|
||||
|
||||
MOZ_MUST_USE bool InitToBlack(uint32_t aWidth, uint32_t aHeight, int64_t aTimeStamp);
|
||||
MOZ_MUST_USE bool InitToBlack(int32_t aWidth,
|
||||
int32_t aHeight,
|
||||
int64_t aTimeStamp);
|
||||
|
||||
protected:
|
||||
cdm::VideoFormat mFormat;
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -19,4 +19,20 @@
|
|||
#define CDM_API __attribute__((visibility("default")))
|
||||
#endif // defined(_WIN32)
|
||||
|
||||
// Define CDM_CLASS_API to export class types. We have to add visibility
|
||||
// attributes to make sure virtual tables in CDM consumer and CDM implementation
|
||||
// are the same. Generally, it was always a good idea, as there're no guarantees
|
||||
// about that for the internal symbols, but it has only become a practical issue
|
||||
// after introduction of LTO devirtualization. See more details on
|
||||
// https://crbug.com/609564#c35
|
||||
#if defined(_WIN32)
|
||||
#if defined(__clang__)
|
||||
#define CDM_CLASS_API [[clang::lto_visibility_public]]
|
||||
#else
|
||||
#define CDM_CLASS_API
|
||||
#endif
|
||||
#else // defined(_WIN32)
|
||||
#define CDM_CLASS_API __attribute__((visibility("default")))
|
||||
#endif // defined(_WIN32)
|
||||
|
||||
#endif // CDM_CONTENT_DECRYPTION_MODULE_EXPORT_H_
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
// Copyright 2017 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CDM_CONTENT_DECRYPTION_MODULE_PROXY_H_
|
||||
#define CDM_CONTENT_DECRYPTION_MODULE_PROXY_H_
|
||||
|
||||
#include "content_decryption_module_export.h"
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
namespace cdm {
|
||||
|
||||
class CDM_CLASS_API CdmProxyClient;
|
||||
|
||||
// A proxy class for the CDM.
|
||||
// In general, the interpretation of the CdmProxy and CdmProxyClient method
|
||||
// parameters are protocol dependent. For enum parameters, values outside the
|
||||
// enum range may not work.
|
||||
class CDM_CLASS_API CdmProxy {
|
||||
public:
|
||||
enum Function : uint32_t {
|
||||
// For Intel Negotiate Crypto SessionKey Exchange (CSME) path to call
|
||||
// ID3D11VideoContext::NegotiateCryptoSessionKeyExchange.
|
||||
kIntelNegotiateCryptoSessionKeyExchange = 1,
|
||||
// There will be more values in the future e.g. for D3D11 RSA method.
|
||||
};
|
||||
|
||||
// Initializes the proxy. The results will be returned in
|
||||
// CdmProxyClient::OnInitialized().
|
||||
virtual void Initialize() = 0;
|
||||
|
||||
// Processes and updates the state of the proxy.
|
||||
// |output_data_size| is required by some protocol to set up the output data.
|
||||
// The operation may fail if the |output_data_size| is wrong. The results will
|
||||
// be returned in CdmProxyClient::OnProcessed().
|
||||
virtual void Process(Function function,
|
||||
uint32_t crypto_session_id,
|
||||
const uint8_t* input_data,
|
||||
uint32_t input_data_size,
|
||||
uint32_t output_data_size) = 0;
|
||||
|
||||
// Creates a crypto session for handling media.
|
||||
// If extra data has to be passed to further setup the media crypto session,
|
||||
// pass the data as |input_data|. The results will be returned in
|
||||
// CdmProxyClient::OnMediaCryptoSessionCreated().
|
||||
virtual void CreateMediaCryptoSession(const uint8_t* input_data,
|
||||
uint32_t input_data_size) = 0;
|
||||
|
||||
// Sets a key for the session identified by |crypto_session_id|.
|
||||
virtual void SetKey(uint32_t crypto_session_id,
|
||||
const uint8_t* key_id,
|
||||
uint32_t key_id_size,
|
||||
const uint8_t* key_blob,
|
||||
uint32_t key_blob_size) = 0;
|
||||
|
||||
// Removes a key for the session identified by |crypto_session_id|.
|
||||
virtual void RemoveKey(uint32_t crypto_session_id,
|
||||
const uint8_t* key_id,
|
||||
uint32_t key_id_size) = 0;
|
||||
|
||||
protected:
|
||||
CdmProxy() {}
|
||||
virtual ~CdmProxy() {}
|
||||
};
|
||||
|
||||
// Responses to CdmProxy calls. All responses will be called asynchronously.
|
||||
class CDM_CLASS_API CdmProxyClient {
|
||||
public:
|
||||
enum Status : uint32_t {
|
||||
kOk,
|
||||
kFail,
|
||||
};
|
||||
|
||||
enum Protocol : uint32_t {
|
||||
kNone = 0, // No protocol supported. Can be used in failure cases.
|
||||
kIntel, // Method using Intel CSME.
|
||||
// There will be more values in the future e.g. kD3D11RsaHardware,
|
||||
// kD3D11RsaSoftware to use the D3D11 RSA method.
|
||||
};
|
||||
|
||||
// Callback for Initialize(). If the proxy created a crypto session, then the
|
||||
// ID for the crypto session is |crypto_session_id|.
|
||||
virtual void OnInitialized(Status status,
|
||||
Protocol protocol,
|
||||
uint32_t crypto_session_id) = 0;
|
||||
|
||||
// Callback for Process(). |output_data| is the output of processing.
|
||||
virtual void OnProcessed(Status status,
|
||||
const uint8_t* output_data,
|
||||
uint32_t output_data_size) = 0;
|
||||
|
||||
// Callback for CreateMediaCryptoSession(). On success:
|
||||
// - |crypto_session_id| is the ID for the created crypto session.
|
||||
// - |output_data| is extra value, if any.
|
||||
// Otherwise, |crypto_session_id| and |output_data| should be ignored.
|
||||
virtual void OnMediaCryptoSessionCreated(Status status,
|
||||
uint32_t crypto_session_id,
|
||||
uint64_t output_data) = 0;
|
||||
|
||||
// Called when there is a hardware reset and all the hardware context is lost.
|
||||
virtual void NotifyHardwareReset() = 0;
|
||||
|
||||
protected:
|
||||
CdmProxyClient() {}
|
||||
virtual ~CdmProxyClient() {}
|
||||
};
|
||||
|
||||
} // namespace cdm
|
||||
|
||||
#endif // CDM_CONTENT_DECRYPTION_MODULE_PROXY_H_
|
|
@ -1090,11 +1090,6 @@ private:
|
|||
|
||||
void SessionClosed(const nsCString& aSessionId) override { }
|
||||
|
||||
void LegacySessionError(const nsCString& aSessionId,
|
||||
nsresult aError,
|
||||
uint32_t aSystemCode,
|
||||
const nsCString& aMessage) override { }
|
||||
|
||||
void Terminated() override { mRunner->Terminated(); }
|
||||
|
||||
void Shutdown() override { mRunner->Shutdown(); }
|
||||
|
|
|
@ -121,7 +121,7 @@ MP4Decoder::GetTracksInfo(const MediaContainerType& aType, MediaResult& aError)
|
|||
if (IsAV1CodecString(codec)) {
|
||||
tracks.AppendElement(
|
||||
CreateTrackInfoWithMIMETypeAndContainerTypeExtraParameters(
|
||||
NS_LITERAL_CSTRING("video/") + NS_ConvertUTF16toUTF8(codec), aType));
|
||||
NS_LITERAL_CSTRING("video/av1"), aType));
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -34,21 +34,21 @@ ToCDMH264Profile(uint8_t aProfile)
|
|||
{
|
||||
switch (aProfile) {
|
||||
case 66:
|
||||
return cdm::VideoDecoderConfig::kH264ProfileBaseline;
|
||||
return cdm::VideoCodecProfile::kH264ProfileBaseline;
|
||||
case 77:
|
||||
return cdm::VideoDecoderConfig::kH264ProfileMain;
|
||||
return cdm::VideoCodecProfile::kH264ProfileMain;
|
||||
case 88:
|
||||
return cdm::VideoDecoderConfig::kH264ProfileExtended;
|
||||
return cdm::VideoCodecProfile::kH264ProfileExtended;
|
||||
case 100:
|
||||
return cdm::VideoDecoderConfig::kH264ProfileHigh;
|
||||
return cdm::VideoCodecProfile::kH264ProfileHigh;
|
||||
case 110:
|
||||
return cdm::VideoDecoderConfig::kH264ProfileHigh10;
|
||||
return cdm::VideoCodecProfile::kH264ProfileHigh10;
|
||||
case 122:
|
||||
return cdm::VideoDecoderConfig::kH264ProfileHigh422;
|
||||
return cdm::VideoCodecProfile::kH264ProfileHigh422;
|
||||
case 144:
|
||||
return cdm::VideoDecoderConfig::kH264ProfileHigh444Predictive;
|
||||
return cdm::VideoCodecProfile::kH264ProfileHigh444Predictive;
|
||||
}
|
||||
return cdm::VideoDecoderConfig::kUnknownVideoCodecProfile;
|
||||
return cdm::VideoCodecProfile::kUnknownVideoCodecProfile;
|
||||
}
|
||||
|
||||
RefPtr<MediaDataDecoder::InitPromise>
|
||||
|
@ -64,17 +64,17 @@ ChromiumCDMVideoDecoder::Init()
|
|||
|
||||
gmp::CDMVideoDecoderConfig config;
|
||||
if (MP4Decoder::IsH264(mConfig.mMimeType)) {
|
||||
config.mCodec() = cdm::VideoDecoderConfig::kCodecH264;
|
||||
config.mCodec() = cdm::VideoCodec::kCodecH264;
|
||||
config.mProfile() =
|
||||
ToCDMH264Profile(mConfig.mExtraData->SafeElementAt(1, 0));
|
||||
config.mExtraData() = *mConfig.mExtraData;
|
||||
mConvertToAnnexB = true;
|
||||
} else if (VPXDecoder::IsVP8(mConfig.mMimeType)) {
|
||||
config.mCodec() = cdm::VideoDecoderConfig::kCodecVp8;
|
||||
config.mProfile() = cdm::VideoDecoderConfig::kProfileNotNeeded;
|
||||
config.mCodec() = cdm::VideoCodec::kCodecVp8;
|
||||
config.mProfile() = cdm::VideoCodecProfile::kProfileNotNeeded;
|
||||
} else if (VPXDecoder::IsVP9(mConfig.mMimeType)) {
|
||||
config.mCodec() = cdm::VideoDecoderConfig::kCodecVp9;
|
||||
config.mProfile() = cdm::VideoDecoderConfig::kProfileNotNeeded;
|
||||
config.mCodec() = cdm::VideoCodec::kCodecVp9;
|
||||
config.mProfile() = cdm::VideoCodecProfile::kProfileNotNeeded;
|
||||
} else {
|
||||
return MediaDataDecoder::InitPromise::CreateAndReject(
|
||||
NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__);
|
||||
|
|
|
@ -334,6 +334,7 @@ AudioDestinationNode::AudioDestinationNode(AudioContext* aContext,
|
|||
, mAudioChannelSuspended(false)
|
||||
, mCaptured(false)
|
||||
, mAudible(AudioChannelService::AudibleState::eAudible)
|
||||
, mCreatedTime(TimeStamp::Now())
|
||||
{
|
||||
nsPIDOMWindowInner* window = aContext->GetParentObject();
|
||||
MediaStreamGraph* graph =
|
||||
|
@ -636,6 +637,13 @@ AudioDestinationNode::InputMuted(bool aMuted)
|
|||
return;
|
||||
}
|
||||
|
||||
if (mDurationBeforeFirstTimeAudible.IsZero()) {
|
||||
MOZ_ASSERT(!aMuted);
|
||||
mDurationBeforeFirstTimeAudible = TimeStamp::Now() - mCreatedTime;
|
||||
Telemetry::Accumulate(Telemetry::WEB_AUDIO_BECOMES_AUDIBLE_TIME,
|
||||
mDurationBeforeFirstTimeAudible.ToSeconds());
|
||||
}
|
||||
|
||||
AudioPlaybackConfig config;
|
||||
nsresult rv = mAudioChannelAgent->NotifyStartedPlaying(&config,
|
||||
mAudible);
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "AudioChannelService.h"
|
||||
#include "AudioNode.h"
|
||||
#include "nsIAudioChannelAgent.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
@ -100,6 +101,11 @@ private:
|
|||
|
||||
bool mCaptured;
|
||||
AudioChannelService::AudibleState mAudible;
|
||||
|
||||
// These varaibles are used to know how long AudioContext would become audible
|
||||
// since it was created.
|
||||
TimeStamp mCreatedTime;
|
||||
TimeDuration mDurationBeforeFirstTimeAudible;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -245,12 +245,6 @@ LocalStorageCache::ProcessUsageDelta(uint32_t aGetDataSetIndex,
|
|||
const int64_t aDelta,
|
||||
const MutationSource aSource)
|
||||
{
|
||||
// Check if we are in a low disk space situation
|
||||
if (aSource == ContentMutation &&
|
||||
aDelta > 0 && mManager && mManager->IsLowDiskSpace()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check limit per this origin
|
||||
Data& data = mData[aGetDataSetIndex];
|
||||
uint64_t newOriginUsage = data.mOriginQuotaUsage + aDelta;
|
||||
|
|
|
@ -60,7 +60,6 @@ NS_IMPL_ISUPPORTS(LocalStorageManager,
|
|||
|
||||
LocalStorageManager::LocalStorageManager()
|
||||
: mCaches(8)
|
||||
, mLowDiskSpace(false)
|
||||
{
|
||||
StorageObserver* observer = StorageObserver::Self();
|
||||
NS_ASSERTION(observer, "No StorageObserver, cannot observe private data delete notifications!");
|
||||
|
@ -451,16 +450,6 @@ LocalStorageManager::Observe(const char* aTopic,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!strcmp(aTopic, "low-disk-space")) {
|
||||
mLowDiskSpace = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!strcmp(aTopic, "no-low-disk-space")) {
|
||||
mLowDiskSpace = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#ifdef DOM_STORAGE_TESTS
|
||||
if (!strcmp(aTopic, "test-reload")) {
|
||||
// This immediately completely reloads all caches from the database.
|
||||
|
|
|
@ -110,12 +110,6 @@ private:
|
|||
typedef nsTHashtable<LocalStorageCacheHashKey> CacheOriginHashtable;
|
||||
nsClassHashtable<nsCStringHashKey, CacheOriginHashtable> mCaches;
|
||||
|
||||
// If mLowDiskSpace is true it indicates a low device storage situation and
|
||||
// so no localStorage writes are allowed. sessionStorage writes are still
|
||||
// allowed.
|
||||
bool mLowDiskSpace;
|
||||
bool IsLowDiskSpace() const { return mLowDiskSpace; };
|
||||
|
||||
void ClearCaches(uint32_t aUnloadFlags,
|
||||
const OriginAttributesPattern& aPattern,
|
||||
const nsACString& aKeyPrefix);
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
#include "mozilla/ipc/PBackgroundChild.h"
|
||||
#include "mozilla/ipc/PBackgroundParent.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "nsIDiskSpaceWatcher.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -625,60 +624,6 @@ StorageDBParent::ReleaseIPDLReference()
|
|||
|
||||
namespace {
|
||||
|
||||
class CheckLowDiskSpaceRunnable
|
||||
: public Runnable
|
||||
{
|
||||
nsCOMPtr<nsIEventTarget> mOwningEventTarget;
|
||||
RefPtr<StorageDBParent> mParent;
|
||||
bool mLowDiskSpace;
|
||||
|
||||
public:
|
||||
explicit CheckLowDiskSpaceRunnable(StorageDBParent* aParent)
|
||||
: Runnable("dom::CheckLowDiskSpaceRunnable")
|
||||
, mOwningEventTarget(GetCurrentThreadEventTarget())
|
||||
, mParent(aParent)
|
||||
, mLowDiskSpace(false)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(aParent);
|
||||
}
|
||||
|
||||
private:
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
if (IsOnBackgroundThread()) {
|
||||
MOZ_ASSERT(mParent);
|
||||
|
||||
if (!mParent->IPCOpen()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (mLowDiskSpace) {
|
||||
mozilla::Unused << mParent->SendObserve(
|
||||
nsDependentCString("low-disk-space"), EmptyString(), EmptyCString());
|
||||
}
|
||||
|
||||
mParent = nullptr;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsCOMPtr<nsIDiskSpaceWatcher> diskSpaceWatcher =
|
||||
do_GetService("@mozilla.org/toolkit/disk-space-watcher;1");
|
||||
if (!diskSpaceWatcher) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
diskSpaceWatcher->GetIsDiskFull(&mLowDiskSpace);
|
||||
|
||||
MOZ_ALWAYS_SUCCEEDS(mOwningEventTarget->Dispatch(this, NS_DISPATCH_NORMAL));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
StorageDBParent::StorageDBParent(const nsString& aProfilePath)
|
||||
|
@ -720,14 +665,6 @@ StorageDBParent::Init()
|
|||
storageThread->GetOriginsHavingData(&scopes);
|
||||
mozilla::Unused << SendOriginsHavingData(scopes);
|
||||
}
|
||||
|
||||
// We need to check if the device is in a low disk space situation, so
|
||||
// we can forbid in that case any write in localStorage.
|
||||
|
||||
RefPtr<CheckLowDiskSpaceRunnable> runnable =
|
||||
new CheckLowDiskSpaceRunnable(this);
|
||||
|
||||
MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable));
|
||||
}
|
||||
|
||||
StorageDBParent::CacheParentBridge*
|
||||
|
|
|
@ -74,9 +74,6 @@ StorageObserver::Init()
|
|||
obs->AddObserver(sSelf, "profile-before-change", true);
|
||||
}
|
||||
|
||||
// Observe low device storage notifications.
|
||||
obs->AddObserver(sSelf, "disk-space-watcher", true);
|
||||
|
||||
// Testing
|
||||
#ifdef DOM_STORAGE_TESTS
|
||||
Preferences::RegisterCallbackAndCall(TestingPrefChanged, kTestingPref);
|
||||
|
@ -410,16 +407,6 @@ StorageObserver::Observe(nsISupports* aSubject,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!strcmp(aTopic, "disk-space-watcher")) {
|
||||
if (NS_LITERAL_STRING("full").Equals(aData)) {
|
||||
Notify("low-disk-space");
|
||||
} else if (NS_LITERAL_STRING("free").Equals(aData)) {
|
||||
Notify("no-low-disk-space");
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#ifdef DOM_STORAGE_TESTS
|
||||
if (!strcmp(aTopic, "domstorage-test-flush-force")) {
|
||||
StorageDBChild* storageChild = StorageDBChild::GetOrCreate();
|
||||
|
|
|
@ -80,8 +80,6 @@ support-files =
|
|||
[test_fallback.html]
|
||||
[test_foreign.html]
|
||||
[test_identicalManifest.html]
|
||||
[test_lowDeviceStorage.html]
|
||||
[test_lowDeviceStorageDuringUpdate.html]
|
||||
[test_missingFile.html]
|
||||
[test_missingManifest.html]
|
||||
[test_noManifest.html]
|
||||
|
|
|
@ -1,91 +0,0 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>Low device storage</title>
|
||||
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/dom/tests/mochitest/ajax/offline/offlineTests.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
/**
|
||||
* This test checks that an offline cache update scheduled *after* a low device
|
||||
* storage situation appears is canceled. It basically does:
|
||||
*
|
||||
* 1. Notifies to the offline cache update service about a fake
|
||||
* low device storage situation.
|
||||
* 2. Schedules an update and observes for its notifications.
|
||||
* 3. We are supposed to receive an error event notifying about the cancelation
|
||||
* of the update because of the low storage situation.
|
||||
* 4. Notifies to the offline cache update service that we've recovered from
|
||||
* the low storage situation.
|
||||
*/
|
||||
|
||||
var updateService = SpecialPowers.Cc['@mozilla.org/offlinecacheupdate-service;1']
|
||||
.getService(Ci.nsIOfflineCacheUpdateService);
|
||||
|
||||
var obs = SpecialPowers.Cc["@mozilla.org/observer-service;1"]
|
||||
.getService(SpecialPowers.Ci.nsIObserverService);
|
||||
|
||||
var errorReceived = false;
|
||||
|
||||
var systemPrincipal = SpecialPowers.Services.scriptSecurityManager.getSystemPrincipal();
|
||||
|
||||
function finish() {
|
||||
obs.notifyObservers(updateService, "disk-space-watcher", "free");
|
||||
|
||||
OfflineTest.teardownAndFinish();
|
||||
}
|
||||
|
||||
if (OfflineTest.setup()) {
|
||||
obs.notifyObservers(updateService, "disk-space-watcher", "full");
|
||||
|
||||
var updateObserver = SpecialPowers.wrapCallbackObject({
|
||||
updateStateChanged: function (aUpdate, aState) {
|
||||
switch(aState) {
|
||||
case Ci.nsIOfflineCacheUpdateObserver.STATE_ERROR:
|
||||
errorReceived = true;
|
||||
OfflineTest.ok(true, "Expected error. Update canceled");
|
||||
break;
|
||||
case Ci.nsIOfflineCacheUpdateObserver.STATE_FINISHED:
|
||||
aUpdate.removeObserver(this);
|
||||
OfflineTest.ok(errorReceived,
|
||||
"Finished after receiving the expected error");
|
||||
finish();
|
||||
break;
|
||||
case Ci.nsIOfflineCacheUpdateObserver.STATE_NOUPDATE:
|
||||
aUpdate.removeObserver(this);
|
||||
OfflineTest.ok(false, "No update");
|
||||
finish();
|
||||
break;
|
||||
case Ci.nsIOfflineCacheUpdateObserver.STATE_DOWNLOADING:
|
||||
case Ci.nsIOfflineCacheUpdateObserver.STATE_ITEMSTARTED:
|
||||
case Ci.nsIOfflineCacheUpdateObserver.STATE_ITEMPROGRESS:
|
||||
aUpdate.removeObserver(this);
|
||||
OfflineTest.ok(false, "The update was supposed to be canceled");
|
||||
finish();
|
||||
break;
|
||||
}
|
||||
},
|
||||
applicationCacheAvailable: function() {}
|
||||
});
|
||||
|
||||
var manifest = "https://example.com/tests/dom/tests/mochitest/ajax/offline/simpleManifest.cacheManifest";
|
||||
var ioService = Cc["@mozilla.org/network/io-service;1"]
|
||||
.getService(Ci.nsIIOService);
|
||||
var manifestURI = ioService.newURI(manifest);
|
||||
var documentURI = ioService.newURI(document.documentURI);
|
||||
var update = updateService.scheduleUpdate(manifestURI, documentURI, systemPrincipal, window);
|
||||
update.addObserver(updateObserver, false);
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -1,58 +0,0 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml" manifest="https://example.com/tests/dom/tests/mochitest/ajax/offline/simpleManifest.cacheManifest">
|
||||
<head>
|
||||
<title>Low device storage during update</title>
|
||||
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/dom/tests/mochitest/ajax/offline/offlineTests.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
/**
|
||||
* This test checks that an offline cache update is canceled when a low device
|
||||
* storage condition is detected during the update.
|
||||
*/
|
||||
|
||||
var updateService = Cc['@mozilla.org/offlinecacheupdate-service;1']
|
||||
.getService(Ci.nsIOfflineCacheUpdateService);
|
||||
|
||||
var obs = SpecialPowers.Cc["@mozilla.org/observer-service;1"]
|
||||
.getService(SpecialPowers.Ci.nsIObserverService);
|
||||
|
||||
function finish() {
|
||||
obs.notifyObservers(updateService, "disk-space-watcher", "free");
|
||||
|
||||
OfflineTest.teardownAndFinish();
|
||||
}
|
||||
|
||||
function onError() {
|
||||
OfflineTest.ok(true, "Expected error: Update canceled");
|
||||
finish();
|
||||
}
|
||||
|
||||
function onUnexpectedEvent() {
|
||||
OfflineTest.ok(false, "The update was supposed to be canceled");
|
||||
finish();
|
||||
}
|
||||
|
||||
function onChecking() {
|
||||
obs.notifyObservers(updateService, "disk-space-watcher", "full");
|
||||
}
|
||||
|
||||
if (OfflineTest.setup()) {
|
||||
applicationCache.onerror = OfflineTest.priv(onError);
|
||||
applicationCache.onprogress = OfflineTest.priv(onUnexpectedEvent);
|
||||
applicationCache.oncached = OfflineTest.priv(onUnexpectedEvent);
|
||||
applicationCache.onchecking = OfflineTest.priv(onChecking);
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -48,8 +48,6 @@ skip-if = toolkit == 'android' || (verify && (os == 'linux' || os == 'win')) #TI
|
|||
skip-if = true # bug 1347690
|
||||
[test_localStorageReplace.html]
|
||||
skip-if = toolkit == 'android'
|
||||
[test_lowDeviceStorage.html]
|
||||
skip-if = verify
|
||||
[test_storageConstructor.html]
|
||||
[test_localStorageSessionPrefOverride.html]
|
||||
[test_firstPartyOnlyPermission.html]
|
||||
|
|
|
@ -1,75 +0,0 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>Test localStorage usage while in a low device storage situation</title>
|
||||
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
/*
|
||||
This test does the following:
|
||||
- Stores an item in localStorage.
|
||||
- Checks the stored value.
|
||||
- Emulates a low device storage situation.
|
||||
- Gets the stored item again.
|
||||
- Removes the stored item.
|
||||
- Fails storing a new value.
|
||||
- Emulates recovering from a low device storage situation.
|
||||
- Stores a new value.
|
||||
- Checks the stored value.
|
||||
*/
|
||||
|
||||
function lowDeviceStorage(lowStorage) {
|
||||
var data = lowStorage ? "full" : "free";
|
||||
SpecialPowers.Services.obs.notifyObservers(null, "disk-space-watcher", data);
|
||||
}
|
||||
|
||||
function startTest() {
|
||||
// Add a test item.
|
||||
localStorage.setItem("item", "value");
|
||||
is(localStorage.getItem("item"), "value", "getItem()");
|
||||
|
||||
// Emulates a low device storage situation.
|
||||
lowDeviceStorage(true);
|
||||
|
||||
// Checks that we can still access to the stored item.
|
||||
is(localStorage.getItem("item"), "value",
|
||||
"getItem() during a device storage situation");
|
||||
|
||||
// Removes the stored item.
|
||||
localStorage.removeItem("item");
|
||||
is(localStorage.getItem("item"), null,
|
||||
"getItem() after removing the item");
|
||||
|
||||
// Fails storing a new item.
|
||||
try {
|
||||
localStorage.setItem("newItem", "value");
|
||||
ok(false, "Storing a new item is expected to fail");
|
||||
} catch(e) {
|
||||
ok(true, "Got an expected exception " + e);
|
||||
} finally {
|
||||
is(localStorage.getItem("newItem"), null,
|
||||
"setItem while device storage is low");
|
||||
}
|
||||
|
||||
// Emulates recovering from a low device storage situation.
|
||||
lowDeviceStorage(false);
|
||||
|
||||
// Add a test item after recovering from the low device storage situation.
|
||||
localStorage.setItem("newItem", "value");
|
||||
is(localStorage.getItem("newItem"), "value",
|
||||
"getItem() with available storage");
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="startTest();">
|
||||
</body>
|
||||
</html>
|
|
@ -39,8 +39,7 @@ function onSpellCheck(editableElement, callback) {
|
|||
// False is important here. Pass false so that the inline spell checker
|
||||
// isn't created if it doesn't already exist.
|
||||
var isc = editor.getInlineSpellChecker(false);
|
||||
}
|
||||
catch (err) {
|
||||
} catch (err) {
|
||||
// getInlineSpellChecker throws if spell checking is not enabled instead of
|
||||
// just returning null, which seems kind of lame. (Spell checking is not
|
||||
// enabled on Android.) The point here is only to determine whether spell
|
||||
|
@ -61,6 +60,7 @@ function onSpellCheck(editableElement, callback) {
|
|||
waitingForEnded = !waitingForEnded;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line mozilla/use-services
|
||||
let os = Cc["@mozilla.org/observer-service;1"].
|
||||
getService(Ci.nsIObserverService);
|
||||
os.addObserver(observe, SPELL_CHECK_STARTED_TOPIC);
|
||||
|
@ -77,4 +77,4 @@ function onSpellCheck(editableElement, callback) {
|
|||
os.removeObserver(observe, SPELL_CHECK_ENDED_TOPIC);
|
||||
callback();
|
||||
}, 0, Ci.nsITimer.TYPE_REPEATING_SLACK);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
"extends": [
|
||||
"plugin:mozilla/chrome-test",
|
||||
"plugin:mozilla/mochitest-test",
|
||||
]
|
||||
};
|
|
@ -32,13 +32,13 @@ var helperAppDlgPromise = new Promise(function(resolve) {
|
|||
}
|
||||
|
||||
HelperAppLauncherDialog.prototype = {
|
||||
show: function(aLauncher, aWindowContext, aReason) {
|
||||
show(aLauncher, aWindowContext, aReason) {
|
||||
ok(true, "Whether showing Dialog");
|
||||
resolve();
|
||||
registrar.unregisterFactory(MOCK_HELPERAPP_DIALOG_CID,
|
||||
mockHelperAppService);
|
||||
},
|
||||
QueryInterface: ChromeUtils.generateQI([Ci.nsIHelperAppLauncherDialog])
|
||||
QueryInterface: ChromeUtils.generateQI([Ci.nsIHelperAppLauncherDialog]),
|
||||
};
|
||||
|
||||
mockHelperAppService = XPCOMUtils._getFactory(HelperAppLauncherDialog);
|
||||
|
|
|
@ -20,13 +20,13 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=348497
|
|||
|
||||
/** Test for Bug 348497 **/
|
||||
function doe() {
|
||||
document.getElementById('testIframe').style.display = 'block';
|
||||
document.getElementById('testIframe').contentDocument.designMode = 'on';
|
||||
document.getElementById("testIframe").style.display = "block";
|
||||
document.getElementById("testIframe").contentDocument.designMode = "on";
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addLoadEvent(doe);
|
||||
addLoadEvent(function() { ok(true, "enabling designmode on an iframe onload does not crash Mozilla")});
|
||||
addLoadEvent(function() { ok(true, "enabling designmode on an iframe onload does not crash Mozilla"); });
|
||||
addLoadEvent(SimpleTest.finish);
|
||||
|
||||
</script>
|
||||
|
|
|
@ -12,10 +12,10 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=389350
|
|||
|
||||
function runTest() {
|
||||
var e = document.getElementById("edit");
|
||||
e.contentDocument.designMode='on';
|
||||
e.style.display='block';
|
||||
e.contentDocument.designMode = "on";
|
||||
e.style.display = "block";
|
||||
e.focus();
|
||||
sendString('abc');
|
||||
sendString("abc");
|
||||
var expected = "<head></head><body>abc</body>";
|
||||
var result = e.contentDocument.documentElement.innerHTML;
|
||||
is(result, expected, "iframe with designmode on had incorrect content");
|
||||
|
|
|
@ -5,14 +5,14 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=519928
|
|||
-->
|
||||
<head>
|
||||
<title>Test for Bug 519928</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=519928">Mozilla Bug 519928</a>
|
||||
<p id="display"></p>
|
||||
<div id="content">
|
||||
<iframe id="load-frame"></iframe>
|
||||
<iframe id="load-frame"></iframe>
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
@ -38,11 +38,13 @@ function expectJSAllowed(allowed, testCondition, callback) {
|
|||
is(self_.ICanRunMyJS, allowed, msg);
|
||||
callback();
|
||||
}, {once: true});
|
||||
// eslint-disable-next-line no-useless-concat
|
||||
var iframeSrc = "<script>parent.parent.ICanRunMyJS = true;</scr" + "ipt>";
|
||||
innerFrame.srcdoc = iframeSrc;
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
/* eslint-disable max-nested-callbacks */
|
||||
addLoadEvent(function() {
|
||||
var enterDesignMode = function() { document.designMode = "on"; };
|
||||
var leaveDesignMode = function() { document.designMode = "off"; };
|
||||
|
@ -82,6 +84,7 @@ addLoadEvent(function() {
|
|||
});
|
||||
});
|
||||
});
|
||||
/* eslint-enable max-nested-callbacks */
|
||||
|
||||
function testDocumentDisabledJS() {
|
||||
window.ICanRunMyJS = false;
|
||||
|
@ -105,6 +108,7 @@ function testDocumentDisabledJS() {
|
|||
is(self_.ICanRunMyJS, false, msg);
|
||||
SimpleTest.finish();
|
||||
}, {once: true});
|
||||
// eslint-disable-next-line no-useless-concat
|
||||
var iframeSrc = "<script>parent.parent.ICanRunMyJS = true;</scr" + "ipt>";
|
||||
innerFrame.srcdoc = iframeSrc;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
"extends": [
|
||||
"plugin:mozilla/browser-test",
|
||||
"plugin:mozilla/mochitest-test",
|
||||
],
|
||||
|
||||
"plugins": [
|
||||
"no-unsanitized",
|
||||
],
|
||||
|
||||
"rules": {
|
||||
"no-unsanitized/property": "off",
|
||||
},
|
||||
};
|
|
@ -4,7 +4,7 @@ add_task(async function() {
|
|||
const kPageURL = "http://example.org/browser/editor/libeditor/tests/bug527935.html";
|
||||
await BrowserTestUtils.withNewTab({
|
||||
gBrowser,
|
||||
url: kPageURL
|
||||
url: kPageURL,
|
||||
}, async function(aBrowser) {
|
||||
var popupShown = false;
|
||||
function listener() {
|
||||
|
|
|
@ -4,9 +4,9 @@ add_task(async function() {
|
|||
const kPageURL = "http://example.org/browser/editor/libeditor/tests/bug629172.html";
|
||||
await BrowserTestUtils.withNewTab({
|
||||
gBrowser,
|
||||
url: kPageURL
|
||||
}, async function(aBrowser) {
|
||||
await ContentTask.spawn(aBrowser, {}, async function() {
|
||||
url: kPageURL,
|
||||
}, async function(browser) {
|
||||
await ContentTask.spawn(browser, {}, async function() {
|
||||
var window = content.window.wrappedJSObject;
|
||||
var document = window.document;
|
||||
|
||||
|
@ -50,8 +50,8 @@ add_task(async function() {
|
|||
return Promise.resolve();
|
||||
}
|
||||
|
||||
async function testDirection(initialDir, aBrowser) {
|
||||
await ContentTask.spawn(aBrowser, {initialDir}, function({initialDir}) {
|
||||
async function testDirection(initDir, aBrowser) {
|
||||
await ContentTask.spawn(aBrowser, {initialDir: initDir}, function({initialDir}) {
|
||||
var window = content.window.wrappedJSObject;
|
||||
var document = window.document;
|
||||
|
||||
|
@ -74,9 +74,9 @@ add_task(async function() {
|
|||
is(window.inputEventCount, 0, "input event count must be 0 before");
|
||||
});
|
||||
await simulateCtrlShiftX(aBrowser);
|
||||
await ContentTask.spawn(aBrowser, {initialDir}, function({initialDir}) {
|
||||
await ContentTask.spawn(aBrowser, {initialDir: initDir}, function({initialDir}) {
|
||||
var window = content.window.wrappedJSObject;
|
||||
var expectedDir = initialDir == "ltr" ? "rtl" : "ltr"
|
||||
var expectedDir = initialDir == "ltr" ? "rtl" : "ltr";
|
||||
is(window.t.getAttribute("dir"), expectedDir,
|
||||
"The dir attribute must be correctly updated");
|
||||
is(window.inputEventCount, 1, "input event count must be 1 after");
|
||||
|
@ -93,7 +93,7 @@ add_task(async function() {
|
|||
is(window.inputEventCount, 1, "input event count must be 1 before");
|
||||
});
|
||||
await simulateCtrlShiftX(aBrowser);
|
||||
await ContentTask.spawn(aBrowser, {initialDir}, function({initialDir}) {
|
||||
await ContentTask.spawn(aBrowser, {initialDir: initDir}, function({initialDir}) {
|
||||
var window = content.window.wrappedJSObject;
|
||||
|
||||
is(window.inputEventCount, 2, "input event count must be 2 after");
|
||||
|
@ -111,7 +111,7 @@ add_task(async function() {
|
|||
});
|
||||
}
|
||||
|
||||
await testDirection("ltr", aBrowser);
|
||||
await testDirection("rtl", aBrowser);
|
||||
await testDirection("ltr", browser);
|
||||
await testDirection("rtl", browser);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<!DOCTYPE>
|
||||
<script>
|
||||
localStorage["clicked"] = "true";
|
||||
localStorage.clicked = "true";
|
||||
close();
|
||||
</script>
|
||||
|
|
|
@ -2,30 +2,27 @@
|
|||
<head>
|
||||
<script type="text/javascript">
|
||||
|
||||
function is(aLeft, aRight, aMessage)
|
||||
{
|
||||
function is(aLeft, aRight, aMessage) {
|
||||
window.opener.SimpleTest.is(aLeft, aRight, aMessage);
|
||||
}
|
||||
|
||||
function unload()
|
||||
{
|
||||
function unload() {
|
||||
window.opener.SimpleTest.finish();
|
||||
}
|
||||
|
||||
function boom()
|
||||
{
|
||||
function boom() {
|
||||
var root = document.documentElement;
|
||||
while(root.firstChild) {
|
||||
while (root.firstChild) {
|
||||
root.firstChild.remove();
|
||||
}
|
||||
root.appendChild(document.createTextNode("Mozilla"));
|
||||
root.focus();
|
||||
cespan = document.createElementNS("http://www.w3.org/1999/xhtml", "span");
|
||||
let cespan = document.createElementNS("http://www.w3.org/1999/xhtml", "span");
|
||||
cespan.setAttributeNS(null, "contenteditable", "true");
|
||||
root.appendChild(cespan);
|
||||
try {
|
||||
document.execCommand("selectAll", false, null);
|
||||
} catch(e) { }
|
||||
} catch (e) { }
|
||||
|
||||
is(window.getSelection().toString(), "Mozilla",
|
||||
"The nodes are not selected");
|
||||
|
|
|
@ -32,11 +32,10 @@ function copyCF_HTML(cfhtml, success, failure) {
|
|||
.QueryInterface(Ci.nsILoadContext);
|
||||
}
|
||||
|
||||
var cb = Cc["@mozilla.org/widget/clipboard;1"].
|
||||
getService(Ci.nsIClipboard);
|
||||
var cb = SpecialPowers.Services.clipboard;
|
||||
|
||||
var counter = 0;
|
||||
function copyCF_HTML_worker(success, failure) {
|
||||
function copyCF_HTML_worker(successFn, failureFn) {
|
||||
if (++counter > 50) {
|
||||
ok(false, "Timed out while polling clipboard for pasted data");
|
||||
failure();
|
||||
|
@ -45,7 +44,7 @@ function copyCF_HTML(cfhtml, success, failure) {
|
|||
|
||||
var flavors = [CF_HTML];
|
||||
if (!cb.hasDataMatchingFlavors(flavors, flavors.length, cb.kGlobalClipboard)) {
|
||||
setTimeout(function() { copyCF_HTML_worker(success, failure); }, 100);
|
||||
setTimeout(function() { copyCF_HTML_worker(successFn, failureFn); }, 100);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -59,7 +58,7 @@ function copyCF_HTML(cfhtml, success, failure) {
|
|||
trans.getTransferData(CF_HTML, data, {});
|
||||
data = SpecialPowers.wrap(data).value.QueryInterface(Ci.nsISupportsCString).data;
|
||||
} catch (e) {
|
||||
setTimeout(function() { copyCF_HTML_worker(success, failure); }, 100);
|
||||
setTimeout(function() { copyCF_HTML_worker(successFn, failureFn); }, 100);
|
||||
return;
|
||||
}
|
||||
success();
|
||||
|
|
|
@ -67,7 +67,7 @@ SimpleTest.waitForFocus(async function() {
|
|||
|
||||
// left is abs positioned element's left + margin-left + border-left-width + 12.
|
||||
// XXX Perhaps, we need to add border-left-width here if you add new test to have thick border.
|
||||
const kPositionerX = 18
|
||||
const kPositionerX = 18;
|
||||
// top is abs positioned element's top + margin-top + border-top-width - 14.
|
||||
// XXX Perhaps, we need to add border-top-width here if you add new test to have thick border.
|
||||
const kPositionerY = -7;
|
||||
|
@ -90,9 +90,9 @@ SimpleTest.waitForFocus(async function() {
|
|||
isfuzzy(newRect.y, rect.y + aDeltaY, 1, description + "The top should be increased by " + aDeltaY + "pixels");
|
||||
}
|
||||
|
||||
await testPositioner( 10, 10);
|
||||
await testPositioner( 10, 10);
|
||||
await testPositioner( 10, -10);
|
||||
await testPositioner(-10, 10);
|
||||
await testPositioner(-10, 10);
|
||||
await testPositioner(-10, -10);
|
||||
}
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ function test(edit, bsCount) {
|
|||
edit.focus();
|
||||
var sel = window.getSelection();
|
||||
sel.collapse(edit.childNodes[0], edit.textContent.length - 1);
|
||||
for (i = 0; i < bsCount; ++i) {
|
||||
for (let i = 0; i < bsCount; ++i) {
|
||||
synthesizeKey("KEY_Backspace");
|
||||
}
|
||||
is(edit.textContent, "ab", "The backspace key should delete the characters correctly");
|
||||
|
@ -92,7 +92,7 @@ function runTest() {
|
|||
* Once the Firefox Emoji font is ready, we can load that via @font-face
|
||||
* and expect these tests to work across all platforms.
|
||||
*/
|
||||
hasEmojiFont =
|
||||
let hasEmojiFont =
|
||||
(navigator.platform.indexOf("Mac") == 0 &&
|
||||
/10\.([7-9]|[1-9][0-9])/.test(navigator.oscpu));
|
||||
|
||||
|
|
|
@ -21,15 +21,13 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1026397
|
|||
/** Test for Bug 1026397 **/
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function runTests()
|
||||
{
|
||||
function runTests() {
|
||||
var input = document.getElementById("input");
|
||||
input.focus();
|
||||
|
||||
function doTest(aMaxLength, aInitialValue, aCaretOffset,
|
||||
aInsertString, aExpectedValueDuringComposition,
|
||||
aExpectedValueAfterCompositionEnd, aAdditionalExplanation)
|
||||
{
|
||||
aExpectedValueAfterCompositionEnd, aAdditionalExplanation) {
|
||||
input.value = aInitialValue;
|
||||
var maxLengthStr = "";
|
||||
if (aMaxLength >= 0) {
|
||||
|
@ -51,10 +49,10 @@ function runTests()
|
|||
{ "string": aInsertString,
|
||||
"clauses":
|
||||
[
|
||||
{ "length": aInsertString.length, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
|
||||
]
|
||||
{ "length": aInsertString.length, "attr": COMPOSITION_ATTR_RAW_CLAUSE },
|
||||
],
|
||||
},
|
||||
"caret": { "start": aInsertString.length, "length": 0 }
|
||||
"caret": { "start": aInsertString.length, "length": 0 },
|
||||
});
|
||||
is(input.value, aExpectedValueDuringComposition,
|
||||
"The value of input whose maxlength is " + maxLengthStr + " should be "
|
||||
|
|
|
@ -17,8 +17,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1053048
|
|||
|
||||
const nsISelectionListener = SpecialPowers.Ci.nsISelectionListener;
|
||||
|
||||
function runTests()
|
||||
{
|
||||
function runTests() {
|
||||
var textarea = SpecialPowers.wrap(document.getElementById("textarea"));
|
||||
textarea.focus();
|
||||
|
||||
|
@ -27,12 +26,11 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1053048
|
|||
|
||||
var selectionListener = {
|
||||
count: 0,
|
||||
notifySelectionChanged: function (aDocument, aSelection, aReason)
|
||||
{
|
||||
notifySelectionChanged(aDocument, aSelection, aReason) {
|
||||
ok(true, "selectionStart: " + textarea.selectionStart);
|
||||
ok(true, "selectionEnd: " + textarea.selectionEnd);
|
||||
this.count++;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// Move caret to the end of the textarea
|
||||
|
|
|
@ -30,8 +30,7 @@ SimpleTest.waitForExplicitFinish();
|
|||
|
||||
const kIsLinux = navigator.platform.indexOf("Linux") == 0;
|
||||
|
||||
function runTests()
|
||||
{
|
||||
function runTests() {
|
||||
var editor0 = document.getElementById("editor0");
|
||||
var editor1 = document.getElementById("editor1");
|
||||
var editor2 = document.getElementById("editor2");
|
||||
|
|
|
@ -34,9 +34,9 @@ SimpleTest.waitForFocus(function() {
|
|||
|
||||
getSpellChecker().UpdateCurrentDictionary(() => {
|
||||
sendString(" ");
|
||||
setTimeout(function() {
|
||||
SimpleTest.executeSoon(function() {
|
||||
sendString("a");
|
||||
setTimeout(function() {
|
||||
SimpleTest.executeSoon(function() {
|
||||
synthesizeKey("KEY_Backspace");
|
||||
|
||||
onSpellCheck(div, function() {
|
||||
|
@ -47,13 +47,12 @@ SimpleTest.waitForFocus(function() {
|
|||
|
||||
SimpleTest.finish();
|
||||
});
|
||||
},0);
|
||||
},0);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function getEditor() {
|
||||
var Ci = SpecialPowers.Ci;
|
||||
var editingSession = SpecialPowers.wrap(window).docShell.editingSession;
|
||||
return editingSession.getEditorForWindow(window);
|
||||
}
|
||||
|
|
|
@ -14,8 +14,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1101392
|
|||
SimpleTest.waitForExplicitFinish();
|
||||
SimpleTest.waitForFocus(runTests);
|
||||
|
||||
function runCopyCommand(element, compareText, nextTest)
|
||||
{
|
||||
function runCopyCommand(element, compareText, nextTest) {
|
||||
element.focus();
|
||||
var expectedEndpoint, sel;
|
||||
if (element.localName == "textarea") {
|
||||
|
@ -48,20 +47,17 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1101392
|
|||
checkCollapse, checkCollapse);
|
||||
}
|
||||
|
||||
function testDiv()
|
||||
{
|
||||
function testDiv() {
|
||||
var content = document.getElementById("content");
|
||||
runCopyCommand(content, 'abc', testTextarea);
|
||||
runCopyCommand(content, "abc", testTextarea);
|
||||
}
|
||||
|
||||
function testTextarea()
|
||||
{
|
||||
function testTextarea() {
|
||||
var textarea = document.getElementById("textarea");
|
||||
runCopyCommand(textarea, 'def', SimpleTest.finish);
|
||||
runCopyCommand(textarea, "def", SimpleTest.finish);
|
||||
}
|
||||
|
||||
function runTests()
|
||||
{
|
||||
function runTests() {
|
||||
testDiv();
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -21,8 +21,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1102906
|
|||
SimpleTest.waitForExplicitFinish();
|
||||
SimpleTest.waitForFocus( () => {
|
||||
let content = document.getElementById("content");
|
||||
let drag = document.getElementById("drag")
|
||||
let selection = window.getSelection();
|
||||
let drag = document.getElementById("drag");
|
||||
let selection = window.getSelection();
|
||||
|
||||
/* Perform drag-and-drop for an arbitrary content. The caret should be at
|
||||
the end of the contenteditable. */
|
||||
|
|
|
@ -43,10 +43,10 @@ SimpleTest.waitForFocus(function() {
|
|||
{ "string": composingString,
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
|
||||
]
|
||||
{ "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE },
|
||||
],
|
||||
},
|
||||
"caret": { "start": 1, "length": 0 }
|
||||
"caret": { "start": 1, "length": 0 },
|
||||
});
|
||||
synthesizeComposition({ type: "compositioncommitasis" });
|
||||
is(t.value, "foo\u306B\nbar", "Correct value after composition");
|
||||
|
|
|
@ -11,7 +11,7 @@ getSelection().collapse(div.firstChild, 2);
|
|||
try {
|
||||
document.execCommand("inserttext", false, "\n");
|
||||
ok(true, "No exception thrown");
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
ok(false, "Exception: " + e);
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -11,7 +11,7 @@ function runTest() {
|
|||
SpecialPowers.setCommandNode(window, document.getElementById("i"));
|
||||
SpecialPowers.doCommand(window, "cmd_copyImageContents");
|
||||
|
||||
var e = document.getElementById('i1');
|
||||
var e = document.getElementById("i1");
|
||||
var doc = e.contentDocument;
|
||||
doc.designMode = "on";
|
||||
doc.defaultView.focus();
|
||||
|
|
|
@ -15,12 +15,11 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1153237
|
|||
// Avoid platform selection differences
|
||||
SimpleTest.waitForFocus(function() {
|
||||
SpecialPowers.pushPrefEnv({
|
||||
"set": [["layout.word_select.eat_space_to_next_word", true]]
|
||||
"set": [["layout.word_select.eat_space_to_next_word", true]],
|
||||
}, runTests);
|
||||
});
|
||||
|
||||
function runTests()
|
||||
{
|
||||
function runTests() {
|
||||
var element = document.getElementById("editor");
|
||||
var sel = window.getSelection();
|
||||
|
||||
|
|
|
@ -34,9 +34,9 @@ SimpleTest.waitForFocus(function() {
|
|||
synthesizeKey("KEY_ArrowLeft");
|
||||
synthesizeKey("KEY_ArrowLeft");
|
||||
|
||||
setTimeout(function() {
|
||||
SimpleTest.executeSoon(function() {
|
||||
synthesizeKey("KEY_Backspace");
|
||||
setTimeout(function() {
|
||||
SimpleTest.executeSoon(function() {
|
||||
sendString(" ");
|
||||
|
||||
onSpellCheck(div, function() {
|
||||
|
@ -47,13 +47,12 @@ SimpleTest.waitForFocus(function() {
|
|||
|
||||
SimpleTest.finish();
|
||||
});
|
||||
},0);
|
||||
},0);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function getEditor() {
|
||||
var Ci = SpecialPowers.Ci;
|
||||
var editingSession = SpecialPowers.wrap(window).docShell.editingSession;
|
||||
return editingSession.getEditorForWindow(window);
|
||||
}
|
||||
|
|
|
@ -21,19 +21,19 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1162952
|
|||
/** Test for Bug 1162952 **/
|
||||
var userCallbackRun = false;
|
||||
|
||||
document.addEventListener('keydown', function() {
|
||||
document.addEventListener("keydown", function() {
|
||||
// During a user callback, the commands should be enabled
|
||||
userCallbackRun = true;
|
||||
is(true, document.queryCommandEnabled('cut'));
|
||||
is(true, document.queryCommandEnabled('copy'));
|
||||
is(true, document.queryCommandEnabled("cut"));
|
||||
is(true, document.queryCommandEnabled("copy"));
|
||||
});
|
||||
|
||||
// Otherwise, they should be disabled
|
||||
is(false, document.queryCommandEnabled('cut'));
|
||||
is(false, document.queryCommandEnabled('copy'));
|
||||
is(false, document.queryCommandEnabled("cut"));
|
||||
is(false, document.queryCommandEnabled("copy"));
|
||||
|
||||
// Fire a user callback
|
||||
sendString('A');
|
||||
sendString("A");
|
||||
|
||||
ok(userCallbackRun, "User callback should've been run");
|
||||
|
||||
|
|
|
@ -32,16 +32,16 @@ SimpleTest.waitForFocus(function() {
|
|||
{ "string": "\u3042",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
|
||||
]
|
||||
{ "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE },
|
||||
],
|
||||
},
|
||||
"caret": { "start": 1, "length": 0 }
|
||||
"caret": { "start": 1, "length": 0 },
|
||||
});
|
||||
|
||||
ok(isThereIMESelection(), "There should be IME selection");
|
||||
|
||||
var compositionEnd = false;
|
||||
editor.addEventListener("compositionend", function () { compositionEnd = true; }, true);
|
||||
editor.addEventListener("compositionend", function() { compositionEnd = true; }, true);
|
||||
|
||||
synthesizeMouseAtCenter(span, {});
|
||||
|
||||
|
@ -51,8 +51,7 @@ SimpleTest.waitForFocus(function() {
|
|||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
function isThereIMESelection()
|
||||
{
|
||||
function isThereIMESelection() {
|
||||
var selCon = SpecialPowers.wrap(window).
|
||||
docShell.
|
||||
editingSession.
|
||||
|
@ -62,7 +61,7 @@ function isThereIMESelection()
|
|||
SpecialPowers.Ci.nsISelectionController.SELECTION_IME_RAWINPUT,
|
||||
SpecialPowers.Ci.nsISelectionController.SELECTION_IME_SELECTEDRAWTEXT,
|
||||
SpecialPowers.Ci.nsISelectionController.SELECTION_IME_CONVERTEDTEXT,
|
||||
SpecialPowers.Ci.nsISelectionController.SELECTION_IME_SELECTEDCONVERTEDTEXT
|
||||
SpecialPowers.Ci.nsISelectionController.SELECTION_IME_SELECTEDCONVERTEDTEXT,
|
||||
];
|
||||
for (var i = 0; i < kIMESelections.length; i++) {
|
||||
var sel = selCon.getSelection(kIMESelections[i]);
|
||||
|
|
|
@ -18,7 +18,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1230473
|
|||
<script type="application/javascript">
|
||||
/** Test for Bug 1230473 **/
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SimpleTest.waitForFocus(()=>{
|
||||
SimpleTest.waitForFocus(() => {
|
||||
function runTest(aEditor) {
|
||||
function committer() {
|
||||
aEditor.blur();
|
||||
|
@ -31,13 +31,13 @@ SimpleTest.waitForFocus(()=>{
|
|||
return isNSEditableElement() ? aEditor.value : aEditor.textContent;
|
||||
}
|
||||
function isComposing() {
|
||||
return isNSEditableElement() ? SpecialPowers.wrap(aEditor)
|
||||
.editor
|
||||
.composing :
|
||||
SpecialPowers.wrap(window)
|
||||
.docShell
|
||||
.editor
|
||||
.composing;
|
||||
return isNSEditableElement() ? SpecialPowers.wrap(aEditor)
|
||||
.editor
|
||||
.composing :
|
||||
SpecialPowers.wrap(window)
|
||||
.docShell
|
||||
.editor
|
||||
.composing;
|
||||
}
|
||||
function clear() {
|
||||
if (isNSEditableElement()) {
|
||||
|
|
|
@ -15,12 +15,11 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1248185
|
|||
// Avoid platform selection differences
|
||||
SimpleTest.waitForFocus(function() {
|
||||
SpecialPowers.pushPrefEnv({
|
||||
"set": [["layout.word_select.eat_space_to_next_word", true]]
|
||||
"set": [["layout.word_select.eat_space_to_next_word", true]],
|
||||
}, runTests);
|
||||
});
|
||||
|
||||
function runTests()
|
||||
{
|
||||
function runTests() {
|
||||
var editor = document.querySelector("#test");
|
||||
editor.focus();
|
||||
|
||||
|
|
|
@ -21,8 +21,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1250010
|
|||
|
||||
<script class="testbody" type="application/javascript">
|
||||
|
||||
function getImageDataURI()
|
||||
{
|
||||
function getImageDataURI() {
|
||||
return document.getElementsByTagName("img")[0].getAttribute("src");
|
||||
}
|
||||
|
||||
|
|
|
@ -96,8 +96,8 @@ SimpleTest.waitForFocus(function() {
|
|||
div.focus();
|
||||
synthesizeMouse(div, 100, 2, {}); /* click behind and down */
|
||||
|
||||
var sel = window.getSelection();
|
||||
var selRange = sel.getRangeAt(0);
|
||||
sel = window.getSelection();
|
||||
selRange = sel.getRangeAt(0);
|
||||
is(selRange.endContainer.nodeName, "#text", "selection should be at the end of text node");
|
||||
is(selRange.endOffset, 1, "offset should be 1");
|
||||
|
||||
|
@ -136,8 +136,8 @@ SimpleTest.waitForFocus(function() {
|
|||
div.focus();
|
||||
synthesizeMouse(div, 100, 2, {}); /* click behind and down */
|
||||
|
||||
var sel = window.getSelection();
|
||||
var selRange = sel.getRangeAt(0);
|
||||
sel = window.getSelection();
|
||||
selRange = sel.getRangeAt(0);
|
||||
is(selRange.endContainer.nodeName, "#text", "selection should be at the end of text node");
|
||||
is(selRange.endOffset, 1, "offset should be 1");
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ SimpleTest.waitForFocus(function() {
|
|||
synthesizeKey("KEY_ArrowRight");
|
||||
synthesizeKey("KEY_ArrowRight");
|
||||
synthesizeKey("KEY_Backspace");
|
||||
if (div.innerHTML, "x<br> ", "pre-wrap: Don't delete uncollapsed space");
|
||||
is(div.innerHTML, "x<br> ", "pre-wrap: Don't delete uncollapsed space");
|
||||
ok(getSelection().isCollapsed, "pre-wrap: Selection must be collapsed");
|
||||
is(getSelection().focusNode, div.lastChild,
|
||||
"pre-wrap: Focus must be in final text node");
|
||||
|
|
|
@ -18,23 +18,23 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1270235
|
|||
<div id="edit1" contenteditable="true"><p>AB</p></div>
|
||||
<script type="application/javascript">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SimpleTest.waitForFocus(()=>{
|
||||
let element = document.getElementById('edit1');
|
||||
SimpleTest.waitForFocus(() => {
|
||||
let element = document.getElementById("edit1");
|
||||
element.focus();
|
||||
let textNode = element.firstChild.firstChild;
|
||||
let node = textNode.splitText(0);
|
||||
node.parentNode.removeChild(node);
|
||||
node.remove();
|
||||
|
||||
ok(!node.parentNode, 'parent must be null');
|
||||
ok(!node.parentNode, "parent must be null");
|
||||
|
||||
let newRange = document.createRange();
|
||||
let newRange = document.createRange();
|
||||
newRange.setStart(node, 0);
|
||||
newRange.setEnd(node, 0);
|
||||
let selection = document.getSelection();
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(newRange);
|
||||
|
||||
ok(selection.isCollapsed, 'isCollapsed must be true');
|
||||
ok(selection.isCollapsed, "isCollapsed must be true");
|
||||
|
||||
// Don't crash by user input
|
||||
sendString("X");
|
||||
|
|
|
@ -8,6 +8,10 @@
|
|||
<script class="testbody" type="application/javascript">
|
||||
|
||||
function runTest() {
|
||||
const headingone = document.getElementById("headingone");
|
||||
const celltwo = document.getElementById("celltwo");
|
||||
const pasteframe = document.getElementById("pasteframe");
|
||||
|
||||
// Copy content from table.
|
||||
var selection = getSelection();
|
||||
var startRange = document.createRange();
|
||||
|
|
|
@ -32,10 +32,10 @@ SimpleTest.waitForFocus(function() {
|
|||
composition: {
|
||||
string: "DEF",
|
||||
clauses: [
|
||||
{ length: 3, attr: COMPOSITION_ATTR_RAW_CLAUSE }
|
||||
]
|
||||
{ length: 3, attr: COMPOSITION_ATTR_RAW_CLAUSE },
|
||||
],
|
||||
},
|
||||
caret: { start: 3, length: 0 }
|
||||
caret: { start: 3, length: 0 },
|
||||
});
|
||||
ok(elm.textContent == "ABCDEF", "composing text should be set");
|
||||
|
||||
|
@ -44,10 +44,10 @@ SimpleTest.waitForFocus(function() {
|
|||
composition: {
|
||||
string: "GHI",
|
||||
clauses: [
|
||||
{ length: 3, attr: COMPOSITION_ATTR_CONVERTED_CLAUSE }
|
||||
]
|
||||
{ length: 3, attr: COMPOSITION_ATTR_CONVERTED_CLAUSE },
|
||||
],
|
||||
},
|
||||
caret: { start: 0, length: 0 }
|
||||
caret: { start: 0, length: 0 },
|
||||
});
|
||||
ok(elm.textContent == "ABCGHI", "composing text should be replaced");
|
||||
|
||||
|
@ -56,10 +56,10 @@ SimpleTest.waitForFocus(function() {
|
|||
composition: {
|
||||
string: "JKL",
|
||||
clauses: [
|
||||
{ length: 3, attr: COMPOSITION_ATTR_CONVERTED_CLAUSE }
|
||||
]
|
||||
{ length: 3, attr: COMPOSITION_ATTR_CONVERTED_CLAUSE },
|
||||
],
|
||||
},
|
||||
caret: { start: 0, length: 0 }
|
||||
caret: { start: 0, length: 0 },
|
||||
});
|
||||
ok(elm.textContent == "ABCJKL", "composing text should be replaced");
|
||||
|
||||
|
@ -68,10 +68,10 @@ SimpleTest.waitForFocus(function() {
|
|||
composition: {
|
||||
string: "MNO",
|
||||
clauses: [
|
||||
{ length: 3, attr: COMPOSITION_ATTR_CONVERTED_CLAUSE }
|
||||
]
|
||||
{ length: 3, attr: COMPOSITION_ATTR_CONVERTED_CLAUSE },
|
||||
],
|
||||
},
|
||||
caret: { start: 1, length: 0 }
|
||||
caret: { start: 1, length: 0 },
|
||||
});
|
||||
ok(elm.textContent == "ABCMNO", "composing text should be replaced");
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1315065
|
|||
<script type="application/javascript">
|
||||
/** Test for Bug 1315065 **/
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SimpleTest.waitForFocus(()=>{
|
||||
SimpleTest.waitForFocus(() => {
|
||||
var editor = document.getElementsByTagName("div")[0];
|
||||
function initForBackspace(aSelectionCollapsedTo /* = 0 ~ 3 */) {
|
||||
editor.innerHTML = "<p id='p'>abc<br></p>";
|
||||
|
@ -55,13 +55,13 @@ SimpleTest.waitForFocus(()=>{
|
|||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < 4; i++) {
|
||||
for (let i = 0; i < 4; i++) {
|
||||
const kDescription = i == 0 ? "Backspace from immediately after the last character" :
|
||||
"Backspace from " + i + "th empty text node";
|
||||
editor.focus();
|
||||
initForBackspace(i);
|
||||
synthesizeKey("KEY_Backspace");
|
||||
var p = document.getElementById("p");
|
||||
let p = document.getElementById("p");
|
||||
ok(p, kDescription + ": <p> element shouldn't be removed by Backspace key press");
|
||||
is(p.tagName.toLowerCase(), "p", kDescription + ": <p> element shouldn't be removed by Backspace key press");
|
||||
// When Backspace key is pressed even in empty text nodes, Gecko should not remove empty text nodes for now
|
||||
|
@ -112,7 +112,7 @@ SimpleTest.waitForFocus(()=>{
|
|||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < 4; i++) {
|
||||
for (let i = 0; i < 4; i++) {
|
||||
const kDescription = i == 0 ? "Delete from immediately before the first character" :
|
||||
"Delete from " + i + "th empty text node";
|
||||
editor.focus();
|
||||
|
|
|
@ -18,7 +18,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1316302
|
|||
<script type="application/javascript">
|
||||
/** Test for Bug 1316302 **/
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SimpleTest.waitForFocus(()=>{
|
||||
SimpleTest.waitForFocus(() => {
|
||||
var editor = document.getElementsByTagName("div")[0];
|
||||
var blockquote = document.getElementsByTagName("blockquote")[0];
|
||||
var selection = window.getSelection();
|
||||
|
|
|
@ -16,9 +16,9 @@
|
|||
<script class="testbody" type="text/javascript">
|
||||
|
||||
var outerEditor = document.getElementById("outerEditor");
|
||||
var innerEditor = document.getElementById("innerEditor");
|
||||
|
||||
function runTests()
|
||||
{
|
||||
function runTests() {
|
||||
outerEditor.focus();
|
||||
is(document.activeElement, outerEditor,
|
||||
"outerEditor should have focus");
|
||||
|
|
|
@ -55,7 +55,7 @@ var tests = [
|
|||
"<span>> mailcite<br></span>x<br>" ],
|
||||
// No <br> at the end to simulate prior deletion to the end of the quote.
|
||||
[ "<span _moz_quote=true>> mailcite</span>", 10,
|
||||
"<span>> mailcite</span><br>x<br>" ]
|
||||
"<span>> mailcite</span><br>x<br>" ],
|
||||
];
|
||||
|
||||
/** Test for Bug 1330796 **/
|
||||
|
@ -68,7 +68,7 @@ SimpleTest.waitForFocus(function() {
|
|||
var theEdit = document.getElementById("editable");
|
||||
makeMailEditor();
|
||||
|
||||
for (i = 0; i < tests.length; i++) {
|
||||
for (let i = 0; i < tests.length; i++) {
|
||||
theEdit.innerHTML = tests[i][0];
|
||||
theEdit.focus();
|
||||
var theText = theEdit.firstChild.firstChild;
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче