Merge mozilla-central to inbound. a=merge CLOSED TREE

This commit is contained in:
Noemi Erli 2018-09-14 01:18:29 +03:00
Родитель ff9ffe2ad0 a548d10a8c
Коммит e6319bab61
265 изменённых файлов: 5743 добавлений и 4927 удалений

Просмотреть файл

@ -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>&gt; mailcite<br></span>x<br>" ],
// No <br> at the end to simulate prior deletion to the end of the quote.
[ "<span _moz_quote=true>&gt; mailcite</span>", 10,
"<span>&gt; mailcite</span><br>x<br>" ]
"<span>&gt; 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;

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше