merge mozilla-central to autoland. r=merge a=merge

This commit is contained in:
Sebastian Hengst 2017-10-07 10:52:29 +02:00
Родитель 2d85e5375c 5d61e2eec8
Коммит 3c8747ae61
514 изменённых файлов: 20402 добавлений и 15926 удалений

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

@ -102,7 +102,13 @@ jobs:
job:
type: decision-task
treeherder-symbol: Nfile
target-tasks-method: nightly_file_update
target-tasks-method: file_update
run-on-projects:
- mozilla-central
when: [] # don't run for now due to unforeseen issues
when:
by-project:
# No default branch
mozilla-central:
# Buildbot start time is 10:02am UTC, until we are able to
# disable buildbot scheduling, use +12h
- {hour: 22, minute: 0}

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

@ -34,7 +34,7 @@ ProxyAccessible::GetCOMInterface(void** aOutAccessible) const
return false;
}
if (!mCOMProxy) {
if (!mCOMProxy && mSafeToRecurse) {
// See if we can lazily obtain a COM proxy
AccessibleWrap* wrap = WrapperFor(this);
bool isDefunct = false;

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

@ -27,6 +27,7 @@ public:
ProxyAccessible(uint64_t aID, ProxyAccessible* aParent,
DocAccessibleParent* aDoc, role aRole, uint32_t aInterfaces)
: ProxyAccessibleBase(aID, aParent, aDoc, aRole, aInterfaces)
, mSafeToRecurse(true)
{
MOZ_COUNT_CTOR(ProxyAccessible);
}
@ -40,7 +41,16 @@ public:
bool GetCOMInterface(void** aOutAccessible) const;
void SetCOMInterface(const RefPtr<IAccessible>& aIAccessible)
{ mCOMProxy = aIAccessible; }
{
if (aIAccessible) {
mCOMProxy = aIAccessible;
} else {
// If we were supposed to be receiving an interface (hence the call to
// this function), but the interface turns out to be null, then we're
// broken for some reason.
mSafeToRecurse = false;
}
}
protected:
explicit ProxyAccessible(DocAccessibleParent* aThisAsDoc)
@ -49,6 +59,7 @@ protected:
private:
RefPtr<IAccessible> mCOMProxy;
bool mSafeToRecurse;
};
}

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

@ -323,6 +323,7 @@ toolbarpaletteitem {
#main-window[inFullscreen][inDOMFullscreen] #fullscr-toggler,
#main-window[inFullscreen][inDOMFullscreen] #sidebar-box,
#main-window[inFullscreen][inDOMFullscreen] #sidebar-splitter,
#main-window[inFullscreen][inDOMFullscreen] #developer-toolbar,
#main-window[inFullscreen]:not([OSXLionFullscreen]) toolbar:not([fullscreentoolbar=true]),
#main-window[inFullscreen] #global-notificationbox,
#main-window[inFullscreen] #high-priority-global-notificationbox {

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

@ -572,10 +572,6 @@
<hbox id="titlebar-content">
<spacer id="titlebar-spacer" flex="1"/>
<hbox id="titlebar-buttonbox-container">
#ifdef XP_WIN
<button class="accessibility-indicator" tooltiptext="&accessibilityIndicator.tooltip;" aria-live="polite"/>
<hbox class="private-browsing-indicator"/>
#endif
<hbox id="titlebar-buttonbox">
<toolbarbutton class="titlebar-button" id="titlebar-min" oncommand="window.minimize();"/>
<toolbarbutton class="titlebar-button" id="titlebar-max" oncommand="onTitlebarMaxClick();"/>

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

@ -5399,10 +5399,6 @@
onget="return this.mCurrentBrowser.contentViewerEdit;"
readonly="true"/>
<property name="contentViewerFile"
onget="return this.mCurrentBrowser.contentViewerFile;"
readonly="true"/>
<property name="contentDocument"
onget="return this.mCurrentBrowser.contentDocument;"
readonly="true"/>

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

@ -1,5 +1,5 @@
This is the PDF.js project output, https://github.com/mozilla/pdf.js
Current extension version is: 1.9.607
Current extension version is: 1.9.630
Taken from upstream commit: b3f84112
Taken from upstream commit: ec469673

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

@ -706,9 +706,6 @@ var Util = function UtilClosure() {
}
return result;
};
Util.sign = function Util_sign(num) {
return num < 0 ? -1 : 1;
};
var ROMAN_NUMBER_MAP = ['', 'C', 'CC', 'CCC', 'CD', 'D', 'DC', 'DCC', 'DCCC', 'CM', '', 'X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC', '', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX'];
Util.toRoman = function Util_toRoman(number, lowerCase) {
assert(Number.isInteger(number) && number > 0, 'The number should be a positive integer.');
@ -1993,7 +1990,7 @@ function _fetchDocument(worker, source, pdfDataRangeTransport, docId) {
if (worker.destroyed) {
return Promise.reject(new Error('Worker was destroyed'));
}
let apiVersion = '1.9.607';
let apiVersion = '1.9.630';
source.disableAutoFetch = (0, _dom_utils.getDefaultSetting)('disableAutoFetch');
source.disableStream = (0, _dom_utils.getDefaultSetting)('disableStream');
source.chunkedViewerLoading = !!pdfDataRangeTransport;
@ -3314,8 +3311,8 @@ var _UnsupportedManager = function UnsupportedManagerClosure() {
}();
var version, build;
{
exports.version = version = '1.9.607';
exports.build = build = 'b3f84112';
exports.version = version = '1.9.630';
exports.build = build = 'ec469673';
}
exports.getDocument = getDocument;
exports.LoopbackPort = LoopbackPort;
@ -5054,8 +5051,8 @@ exports.SVGGraphics = SVGGraphics;
"use strict";
var pdfjsVersion = '1.9.607';
var pdfjsBuild = 'b3f84112';
var pdfjsVersion = '1.9.630';
var pdfjsBuild = 'ec469673';
var pdfjsSharedUtil = __w_pdfjs_require__(0);
var pdfjsDisplayGlobal = __w_pdfjs_require__(13);
var pdfjsDisplayAPI = __w_pdfjs_require__(3);
@ -8153,7 +8150,7 @@ if (isReadableStreamSupported) {
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.PDFJS = exports.isWorker = exports.globalScope = undefined;
exports.PDFJS = exports.globalScope = undefined;
var _api = __w_pdfjs_require__(3);
@ -8175,14 +8172,13 @@ var _svg = __w_pdfjs_require__(8);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var isWorker = typeof window === 'undefined';
if (!_global_scope2.default.PDFJS) {
_global_scope2.default.PDFJS = {};
}
var PDFJS = _global_scope2.default.PDFJS;
{
PDFJS.version = '1.9.607';
PDFJS.build = 'b3f84112';
PDFJS.version = '1.9.630';
PDFJS.build = 'ec469673';
}
PDFJS.pdfBug = false;
if (PDFJS.verbosity !== undefined) {
@ -8260,7 +8256,6 @@ PDFJS.Metadata = _metadata.Metadata;
PDFJS.SVGGraphics = _svg.SVGGraphics;
PDFJS.UnsupportedManager = _api._UnsupportedManager;
exports.globalScope = _global_scope2.default;
exports.isWorker = isWorker;
exports.PDFJS = PDFJS;
/***/ }),

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

@ -706,9 +706,6 @@ var Util = function UtilClosure() {
}
return result;
};
Util.sign = function Util_sign(num) {
return num < 0 ? -1 : 1;
};
var ROMAN_NUMBER_MAP = ['', 'C', 'CC', 'CCC', 'CD', 'D', 'DC', 'DCC', 'DCCC', 'CM', '', 'X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC', '', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX'];
Util.toRoman = function Util_toRoman(number, lowerCase) {
assert(Number.isInteger(number) && number > 0, 'The number should be a positive integer.');
@ -23826,8 +23823,8 @@ exports.PostScriptCompiler = PostScriptCompiler;
"use strict";
var pdfjsVersion = '1.9.607';
var pdfjsBuild = 'b3f84112';
var pdfjsVersion = '1.9.630';
var pdfjsBuild = 'ec469673';
var pdfjsCoreWorker = __w_pdfjs_require__(18);
exports.WorkerMessageHandler = pdfjsCoreWorker.WorkerMessageHandler;
@ -24022,7 +24019,7 @@ var WorkerMessageHandler = {
var cancelXHRs = null;
var WorkerTasks = [];
let apiVersion = docParams.apiVersion;
let workerVersion = '1.9.607';
let workerVersion = '1.9.630';
if (apiVersion !== null && apiVersion !== workerVersion) {
throw new Error(`The API version "${apiVersion}" does not match ` + `the Worker version "${workerVersion}".`);
}

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

@ -4441,7 +4441,7 @@ class PDFHistory {
this._blockHashChange = 0;
this._currentHash = getCurrentHash();
this._numPositionUpdates = 0;
this._currentUid = this._uid = 0;
this._uid = this._maxUid = 0;
this._destination = null;
this._position = null;
if (!this._isValidState(state) || resetHistory) {
@ -4526,7 +4526,7 @@ class PDFHistory {
return;
}
let state = window.history.state;
if (this._isValidState(state) && state.uid < this._uid - 1) {
if (this._isValidState(state) && state.uid < this._maxUid) {
window.history.forward();
}
}
@ -4537,13 +4537,14 @@ class PDFHistory {
let shouldReplace = forceReplace || !this._destination;
let newState = {
fingerprint: this.fingerprint,
uid: shouldReplace ? this._currentUid : this._uid,
uid: shouldReplace ? this._uid : this._uid + 1,
destination
};
this._updateInternalState(destination, newState.uid);
if (shouldReplace) {
window.history.replaceState(newState, '');
} else {
this._maxUid = this._uid;
window.history.pushState(newState, '');
}
}
@ -4603,8 +4604,7 @@ class PDFHistory {
delete destination.temporary;
}
this._destination = destination;
this._currentUid = uid;
this._uid = this._currentUid + 1;
this._uid = uid;
this._numPositionUpdates = 0;
}
_updateViewarea({ location }) {
@ -4638,7 +4638,7 @@ class PDFHistory {
hashChanged = this._currentHash !== newHash;
this._currentHash = newHash;
if (!state || false) {
this._currentUid = this._uid;
this._uid++;
let { hash, page, rotation } = parseCurrentHash(this.linkService);
this._pushOrReplaceState({
hash,

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

@ -1,997 +0,0 @@
{
"ach": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"af": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"an": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"ar": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"as": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"ast": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"az": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"be": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"bg": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"bn-BD": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"bn-IN": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"br": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"bs": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"ca": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"cak": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"cs": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"cy": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"da": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"de": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"dsb": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"el": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"en-GB": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"en-ZA": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"eo": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"es-AR": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"es-CL": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"es-ES": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"es-MX": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"et": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"eu": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"fa": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"ff": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"fi": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"fr": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"fy-NL": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"ga-IE": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"gd": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"gl": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"gn": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"gu-IN": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"he": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"hi-IN": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"hr": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"hsb": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"hu": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"hy-AM": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"ia": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"id": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"is": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"it": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"ja": {
"platforms": [
"linux",
"linux64",
"win32",
"win64"
],
"revision": "default"
},
"ja-JP-mac": {
"platforms": [
"macosx64"
],
"revision": "default"
},
"ka": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"kab": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"kk": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"km": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"kn": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"ko": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"lij": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"lo": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"lt": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"ltg": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"lv": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"mai": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"mk": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"ml": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"mr": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"ms": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"my": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"nb-NO": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"ne-NP": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"nl": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"nn-NO": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"or": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"pa-IN": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"pl": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"pt-BR": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"pt-PT": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"rm": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"ro": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"ru": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"si": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"sk": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"sl": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"son": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"sq": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"sr": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"sv-SE": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"ta": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"te": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"th": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"tl": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"tr": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"uk": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"ur": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"uz": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"vi": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"xh": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"zh-CN": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
},
"zh-TW": {
"platforms": [
"linux",
"linux64",
"macosx64",
"win32",
"win64"
],
"revision": "default"
}
}

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

@ -2,9 +2,8 @@
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<svg width="16" height="16" viewBox="0 0 16 16" fill="context-fill" fill-opacity="context-fill-opacity" xmlns="http://www.w3.org/2000/svg">
<path fill-opacity=".15" d="M5,1H1C0.4,1,0,1.4,0,2v12.1C0,14.6,0.4,15,0.9,15h14.2c0.5,0,0.9-0.4,0.9-0.9V3.9C16,3.4,15.6,3,15.1,3H7 L6.2,1.9C6.2,1.9,5.6,1,5,1L5,1z"/>
<path d="M4.9,2C5,2.1,5.2,2.3,5.4,2.5l0.8,1.1L6.5,4H7h7.5C14.8,4,15,4.2,15,4.5v9c0,0.3-0.2,0.5-0.5,0.5h-13 C1.2,14,1,13.8,1,13.5v-11C1,2.2,1.2,2,1.5,2H4.9 M5,1H1C0.4,1,0,1.4,0,2v12.1C0,14.6,0.4,15,0.9,15h14.2c0.5,0,0.9-0.4,0.9-0.9V3.9 C16,3.4,15.6,3,15.1,3H7L6.2,1.9C6.2,1.9,5.6,1,5,1L5,1z"/>
<path fill-opacity=".15" d="M14,5H2C0.9,5,0,5.9,0,7v7c0,0.6,0.4,1,1,1h14c0.6,0,1-0.4,1-1V7C16,5.9,15.1,5,14,5L14,5z"/>
<path fill-opacity=".15" d="M16,13H0v1c0,0.6,0.4,1,1,1h14c0.6,0,1-0.4,1-1V13z"/>
<path d="M14,6c0.6,0,1,0.4,1,1v6.5c0,0.3-0.2,0.5-0.5,0.5h-13C1.2,14,1,13.8,1,13.5V7c0-0.6,0.4-1,1-1H14 M14,5H2 C0.9,5,0,5.9,0,7v7c0,0.6,0.4,1,1,1h14c0.6,0,1-0.4,1-1V7C16,5.9,15.1,5,14,5L14,5z"/>
<path d="M14.5 3H6.914a.5.5 0 0 1-.354-.146L5.146 1.439A1.491 1.491 0 0 0 4.086 1H1.5A1.5 1.5 0 0 0 0 2.5v11A1.5 1.5 0 0 0 1.5 15h13a1.5 1.5 0 0 0 1.5-1.5v-9A1.5 1.5 0 0 0 14.5 3zm.5 10.5a.5.5 0 0 1-.5.5h-13a.5.5 0 0 1-.5-.5V6h14zM1 5V2.5a.5.5 0 0 1 .5-.5h2.586a.5.5 0 0 1 .354.146l1.414 1.415A1.491 1.491 0 0 0 6.914 4H14.5a.5.5 0 0 1 .5.5V5z"/>
<path d="M15 13.5a.5.5 0 0 1-.5.5h-13a.5.5 0 0 1-.5-.5V6h14z" fill-opacity=".2"/>
<path d="M1 5V2.5a.5.5 0 0 1 .5-.5h2.586a.5.5 0 0 1 .354.146l1.414 1.415A1.491 1.491 0 0 0 6.914 4H14.5a.5.5 0 0 1 .5.5V5z" fill-opacity=".1"/>
<path d="M15 13.5a.5.5 0 0 1-.5.5h-13a.5.5 0 0 1-.5-.5V13h14z" fill-opacity=".05"/>
</svg>

До

Ширина:  |  Высота:  |  Размер: 1.2 KiB

После

Ширина:  |  Высота:  |  Размер: 1.0 KiB

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

@ -1076,21 +1076,25 @@ notification[value="translation"] {
/* Private browsing and accessibility indicators */
@media (-moz-os-version: windows-win7) {
/* Making sure that indicators take up all available vertical space. */
:root[tabsintitlebar]:not([inFullscreen]) .private-browsing-indicator,
:root[tabsintitlebar]:not([inFullscreen]) .accessibility-indicator {
height: var(--tab-min-height);
}
:root[sizemode="normal"][chromehidden~="menubar"] #toolbar-menubar ~ #TabsToolbar > .private-browsing-indicator,
:root[sizemode="normal"][chromehidden~="menubar"] #toolbar-menubar ~ #TabsToolbar > .accessibility-indicator,
:root[sizemode="normal"] #toolbar-menubar[autohide="true"][inactive] ~ #TabsToolbar > .private-browsing-indicator,
:root[sizemode="normal"] #toolbar-menubar[autohide="true"][inactive] ~ #TabsToolbar > .accessibility-indicator {
margin-top: calc(-1 * var(--space-above-tabbar));
}
:root[tabsintitlebar][sizemode="normal"]:not([inFullscreen]) .private-browsing-indicator,
:root[tabsintitlebar][sizemode="normal"]:not([inFullscreen]) .accessibility-indicator {
height: calc(var(--tab-min-height) + 4px);
/* Compensate for 4px extra margin on top of the tabs toolbar on Windows 7. */
@media (-moz-os-version: windows-win7) {
:root[sizemode="normal"][chromehidden~="menubar"] #toolbar-menubar ~ #TabsToolbar > .private-browsing-indicator,
:root[sizemode="normal"][chromehidden~="menubar"] #toolbar-menubar ~ #TabsToolbar > .accessibility-indicator,
:root[sizemode="normal"] #toolbar-menubar[autohide="true"][inactive] ~ #TabsToolbar > .private-browsing-indicator,
:root[sizemode="normal"] #toolbar-menubar[autohide="true"][inactive] ~ #TabsToolbar > .accessibility-indicator {
margin-top: calc(-1 * (var(--space-above-tabbar) + 4px));
}
}
:root:-moz-any([tabsintitlebar], [inFullscreen]):not([privatebrowsingmode=temporary]) .accessibility-indicator,
:root:-moz-any([tabsintitlebar], [inFullscreen]) .private-browsing-indicator {
:root:not([privatebrowsingmode=temporary]) .accessibility-indicator,
.private-browsing-indicator {
margin-inline-end: 12px;
}
@ -1099,13 +1103,6 @@ notification[value="translation"] {
margin-inline-start: 12px;
}
:root[accessibilitymode][tabsintitlebar]:not([inFullscreen]) > #tab-view-deck > #browser-panel > #navigator-toolbox > #TabsToolbar > .accessibility-indicator,
:root[privatebrowsingmode=temporary][tabsintitlebar]:not([inFullscreen]) > #tab-view-deck > #browser-panel > #navigator-toolbox > #TabsToolbar > .private-browsing-indicator,
:root[accessibilitymode]:not([tabsintitlebar]) > #titlebar > #titlebar-content > #titlebar-secondary-buttonbox > .accessibility-indicator,
:root[privatebrowsingmode=temporary]:not([tabsintitlebar]) > #titlebar > #titlebar-content > #titlebar-secondary-buttonbox > .private-browsing-indicator {
display: none;
}
/* End private browsing and accessibility indicators */
%include ../shared/UITour.inc.css

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

@ -1250,9 +1250,9 @@ Inspector.prototype = {
}));
menu.append(new MenuItem({
id: "node-menu-collapse",
label: INSPECTOR_L10N.getStr("inspectorCollapseNode.label"),
label: INSPECTOR_L10N.getStr("inspectorCollapseAll.label"),
disabled: !isNodeWithChildren || !markupContainer.expanded,
click: () => this.collapseNode(),
click: () => this.collapseAll(),
}));
menu.append(new MenuItem({
@ -1981,8 +1981,8 @@ Inspector.prototype = {
this.markup.expandAll(this.selection.nodeFront);
},
collapseNode: function () {
this.markup.collapseNode(this.selection.nodeFront);
collapseAll: function () {
this.markup.collapseAll(this.selection.nodeFront);
},
/**

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

@ -263,10 +263,10 @@ inspectorUseInConsole.label=Use in Console
# mark-up elements
inspectorExpandNode.label=Expand All
# LOCALIZATION NOTE (inspectorCollapseNode.label): This is the label
# LOCALIZATION NOTE (inspectorCollapseAll.label): This is the label
# shown in the inspector contextual-menu for recursively collapsing
# mark-up elements
inspectorCollapseNode.label=Collapse
inspectorCollapseAll.label=Collapse All
# LOCALIZATION NOTE (inspectorScreenshotNode.label): This is the label
# shown in the inspector contextual-menu for the item that lets users take

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

@ -3,10 +3,18 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
:root {
--markup-hidden-attr-name-color: #CA60AC;
--markup-hidden-attr-value-color: #5C6D87;
--markup-hidden-punctuation-color: #909090;
--markup-hidden-tag-color: #97A4B3;
--markup-outline: var(--theme-splitter-color);
}
.theme-dark:root {
--markup-hidden-attr-name-color: #CC8EC8;
--markup-hidden-attr-value-color: #9893A3;
--markup-hidden-punctuation-color: #909090;
--markup-hidden-tag-color: #AFB5BF;
--markup-outline: var(--theme-selection-background);
}
@ -332,6 +340,22 @@ ul.children + .tag-line::before {
z-index: 1;
}
.not-displayed {
color: var(--markup-hidden-punctuation-color);
}
.not-displayed .attr-name {
color: var(--markup-hidden-attr-name-color);
}
.not-displayed .attr-value {
color: var(--markup-hidden-attr-value-color);
}
.not-displayed .tag {
color: var(--markup-hidden-tag-color);
}
/* Firebug Theme */
.theme-firebug .theme-fg-color3 {
@ -353,6 +377,12 @@ ul.children + .tag-line::before {
font-size: var(--theme-toolbar-font-size);
}
/* In case a node isn't displayed in the page, we fade the syntax highlighting */
.theme-firebug .not-displayed .open,
.theme-firebug .not-displayed .close {
opacity: .5;
}
/* Selected nodes in the tree should have light selected text.
theme-selected doesn't work in this case since the text is a
sibling of the class, not a child. */
@ -383,12 +413,6 @@ ul.children + .tag-line::before {
color: #787878;
}
/* In case a node isn't displayed in the page, we fade the syntax highlighting */
.not-displayed .open,
.not-displayed .close {
opacity: .5;
}
/* Events */
.markupview-events {
font-size: 8px;

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

@ -810,8 +810,8 @@ WebConsoleActor.prototype =
}
// See `window` definition. It isn't always a DOM Window.
let requestStartTime = this.window && this.window.performance ?
this.window.performance.timing.requestStart : 0;
let winStartTime = this.window && this.window.performance ?
this.window.performance.timing.navigationStart : 0;
let cache = this.consoleAPIListener
.getCachedMessages(!this.parentActor.isRootActor);
@ -819,7 +819,7 @@ WebConsoleActor.prototype =
// Filter out messages that came from a ServiceWorker but happened
// before the page was requested.
if (cachedMessage.innerID === "ServiceWorker" &&
requestStartTime > cachedMessage.timeStamp) {
winStartTime > cachedMessage.timeStamp) {
return;
}

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

@ -41,7 +41,6 @@ XPIDL_SOURCES += [
'nsIContentViewer.idl',
'nsIContentViewerContainer.idl',
'nsIContentViewerEdit.idl',
'nsIContentViewerFile.idl',
'nsIContextMenuListener.idl',
'nsIContextMenuListener2.idl',
'nsIDocCharset.idl',

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

@ -1,31 +0,0 @@
/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
interface nsIDOMWindow;
interface nsIPrintSettings;
interface nsIWebProgressListener;
%{ C++
#include <stdio.h>
%}
[ptr] native FILE(FILE);
/**
* The nsIDocShellFile
*/
[scriptable, uuid(564a3276-6228-401e-9b5c-d82cb382a60f)]
interface nsIContentViewerFile : nsISupports
{
readonly attribute boolean printable;
[noscript] void print(in boolean aSilent,
in FILE aDebugFile,
in nsIPrintSettings aPrintSettings);
};

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

@ -6,6 +6,7 @@
#include "mozilla/dom/CustomElementRegistry.h"
#include "mozilla/CycleCollectedJSContext.h"
#include "mozilla/dom/CustomElementRegistryBinding.h"
#include "mozilla/dom/HTMLElementBinding.h"
#include "mozilla/dom/WebComponentsBinding.h"

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

@ -47,7 +47,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMIntersectionObserver)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocument)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mCallback)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mRoot)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mQueuedEntries)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
@ -55,7 +54,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMIntersectionObserver)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocument)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCallback)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRoot)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mQueuedEntries)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
@ -81,7 +79,10 @@ DOMIntersectionObserver::Constructor(const mozilla::dom::GlobalObject& aGlobal,
RefPtr<DOMIntersectionObserver> observer =
new DOMIntersectionObserver(window.forget(), aCb);
observer->mRoot = aOptions.mRoot;
if (aOptions.mRoot) {
observer->mRoot = aOptions.mRoot;
observer->mRoot->RegisterIntersectionObserver(observer);
}
if (!observer->SetRootMargin(aOptions.mRootMargin)) {
aRv.ThrowDOMException(NS_ERROR_DOM_SYNTAX_ERR,
@ -175,8 +176,13 @@ DOMIntersectionObserver::Unobserve(Element& aTarget)
}
void
DOMIntersectionObserver::UnlinkTarget(Element& aTarget)
DOMIntersectionObserver::UnlinkElement(Element& aTarget)
{
if (mRoot && mRoot == &aTarget) {
mRoot = nullptr;
Disconnect();
return;
}
mObservationTargets.RemoveElement(&aTarget);
if (mObservationTargets.Length() == 0) {
Disconnect();

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

@ -116,7 +116,11 @@ class DOMIntersectionObserver final : public nsISupports,
public:
DOMIntersectionObserver(already_AddRefed<nsPIDOMWindowInner>&& aOwner,
mozilla::dom::IntersectionCallback& aCb)
: mOwner(aOwner), mDocument(mOwner->GetExtantDoc()), mCallback(&aCb), mConnected(false)
: mOwner(aOwner),
mDocument(mOwner->GetExtantDoc()),
mCallback(&aCb),
mRoot(nullptr),
mConnected(false)
{
}
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
@ -152,7 +156,7 @@ public:
void Observe(Element& aTarget);
void Unobserve(Element& aTarget);
void UnlinkTarget(Element& aTarget);
void UnlinkElement(Element& aTarget);
void Disconnect();
void TakeRecords(nsTArray<RefPtr<DOMIntersectionObserverEntry>>& aRetVal);
@ -176,11 +180,12 @@ protected:
nsCOMPtr<nsPIDOMWindowInner> mOwner;
RefPtr<nsIDocument> mDocument;
RefPtr<mozilla::dom::IntersectionCallback> mCallback;
RefPtr<Element> mRoot;
// Raw pointer which is explicitly cleared by UnlinkElement().
Element* mRoot;
nsCSSRect mRootMargin;
nsTArray<double> mThresholds;
// Holds raw pointers which are explicitly cleared by UnlinkTarget().
// Holds raw pointers which are explicitly cleared by UnlinkElement().
nsTArray<Element*> mObservationTargets;
nsTArray<RefPtr<DOMIntersectionObserverEntry>> mQueuedEntries;

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

@ -4194,13 +4194,6 @@ Element::ClearDataset()
slots->mDataset = nullptr;
}
nsDataHashtable<nsRefPtrHashKey<DOMIntersectionObserver>, int32_t>*
Element::RegisteredIntersectionObservers()
{
nsExtendedDOMSlots* slots = ExtendedDOMSlots();
return &slots->mRegisteredIntersectionObservers;
}
enum nsPreviousIntersectionThreshold {
eUninitialized = -2,
eNonIntersecting = -1
@ -4209,8 +4202,21 @@ enum nsPreviousIntersectionThreshold {
void
Element::RegisterIntersectionObserver(DOMIntersectionObserver* aObserver)
{
RegisteredIntersectionObservers()->LookupForAdd(aObserver).OrInsert([]() {
// Value can be:
IntersectionObserverList* observers =
static_cast<IntersectionObserverList*>(
GetProperty(nsGkAtoms::intersectionobserverlist)
);
if (!observers) {
observers = new IntersectionObserverList();
observers->Put(aObserver, eUninitialized);
SetProperty(nsGkAtoms::intersectionobserverlist, observers,
nsINode::DeleteProperty<IntersectionObserverList>);
return;
}
observers->LookupForAdd(aObserver).OrInsert([]() {
// If element is being observed, value can be:
// -2: Makes sure next calculated threshold always differs, leading to a
// notification task being scheduled.
// -1: Non-intersecting.
@ -4222,14 +4228,44 @@ Element::RegisterIntersectionObserver(DOMIntersectionObserver* aObserver)
void
Element::UnregisterIntersectionObserver(DOMIntersectionObserver* aObserver)
{
RegisteredIntersectionObservers()->Remove(aObserver);
IntersectionObserverList* observers =
static_cast<IntersectionObserverList*>(
GetProperty(nsGkAtoms::intersectionobserverlist)
);
if (observers) {
observers->Remove(aObserver);
}
}
void
Element::UnlinkIntersectionObservers()
{
IntersectionObserverList* observers =
static_cast<IntersectionObserverList*>(
GetProperty(nsGkAtoms::intersectionobserverlist)
);
if (!observers) {
return;
}
for (auto iter = observers->Iter(); !iter.Done(); iter.Next()) {
DOMIntersectionObserver* observer = iter.Key();
observer->UnlinkElement(*this);
}
observers->Clear();
}
bool
Element::UpdateIntersectionObservation(DOMIntersectionObserver* aObserver, int32_t aThreshold)
{
IntersectionObserverList* observers =
static_cast<IntersectionObserverList*>(
GetProperty(nsGkAtoms::intersectionobserverlist)
);
if (!observers) {
return false;
}
bool updated = false;
if (auto entry = RegisteredIntersectionObservers()->Lookup(aObserver)) {
if (auto entry = observers->Lookup(aObserver)) {
updated = entry.Data() != aThreshold;
entry.Data() = aThreshold;
}

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

@ -73,6 +73,8 @@ namespace dom {
class ElementOrCSSPseudoElement;
class UnrestrictedDoubleOrKeyframeAnimationOptions;
enum class CallerType : uint32_t;
typedef nsDataHashtable<nsRefPtrHashKey<DOMIntersectionObserver>, int32_t>
IntersectionObserverList;
} // namespace dom
} // namespace mozilla
@ -1436,6 +1438,7 @@ public:
void RegisterIntersectionObserver(DOMIntersectionObserver* aObserver);
void UnregisterIntersectionObserver(DOMIntersectionObserver* aObserver);
void UnlinkIntersectionObservers();
bool UpdateIntersectionObservation(DOMIntersectionObserver* aObserver, int32_t threshold);
protected:
@ -1721,9 +1724,6 @@ protected:
nsDOMTokenList* GetTokenList(nsIAtom* aAtom,
const DOMTokenListSupportedTokenArray aSupportedTokens = nullptr);
nsDataHashtable<nsRefPtrHashKey<DOMIntersectionObserver>, int32_t>*
RegisteredIntersectionObservers();
private:
/**
* Hook for implementing GetClasses. This is guaranteed to only be

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

@ -793,14 +793,6 @@ FragmentOrElement::nsDOMSlots::Traverse(nsCycleCollectionTraversalCallback &cb)
}
}
for (auto iter = mExtendedSlots->mRegisteredIntersectionObservers.Iter();
!iter.Done(); iter.Next()) {
DOMIntersectionObserver* observer = iter.Key();
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
"mExtendedSlots->mRegisteredIntersectionObservers[i]");
cb.NoteXPCOMChild(observer);
}
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mExtendedSlots->mFrameLoaderOrOpener");
cb.NoteXPCOMChild(mExtendedSlots->mFrameLoaderOrOpener);
}
@ -833,7 +825,6 @@ FragmentOrElement::nsDOMSlots::Unlink()
}
mExtendedSlots->mCustomElementData = nullptr;
}
mExtendedSlots->mRegisteredIntersectionObservers.Clear();
nsCOMPtr<nsIFrameLoader> frameLoader =
do_QueryInterface(mExtendedSlots->mFrameLoaderOrOpener);
if (frameLoader) {
@ -1540,6 +1531,11 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(FragmentOrElement)
// which is dispatched in UnbindFromTree.
if (tmp->HasProperties()) {
if (tmp->IsElement()) {
Element* elem = tmp->AsElement();
elem->UnlinkIntersectionObservers();
}
if (tmp->IsHTMLElement() || tmp->IsSVGElement()) {
nsIAtom*** props = Element::HTMLSVGPropertiesToTraverseAndUnlink();
for (uint32_t i = 0; props[i]; ++i) {
@ -1594,14 +1590,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(FragmentOrElement)
{
nsDOMSlots *slots = tmp->GetExistingDOMSlots();
if (slots) {
if (slots->mExtendedSlots && tmp->IsElement()) {
Element* elem = tmp->AsElement();
for (auto iter = slots->mExtendedSlots->mRegisteredIntersectionObservers.Iter();
!iter.Done(); iter.Next()) {
DOMIntersectionObserver* observer = iter.Key();
observer->UnlinkTarget(*elem);
}
}
slots->Unlink();
}
}
@ -2122,6 +2110,19 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(FragmentOrElement)
#endif
if (tmp->HasProperties()) {
if (tmp->IsElement()) {
Element* elem = tmp->AsElement();
IntersectionObserverList* observers =
static_cast<IntersectionObserverList*>(
elem->GetProperty(nsGkAtoms::intersectionobserverlist)
);
if (observers) {
for (auto iter = observers->Iter(); !iter.Done(); iter.Next()) {
DOMIntersectionObserver* observer = iter.Key();
cb.NoteXPCOMChild(observer);
}
}
}
if (tmp->IsHTMLElement() || tmp->IsSVGElement()) {
nsIAtom*** props = Element::HTMLSVGPropertiesToTraverseAndUnlink();
for (uint32_t i = 0; props[i]; ++i) {

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

@ -40,7 +40,6 @@ namespace mozilla {
class DeclarationBlock;
namespace dom {
struct CustomElementData;
class DOMIntersectionObserver;
class Element;
} // namespace dom
} // namespace mozilla
@ -313,12 +312,6 @@ public:
*/
RefPtr<CustomElementData> mCustomElementData;
/**
* Registered Intersection Observers on the element.
*/
nsDataHashtable<nsRefPtrHashKey<DOMIntersectionObserver>, int32_t>
mRegisteredIntersectionObservers;
/**
* For XUL to hold either frameloader or opener.
*/

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

@ -0,0 +1,20 @@
<html>
<head>
<script></script>
<!-- a -->
<script>
window.onload=function(){
let s=window.getSelection();
let r=document.createRange();
r.selectNode(document.getElementById('b'));
s.addRange(r);
try{window.getSelection().modify('extend','forward','word')}catch(e){}
let o=document.getElementById('a');
o.parentNode.replaceChild(document.createElement('col'), o);
}
</script>
>
<template id='a' contenteditable='true'></template>
<header id='b'></header>
<!-- a -->
</html>

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

@ -227,4 +227,5 @@ pref(clipboard.autocopy,true) load 1385272-1.html
load 1393806.html
load 1400701.html
load 1403377.html
load 1405771.html
load 1406109-1.html

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

@ -267,7 +267,6 @@ nsIWordBreaker *nsContentUtils::sWordBreaker;
nsIBidiKeyboard *nsContentUtils::sBidiKeyboard = nullptr;
uint32_t nsContentUtils::sScriptBlockerCount = 0;
uint32_t nsContentUtils::sDOMNodeRemovedSuppressCount = 0;
uint32_t nsContentUtils::sMicroTaskLevel = 0;
AutoTArray<nsCOMPtr<nsIRunnable>, 8>* nsContentUtils::sBlockedScriptRunners = nullptr;
uint32_t nsContentUtils::sRunnersCountAtFirstBlocker = 0;
nsIInterfaceRequestor* nsContentUtils::sSameOriginChecker = nullptr;
@ -5766,51 +5765,6 @@ nsContentUtils::GetStableStateEventTarget()
return sStableStateEventTarget;
}
void
nsContentUtils::EnterMicroTask()
{
MOZ_ASSERT(NS_IsMainThread());
++sMicroTaskLevel;
}
void
nsContentUtils::LeaveMicroTask()
{
MOZ_ASSERT(NS_IsMainThread());
if (--sMicroTaskLevel == 0) {
PerformMainThreadMicroTaskCheckpoint();
}
}
bool
nsContentUtils::IsInMicroTask()
{
MOZ_ASSERT(NS_IsMainThread());
return sMicroTaskLevel != 0;
}
uint32_t
nsContentUtils::MicroTaskLevel()
{
MOZ_ASSERT(NS_IsMainThread());
return sMicroTaskLevel;
}
void
nsContentUtils::SetMicroTaskLevel(uint32_t aLevel)
{
MOZ_ASSERT(NS_IsMainThread());
sMicroTaskLevel = aLevel;
}
void
nsContentUtils::PerformMainThreadMicroTaskCheckpoint()
{
MOZ_ASSERT(NS_IsMainThread());
nsDOMMutationObserver::HandleMutations();
}
/*
* Helper function for nsContentUtils::ProcessViewportInfo.
*
@ -10464,9 +10418,11 @@ nsContentUtils::GetLoadingPrincipalForXULNode(nsIContent* aLoadingNode,
nsAutoString loadingStr;
aLoadingNode->GetAttr(kNameSpaceID_None, nsGkAtoms::loadingprincipal,
loadingStr);
if (loadingStr.IsEmpty()) {
// Fall back to mContent's principal (SystemPrincipal) if 'loadingprincipal'
// isn't specified.
// Fall back to mContent's principal if 'loadingprincipal' isn't specified,
// or if the doc isn't loaded by System Principal.
if (loadingStr.IsEmpty() ||
!aLoadingNode->OwnerDoc()->NodePrincipal()->GetIsSystemPrincipal()) {
loadingPrincipal.forget(aLoadingPrincipal);
return result;
}

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

@ -1948,17 +1948,6 @@ public:
*/
static nsISerialEventTarget* GetStableStateEventTarget();
// Call EnterMicroTask when you're entering JS execution.
// Usually the best way to do this is to use nsAutoMicroTask.
static void EnterMicroTask();
static void LeaveMicroTask();
static bool IsInMicroTask();
static uint32_t MicroTaskLevel();
static void SetMicroTaskLevel(uint32_t aLevel);
static void PerformMainThreadMicroTaskCheckpoint();
/* Process viewport META data. This gives us information for the scale
* and zoom of a page on mobile devices. We stick the information in
* the document header and use it later on after rendering.
@ -3331,7 +3320,7 @@ private:
static bool sInitialized;
static uint32_t sScriptBlockerCount;
static uint32_t sDOMNodeRemovedSuppressCount;
static uint32_t sMicroTaskLevel;
// Not an nsCOMArray because removing elements from those is slower
static AutoTArray<nsCOMPtr<nsIRunnable>, 8>* sBlockedScriptRunners;
static uint32_t sRunnersCountAtFirstBlocker;
@ -3493,19 +3482,6 @@ public:
}
};
class MOZ_STACK_CLASS nsAutoMicroTask
{
public:
nsAutoMicroTask()
{
nsContentUtils::EnterMicroTask();
}
~nsAutoMicroTask()
{
nsContentUtils::LeaveMicroTask();
}
};
namespace mozilla {
namespace dom {

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

@ -26,6 +26,7 @@
#include "nsIDocument.h"
#include "mozilla/dom/Animation.h"
#include "nsIAnimationObserver.h"
#include "nsGlobalWindow.h"
class nsDOMMutationObserver;
using mozilla::dom::MutationObservingInfo;
@ -609,11 +610,7 @@ protected:
bool Suppressed()
{
if (mOwner) {
nsCOMPtr<nsIDocument> d = mOwner->GetExtantDoc();
return d && d->IsInSyncOperation();
}
return false;
return mOwner && nsGlobalWindow::Cast(mOwner)->IsInSyncOperation();
}
static void HandleMutationsInternal();

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

@ -50,7 +50,6 @@
#include "nsViewManager.h"
#include "nsIDOMHTMLCanvasElement.h"
#include "nsLayoutUtils.h"
#include "nsComputedDOMStyle.h"
#include "nsIPresShell.h"
@ -106,6 +105,7 @@
#include "nsNetUtil.h"
#include "nsDocument.h"
#include "HTMLImageElement.h"
#include "HTMLCanvasElement.h"
#include "mozilla/css/ImageLoader.h"
#include "mozilla/layers/APZCTreeManager.h" // for layers::ZoomToRectBehavior
#include "mozilla/dom/Promise.h"
@ -1624,26 +1624,19 @@ nsDOMWindowUtils::GetTranslationNodes(nsIDOMNode* aRoot,
}
static already_AddRefed<DataSourceSurface>
CanvasToDataSourceSurface(nsIDOMHTMLCanvasElement* aCanvas)
CanvasToDataSourceSurface(HTMLCanvasElement* aCanvas)
{
nsCOMPtr<nsINode> node = do_QueryInterface(aCanvas);
if (!node) {
return nullptr;
}
MOZ_ASSERT(node->IsElement(),
"An nsINode that implements nsIDOMHTMLCanvasElement should "
"be an element.");
MOZ_ASSERT(aCanvas);
nsLayoutUtils::SurfaceFromElementResult result =
nsLayoutUtils::SurfaceFromElement(node->AsElement());
nsLayoutUtils::SurfaceFromElement(aCanvas);
MOZ_ASSERT(result.GetSourceSurface());
return result.GetSourceSurface()->GetDataSurface();
}
NS_IMETHODIMP
nsDOMWindowUtils::CompareCanvases(nsIDOMHTMLCanvasElement *aCanvas1,
nsIDOMHTMLCanvasElement *aCanvas2,
nsDOMWindowUtils::CompareCanvases(nsISupports *aCanvas1,
nsISupports *aCanvas2,
uint32_t* aMaxDifference,
uint32_t* retVal)
{
@ -1652,8 +1645,17 @@ nsDOMWindowUtils::CompareCanvases(nsIDOMHTMLCanvasElement *aCanvas1,
retVal == nullptr)
return NS_ERROR_FAILURE;
RefPtr<DataSourceSurface> img1 = CanvasToDataSourceSurface(aCanvas1);
RefPtr<DataSourceSurface> img2 = CanvasToDataSourceSurface(aCanvas2);
nsCOMPtr<nsIContent> contentCanvas1 = do_QueryInterface(aCanvas1);
nsCOMPtr<nsIContent> contentCanvas2 = do_QueryInterface(aCanvas2);
auto canvas1 = HTMLCanvasElement::FromContentOrNull(contentCanvas1);
auto canvas2 = HTMLCanvasElement::FromContentOrNull(contentCanvas2);
if (!canvas1 || !canvas2) {
return NS_ERROR_FAILURE;
}
RefPtr<DataSourceSurface> img1 = CanvasToDataSourceSurface(canvas1);
RefPtr<DataSourceSurface> img2 = CanvasToDataSourceSurface(canvas2);
DataSourceSurface::ScopedMap map1(img1, DataSourceSurface::READ);
DataSourceSurface::ScopedMap map2(img2, DataSourceSurface::READ);

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

@ -13475,8 +13475,12 @@ MarkDocumentTreeToBeInSyncOperation(nsIDocument* aDoc, void* aData)
nsAutoSyncOperation::nsAutoSyncOperation(nsIDocument* aDoc)
{
mMicroTaskLevel = nsContentUtils::MicroTaskLevel();
nsContentUtils::SetMicroTaskLevel(0);
mMicroTaskLevel = 0;
CycleCollectedJSContext* ccjs = CycleCollectedJSContext::Get();
if (ccjs) {
mMicroTaskLevel = ccjs->MicroTaskLevel();
ccjs->SetMicroTaskLevel(0);
}
if (aDoc) {
if (nsPIDOMWindowOuter* win = aDoc->GetWindow()) {
if (nsCOMPtr<nsPIDOMWindowOuter> top = win->GetTop()) {
@ -13495,7 +13499,10 @@ nsAutoSyncOperation::~nsAutoSyncOperation()
}
mDocuments[i]->SetIsInSyncOperation(false);
}
nsContentUtils::SetMicroTaskLevel(mMicroTaskLevel);
CycleCollectedJSContext* ccjs = CycleCollectedJSContext::Get();
if (ccjs) {
ccjs->SetMicroTaskLevel(mMicroTaskLevel);
}
}
gfxUserFontSet*

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

@ -582,6 +582,7 @@ GK_ATOM(int64, "int64")
GK_ATOM(integer, "integer")
GK_ATOM(integrity, "integrity")
GK_ATOM(intersection, "intersection")
GK_ATOM(intersectionobserverlist, "intersectionobserverlist")
GK_ATOM(is, "is")
GK_ATOM(iscontainer, "iscontainer")
GK_ATOM(isempty, "isempty")

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

@ -1313,6 +1313,11 @@ public:
void UpdateTopInnerWindow();
virtual bool IsInSyncOperation() override
{
return GetExtantDoc() && GetExtantDoc()->IsInSyncOperation();
}
protected:
// Web IDL helpers

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

@ -74,6 +74,8 @@ public:
void UnlinkHostObjectURIs();
void TraverseHostObjectURIs(nsCycleCollectionTraversalCallback &aCb);
virtual bool IsInSyncOperation() { return false; }
protected:
virtual ~nsIGlobalObject();

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

@ -25,7 +25,7 @@
#include "xpcpublic.h"
#include "nsContentUtils.h"
#include "nsGlobalWindow.h"
#include "mozilla/CycleCollectedJSContext.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/Date.h"
#include "mozilla/dom/Element.h"
@ -152,7 +152,8 @@ nsJSUtils::ExecutionContext::ExecutionContext(JSContext* aCx,
{
MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext());
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(nsContentUtils::IsInMicroTask());
MOZ_ASSERT(CycleCollectedJSContext::Get() &&
CycleCollectedJSContext::Get()->MicroTaskLevel());
MOZ_ASSERT(mRetValue.isUndefined());
MOZ_ASSERT(js::GetGlobalForObjectCrossCompartment(aGlobal) == aGlobal);
@ -390,7 +391,8 @@ nsJSUtils::CompileModule(JSContext* aCx,
aEvaluationGlobal);
MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx) == aEvaluationGlobal);
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(nsContentUtils::IsInMicroTask());
MOZ_ASSERT(CycleCollectedJSContext::Get() &&
CycleCollectedJSContext::Get()->MicroTaskLevel());
NS_ENSURE_TRUE(xpc::Scriptability::Get(aEvaluationGlobal).Allowed(), NS_OK);
@ -408,7 +410,8 @@ nsJSUtils::ModuleInstantiate(JSContext* aCx, JS::Handle<JSObject*> aModule)
MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext());
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(nsContentUtils::IsInMicroTask());
MOZ_ASSERT(CycleCollectedJSContext::Get() &&
CycleCollectedJSContext::Get()->MicroTaskLevel());
NS_ENSURE_TRUE(xpc::Scriptability::Get(aModule).Allowed(), NS_OK);
@ -426,7 +429,8 @@ nsJSUtils::ModuleEvaluate(JSContext* aCx, JS::Handle<JSObject*> aModule)
MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext());
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(nsContentUtils::IsInMicroTask());
MOZ_ASSERT(CycleCollectedJSContext::Get() &&
CycleCollectedJSContext::Get()->MicroTaskLevel());
NS_ENSURE_TRUE(xpc::Scriptability::Get(aModule).Allowed(), NS_OK);

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

@ -293,19 +293,6 @@ nsNodeUtils::LastRelease(nsINode* aNode)
NodeWillBeDestroyed, (aNode));
}
if (aNode->IsElement()) {
Element* elem = aNode->AsElement();
FragmentOrElement::nsDOMSlots* domSlots =
static_cast<FragmentOrElement::nsDOMSlots*>(slots);
if (domSlots->mExtendedSlots) {
for (auto iter = domSlots->mExtendedSlots->mRegisteredIntersectionObservers.Iter();
!iter.Done(); iter.Next()) {
DOMIntersectionObserver* observer = iter.Key();
observer->UnlinkTarget(*elem);
}
}
}
delete slots;
aNode->mSlots = nullptr;
}
@ -320,6 +307,12 @@ nsNodeUtils::LastRelease(nsINode* aNode)
}
else {
if (aNode->HasProperties()) {
if (aNode->IsElement()) {
Element* elem = aNode->AsElement();
elem->UnlinkIntersectionObservers();
elem->DeleteProperty(nsGkAtoms::intersectionobserverlist);
}
// Strong reference to the document so that deleting properties can't
// delete the document.
nsCOMPtr<nsIDocument> document = aNode->OwnerDoc();

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

@ -947,6 +947,23 @@ nsRange::IntersectsNode(nsINode& aNode, ErrorResult& aRv)
return result;
}
void
nsRange::NotifySelectionListenersAfterRangeSet()
{
if (mSelection) {
// Our internal code should not move focus with using this instance while
// it's calling Selection::NotifySelectionListeners() which may move focus
// or calls selection listeners. So, let's set mCalledByJS to false here
// since non-*JS() methods don't set it to false.
AutoCalledByJSRestore calledByJSRestorer(*this);
mCalledByJS = false;
// Be aware, this range may be modified or stop being a range for selection
// after this call. Additionally, the selection instance may have gone.
RefPtr<Selection> selection = mSelection;
selection->NotifySelectionListeners(calledByJSRestorer.SavedValue());
}
}
/******************************************************
* Private helper routines
******************************************************/
@ -1030,17 +1047,13 @@ nsRange::DoSetRange(const RawRangeBoundary& aStart,
// Notify any selection listeners. This has to occur last because otherwise the world
// could be observed by a selection listener while the range was in an invalid state.
// So we run it off of a script runner to ensure it runs after the mutation observers
// have finished running.
if (mSelection) {
// Our internal code should not move focus with using this instance while
// it's calling Selection::NotifySelectionListeners() which may move focus
// or calls selection listeners. So, let's set mCalledByJS to false here
// since non-*JS() methods don't set it to false.
AutoCalledByJSRestore calledByJSRestorer(*this);
mCalledByJS = false;
// Be aware, this range may be modified or stop being a range for selection
// after this call. Additionally, the selection instance may have gone.
RefPtr<Selection> selection = mSelection;
selection->NotifySelectionListeners(calledByJSRestorer.SavedValue());
nsContentUtils::AddScriptRunner(NewRunnableMethod(
"NotifySelectionListenersAfterRangeSet",
this,
&nsRange::NotifySelectionListenersAfterRangeSet));
}
}

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

@ -427,6 +427,11 @@ public:
*/
void ExcludeNonSelectableNodes(nsTArray<RefPtr<nsRange>>* aOutRanges);
/**
* Notify the selection listeners after a range has been modified.
*/
void NotifySelectionListenersAfterRangeSet();
typedef nsTHashtable<nsPtrHashKey<nsRange> > RangeHashTable;
protected:

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

@ -624,6 +624,7 @@ skip-if = toolkit == 'android'
[test_bug1381710.html]
[test_bug1384658.html]
skip-if = toolkit == 'android'
[test_bug1399603.html]
[test_bug1399605.html]
[test_caretPositionFromPoint.html]
[test_change_policy.html]

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

@ -0,0 +1,63 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test for Bug 1399603</title>
<script type="application/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=1399603">Mozilla Bug 1399603</a>
<p id="display"></p>
<div id="content">
<div id="root">
<div id="target"></div>
</div>
</div>
<pre id="test">
<script type="application/javascript">
function waitForNotification(f) {
requestAnimationFrame(function() {
setTimeout(function() { setTimeout(f); });
});
}
function forceGC() {
SpecialPowers.gc();
SpecialPowers.forceShrinkingGC();
SpecialPowers.forceCC();
SpecialPowers.gc();
SpecialPowers.forceShrinkingGC();
SpecialPowers.forceCC();
}
let content = document.getElementById('content');
let root = document.getElementById('root');
let target = document.getElementById('target');
let entries = [];
let observer = new IntersectionObserver(function(changes) {
entries = entries.concat(changes);
}, { root: root });
observer.observe(target);
waitForNotification(function () {
is(entries.length, 1, "Initial notification.");
root.removeChild(target);
content.removeChild(root);
root = null;
forceGC();
waitForNotification(function () {
is(entries.length, 1, "No new notifications.");
SimpleTest.finish();
});
});
SimpleTest.waitForExplicitFinish();
</script>
</pre>
<div id="log">
</div>
</body>
</html>

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

@ -5,6 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/CallbackObject.h"
#include "mozilla/CycleCollectedJSContext.h"
#include "mozilla/dom/BindingUtils.h"
#include "jsfriendapi.h"
#include "nsIScriptGlobalObject.h"
@ -140,7 +141,10 @@ CallbackObject::CallSetup::CallSetup(CallbackObject* aCallback,
, mIsMainThread(NS_IsMainThread())
{
if (mIsMainThread) {
nsContentUtils::EnterMicroTask();
CycleCollectedJSContext* ccjs = CycleCollectedJSContext::Get();
if (ccjs) {
ccjs->EnterMicroTask();
}
}
// Compute the caller's subject principal (if necessary) early, before we
@ -349,7 +353,10 @@ CallbackObject::CallSetup::~CallSetup()
// It is important that this is the last thing we do, after leaving the
// compartment and undoing all our entry/incumbent script changes
if (mIsMainThread) {
nsContentUtils::LeaveMicroTask();
CycleCollectedJSContext* ccjs = CycleCollectedJSContext::Get();
if (ccjs) {
ccjs->LeaveMicroTask();
}
}
}

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

@ -976,7 +976,7 @@ public:
{
}
virtual void DoUpdate() override
virtual void OnRenderingChange() override
{
if (!mContext) {
MOZ_CRASH("GFX: This should never be called without a context");

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

@ -1819,7 +1819,7 @@ WebGLContext::UpdateContextLossStatus()
if (mCanvasElement) {
nsContentUtils::DispatchTrustedEvent(
mCanvasElement->OwnerDoc(),
static_cast<nsIDOMHTMLCanvasElement*>(mCanvasElement),
static_cast<nsIContent*>(mCanvasElement),
kEventName,
kCanBubble,
kIsCancelable,
@ -1887,7 +1887,7 @@ WebGLContext::UpdateContextLossStatus()
if (mCanvasElement) {
nsContentUtils::DispatchTrustedEvent(
mCanvasElement->OwnerDoc(),
static_cast<nsIDOMHTMLCanvasElement*>(mCanvasElement),
static_cast<nsIContent*>(mCanvasElement),
NS_LITERAL_STRING("webglcontextrestored"),
true,
true);

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

@ -38,7 +38,6 @@ already_AddRefed<Promise>
CredentialsContainer::Get(const CredentialRequestOptions& aOptions)
{
RefPtr<WebAuthnManager> mgr = WebAuthnManager::GetOrCreate();
MOZ_ASSERT(mgr);
return mgr->GetAssertion(mParent, aOptions.mPublicKey);
}
@ -46,7 +45,6 @@ already_AddRefed<Promise>
CredentialsContainer::Create(const CredentialCreationOptions& aOptions)
{
RefPtr<WebAuthnManager> mgr = WebAuthnManager::GetOrCreate();
MOZ_ASSERT(mgr);
return mgr->MakeCredential(mParent, aOptions.mPublicKey);
}

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

@ -1100,7 +1100,10 @@ EventListenerManager::HandleEventSubType(Listener* aListener,
if (NS_SUCCEEDED(result)) {
if (mIsMainThreadELM) {
nsContentUtils::EnterMicroTask();
CycleCollectedJSContext* ccjs = CycleCollectedJSContext::Get();
if (ccjs) {
ccjs->EnterMicroTask();
}
}
// nsIDOMEvent::currentTarget is set in EventDispatcher.
if (listenerHolder.HasWebIDLCallback()) {
@ -1112,7 +1115,10 @@ EventListenerManager::HandleEventSubType(Listener* aListener,
result = listenerHolder.GetXPCOMCallback()->HandleEvent(aDOMEvent);
}
if (mIsMainThreadELM) {
nsContentUtils::LeaveMicroTask();
CycleCollectedJSContext* ccjs = CycleCollectedJSContext::Get();
if (ccjs) {
ccjs->LeaveMicroTask();
}
}
}

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

@ -11,7 +11,6 @@
#include "MultipartBlobImpl.h"
#include "nsIInputStream.h"
#include "nsPIDOMWindow.h"
#include "TemporaryBlobImpl.h"
#include "StreamBlobImpl.h"
#include "StringBlobImpl.h"
@ -94,17 +93,6 @@ Blob::CreateMemoryBlob(nsISupports* aParent, void* aMemoryBuffer,
return blob.forget();
}
/* static */ already_AddRefed<Blob>
Blob::CreateTemporaryBlob(nsISupports* aParent, PRFileDesc* aFD,
uint64_t aStartPos, uint64_t aLength,
const nsAString& aContentType)
{
RefPtr<Blob> blob = Blob::Create(aParent,
new TemporaryBlobImpl(aFD, aStartPos, aLength, aContentType));
MOZ_ASSERT(!blob->mImpl->IsFile());
return blob.forget();
}
Blob::Blob(nsISupports* aParent, BlobImpl* aImpl)
: mImpl(aImpl)
, mParent(aParent)

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

@ -59,11 +59,6 @@ public:
CreateMemoryBlob(nsISupports* aParent, void* aMemoryBuffer, uint64_t aLength,
const nsAString& aContentType);
static already_AddRefed<Blob>
CreateTemporaryBlob(nsISupports* aParent, PRFileDesc* aFD,
uint64_t aStartPos, uint64_t aLength,
const nsAString& aContentType);
BlobImpl* Impl() const
{
return mImpl;

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

@ -254,7 +254,7 @@ FileBlobImpl::CreateInputStream(nsIInputStream** aStream, ErrorResult& aRv)
}
RefPtr<SlicedInputStream> slicedInputStream =
new SlicedInputStream(stream, mStart, mLength);
new SlicedInputStream(stream.forget(), mStart, mLength);
slicedInputStream.forget(aStream);
}

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

@ -73,7 +73,6 @@ public:
protected:
virtual ~FileBlobImpl() = default;
private:
// Create slice
FileBlobImpl(const FileBlobImpl* aOther, uint64_t aStart,
uint64_t aLength, const nsAString& aContentType);

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

@ -7,6 +7,9 @@
#include "MutableBlobStorage.h"
#include "MemoryBlobImpl.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/dom/ipc/TemporaryIPCBlobChild.h"
#include "mozilla/ipc/BackgroundChild.h"
#include "mozilla/ipc/PBackgroundChild.h"
#include "mozilla/Preferences.h"
#include "mozilla/TaskQueue.h"
#include "File.h"
@ -74,78 +77,6 @@ private:
nsresult mRv;
};
// This runnable goes back to the main-thread and informs the BlobStorage about
// the temporary file.
class FileCreatedRunnable final : public Runnable
{
public:
FileCreatedRunnable(MutableBlobStorage* aBlobStorage, PRFileDesc* aFD)
: Runnable("dom::FileCreatedRunnable")
, mBlobStorage(aBlobStorage)
, mFD(aFD)
{
MOZ_ASSERT(aBlobStorage);
MOZ_ASSERT(aFD);
}
NS_IMETHOD
Run() override
{
MOZ_ASSERT(NS_IsMainThread());
mBlobStorage->TemporaryFileCreated(mFD);
mFD = nullptr;
return NS_OK;
}
private:
~FileCreatedRunnable()
{
// If something when wrong, we still have to close the FileDescriptor.
if (mFD) {
PR_Close(mFD);
}
}
RefPtr<MutableBlobStorage> mBlobStorage;
PRFileDesc* mFD;
};
// This runnable creates the temporary file. When done, FileCreatedRunnable is
// dispatched back to the main-thread.
class CreateTemporaryFileRunnable final : public Runnable
{
public:
explicit CreateTemporaryFileRunnable(MutableBlobStorage* aBlobStorage)
: Runnable("dom::CreateTemporaryFileRunnable")
, mBlobStorage(aBlobStorage)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(aBlobStorage);
}
NS_IMETHOD
Run() override
{
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(mBlobStorage);
PRFileDesc* tempFD = nullptr;
nsresult rv = NS_OpenAnonymousTemporaryFile(&tempFD);
if (NS_WARN_IF(NS_FAILED(rv))) {
return NS_OK;
}
// The ownership of the tempFD is moved to the FileCreatedRunnable.
return mBlobStorage->EventTarget()->Dispatch(
new FileCreatedRunnable(mBlobStorage, tempFD), NS_DISPATCH_NORMAL);
}
private:
RefPtr<MutableBlobStorage> mBlobStorage;
};
// Simple runnable to propagate the error to the BlobStorage.
class ErrorPropagationRunnable final : public Runnable
{
@ -281,8 +212,11 @@ private:
// This runnable is dispatched to the main-thread from the IO thread and its
// task is to create the blob and inform the callback.
class CreateBlobRunnable final : public Runnable
, public TemporaryIPCBlobChildCallback
{
public:
NS_DECL_ISUPPORTS_INHERITED
CreateBlobRunnable(MutableBlobStorage* aBlobStorage,
already_AddRefed<nsISupports> aParent,
const nsACString& aContentType,
@ -302,11 +236,27 @@ public:
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mBlobStorage);
mBlobStorage->CreateBlobAndRespond(mParent.forget(), mContentType,
mCallback.forget());
mBlobStorage->AskForBlob(this, mContentType);
return NS_OK;
}
void
OperationSucceeded(BlobImpl* aBlobImpl) override
{
nsCOMPtr<nsISupports> parent(Move(mParent));
RefPtr<MutableBlobStorageCallback> callback(Move(mCallback));
RefPtr<Blob> blob = Blob::Create(parent, aBlobImpl);
callback->BlobStoreCompleted(mBlobStorage, blob, NS_OK);
}
void
OperationFailed(nsresult aRv) override
{
RefPtr<MutableBlobStorageCallback> callback(Move(mCallback));
callback->BlobStoreCompleted(mBlobStorage, nullptr, aRv);
}
private:
~CreateBlobRunnable()
{
@ -327,17 +277,21 @@ private:
RefPtr<MutableBlobStorageCallback> mCallback;
};
NS_IMPL_ISUPPORTS_INHERITED0(CreateBlobRunnable, Runnable)
// This task is used to know when the writing is completed. From the IO thread
// it dispatches a CreateBlobRunnable to the main-thread.
class LastRunnable final : public Runnable
{
public:
LastRunnable(MutableBlobStorage* aBlobStorage,
PRFileDesc* aFD,
nsISupports* aParent,
const nsACString& aContentType,
MutableBlobStorageCallback* aCallback)
: Runnable("dom::LastRunnable")
, mBlobStorage(aBlobStorage)
, mFD(aFD)
, mParent(aParent)
, mContentType(aContentType)
, mCallback(aCallback)
@ -345,13 +299,17 @@ public:
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mBlobStorage);
MOZ_ASSERT(aCallback);
MOZ_ASSERT(aFD);
}
NS_IMETHOD
Run() override
{
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(mBlobStorage);
PR_Close(mFD);
mFD = nullptr;
RefPtr<Runnable> runnable =
new CreateBlobRunnable(mBlobStorage, mParent.forget(),
mContentType, mCallback.forget());
@ -373,6 +331,7 @@ private:
}
RefPtr<MutableBlobStorage> mBlobStorage;
PRFileDesc* mFD;
nsCOMPtr<nsISupports> mParent;
nsCString mContentType;
RefPtr<MutableBlobStorageCallback> mCallback;
@ -381,7 +340,8 @@ private:
} // anonymous namespace
MutableBlobStorage::MutableBlobStorage(MutableBlobStorageType aType,
nsIEventTarget* aEventTarget)
nsIEventTarget* aEventTarget,
uint32_t aMaxMemory)
: mData(nullptr)
, mDataLen(0)
, mDataBufferLen(0)
@ -389,6 +349,7 @@ MutableBlobStorage::MutableBlobStorage(MutableBlobStorageType aType,
, mFD(nullptr)
, mErrorResult(NS_OK)
, mEventTarget(aEventTarget)
, mMaxMemory(aMaxMemory)
{
MOZ_ASSERT(NS_IsMainThread());
@ -396,6 +357,11 @@ MutableBlobStorage::MutableBlobStorage(MutableBlobStorageType aType,
mEventTarget = GetMainThreadEventTarget();
}
if (aMaxMemory == 0 && aType == eCouldBeInTemporaryFile) {
mMaxMemory = Preferences::GetUint("dom.blob.memoryToTemporaryFile",
BLOB_MEMORY_TEMPORARY_FILE);
}
MOZ_ASSERT(mEventTarget);
}
@ -411,6 +377,11 @@ MutableBlobStorage::~MutableBlobStorage()
if (mTaskQueue) {
mTaskQueue->BeginShutdown();
}
if (mActor) {
NS_ProxyRelease("MutableBlobStorage::mActor",
EventTarget(), mActor.forget());
}
}
void
@ -430,18 +401,24 @@ MutableBlobStorage::GetBlobWhenReady(nsISupports* aParent,
MOZ_ASSERT(mFD);
if (NS_FAILED(mErrorResult)) {
MOZ_ASSERT(!mActor);
RefPtr<Runnable> runnable =
new BlobCreationDoneRunnable(this, aCallback, nullptr, mErrorResult);
EventTarget()->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL);
return;
}
MOZ_ASSERT(mActor);
// We want to wait until all the WriteRunnable are completed. The way we do
// this is to go to the I/O thread and then we come back: the runnables are
// executed in order and this LastRunnable will be... the last one.
// This Runnable will also close the FD on the I/O thread.
RefPtr<Runnable> runnable =
new LastRunnable(this, aParent, aContentType, aCallback);
new LastRunnable(this, mFD, aParent, aContentType, aCallback);
DispatchToIOThread(runnable.forget());
mFD = nullptr;
return;
}
@ -490,10 +467,7 @@ MutableBlobStorage::Append(const void* aData, uint32_t aLength)
// If eInMemory is the current Storage state, we could maybe migrate to
// a temporary file.
if (mStorageState == eInMemory && ShouldBeTemporaryStorage(aLength)) {
nsresult rv = MaybeCreateTemporaryFile();
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
MaybeCreateTemporaryFile();
}
// If we are already in the temporaryFile mode, we have to dispatch a
@ -570,30 +544,52 @@ MutableBlobStorage::ShouldBeTemporaryStorage(uint64_t aSize) const
return false;
}
return bufferSize.value() >= Preferences::GetUint("dom.blob.memoryToTemporaryFile",
BLOB_MEMORY_TEMPORARY_FILE);
return bufferSize.value() >= mMaxMemory;
}
nsresult
void
MutableBlobStorage::MaybeCreateTemporaryFile()
{
if (XRE_IsParentProcess()) {
RefPtr<Runnable> runnable = new CreateTemporaryFileRunnable(this);
DispatchToIOThread(runnable.forget());
mStorageState = eWaitingForTemporaryFile;
mozilla::ipc::PBackgroundChild* actor =
mozilla::ipc::BackgroundChild::GetForCurrentThread();
if (actor) {
ActorCreated(actor);
} else {
RefPtr<MutableBlobStorage> self(this);
ContentChild::GetSingleton()->
AsyncOpenAnonymousTemporaryFile([self](PRFileDesc* prfile) {
if (prfile) {
// The ownership of the prfile is moved to the FileCreatedRunnable.
self->EventTarget()->Dispatch(
new FileCreatedRunnable(self, prfile), NS_DISPATCH_NORMAL);
}
});
mozilla::ipc::BackgroundChild::GetOrCreateForCurrentThread(this);
}
}
void
MutableBlobStorage::ActorFailed()
{
MOZ_CRASH("Failed to create a PBackgroundChild actor!");
}
void
MutableBlobStorage::ActorCreated(PBackgroundChild* aActor)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mStorageState == eWaitingForTemporaryFile ||
mStorageState == eClosed);
MOZ_ASSERT_IF(mPendingCallback, mStorageState == eClosed);
// If the object has been already closed and we don't need to execute a
// callback, we have nothing else to do.
if (mStorageState == eClosed && !mPendingCallback) {
return;
}
mStorageState = eWaitingForTemporaryFile;
return NS_OK;
mActor = new TemporaryIPCBlobChild(this);
aActor->SendPTemporaryIPCBlobConstructor(mActor);
// We need manually to increase the reference for this actor because the
// IPC allocator method is not triggered. The Release() is called by IPDL
// when the actor is deleted.
mActor.get()->AddRef();
// The actor will call us when the FileDescriptor is received.
}
void
@ -603,12 +599,18 @@ MutableBlobStorage::TemporaryFileCreated(PRFileDesc* aFD)
MOZ_ASSERT(mStorageState == eWaitingForTemporaryFile ||
mStorageState == eClosed);
MOZ_ASSERT_IF(mPendingCallback, mStorageState == eClosed);
MOZ_ASSERT(mActor);
MOZ_ASSERT(aFD);
// If the object has been already closed and we don't need to execute a
// callback, we need just to close the file descriptor in the correct thread.
if (mStorageState == eClosed && !mPendingCallback) {
RefPtr<Runnable> runnable = new CloseFileRunnable(aFD);
DispatchToIOThread(runnable.forget());
// Let's inform the parent that we have nothing else to do.
mActor->SendOperationDone(false, EmptyCString());
mActor = nullptr;
return;
}
@ -638,9 +640,10 @@ MutableBlobStorage::TemporaryFileCreated(PRFileDesc* aFD)
MOZ_ASSERT(mPendingCallback);
RefPtr<Runnable> runnable =
new LastRunnable(this, mPendingParent, mPendingContentType,
new LastRunnable(this, mFD, mPendingParent, mPendingContentType,
mPendingCallback);
DispatchToIOThread(runnable.forget());
mFD = nullptr;
mPendingParent = nullptr;
mPendingCallback = nullptr;
@ -648,24 +651,17 @@ MutableBlobStorage::TemporaryFileCreated(PRFileDesc* aFD)
}
void
MutableBlobStorage::CreateBlobAndRespond(already_AddRefed<nsISupports> aParent,
const nsACString& aContentType,
already_AddRefed<MutableBlobStorageCallback> aCallback)
MutableBlobStorage::AskForBlob(TemporaryIPCBlobChildCallback* aCallback,
const nsACString& aContentType)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mStorageState == eClosed);
MOZ_ASSERT(mFD);
MOZ_ASSERT(!mFD);
MOZ_ASSERT(mActor);
MOZ_ASSERT(aCallback);
nsCOMPtr<nsISupports> parent(aParent);
RefPtr<MutableBlobStorageCallback> callback(aCallback);
RefPtr<Blob> blob =
File::CreateTemporaryBlob(parent, mFD, 0, mDataLen,
NS_ConvertUTF8toUTF16(aContentType));
callback->BlobStoreCompleted(this, blob, NS_OK);
// ownership of this FD is moved to the BlobImpl.
mFD = nullptr;
mActor->AskForBlob(aCallback, aContentType);
mActor = nullptr;
}
void
@ -673,6 +669,9 @@ MutableBlobStorage::ErrorPropagated(nsresult aRv)
{
MOZ_ASSERT(NS_IsMainThread());
mErrorResult = aRv;
mActor->SendOperationDone(false, EmptyCString());
mActor = nullptr;
}
void
@ -690,5 +689,14 @@ MutableBlobStorage::DispatchToIOThread(already_AddRefed<nsIRunnable> aRunnable)
mTaskQueue->Dispatch(runnable.forget());
}
size_t
MutableBlobStorage::SizeOfCurrentMemoryBuffer() const
{
MOZ_ASSERT(NS_IsMainThread());
return mStorageState < eInTemporaryFile ? mDataLen : 0;
}
NS_IMPL_ISUPPORTS(MutableBlobStorage, nsIIPCBackgroundChildCreateCallback)
} // dom namespace
} // mozilla namespace

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

@ -8,9 +8,11 @@
#define mozilla_dom_MutableBlobStorage_h
#include "mozilla/RefPtr.h"
#include "nsIIPCBackgroundChildCreateCallback.h"
#include "prio.h"
class nsIEventTarget;
class nsIRunnable;
namespace mozilla {
@ -21,6 +23,8 @@ namespace dom {
class Blob;
class BlobImpl;
class MutableBlobStorage;
class TemporaryIPCBlobChild;
class TemporaryIPCBlobChildCallback;
class MutableBlobStorageCallback
{
@ -33,10 +37,11 @@ public:
};
// This class is main-thread only.
class MutableBlobStorage final
class MutableBlobStorage final : public nsIIPCBackgroundChildCreateCallback
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MutableBlobStorage);
NS_DECL_NSIIPCBACKGROUNDCHILDCREATECALLBACK
NS_DECL_THREADSAFE_ISUPPORTS
enum MutableBlobStorageType
{
@ -45,7 +50,8 @@ public:
};
explicit MutableBlobStorage(MutableBlobStorageType aType,
nsIEventTarget* aEventTarget = nullptr);
nsIEventTarget* aEventTarget = nullptr,
uint32_t aMaxMemory = 0);
nsresult Append(const void* aData, uint32_t aLength);
@ -57,9 +63,8 @@ public:
void TemporaryFileCreated(PRFileDesc* aFD);
void CreateBlobAndRespond(already_AddRefed<nsISupports> aParent,
const nsACString& aContentType,
already_AddRefed<MutableBlobStorageCallback> aCallback);
void AskForBlob(TemporaryIPCBlobChildCallback* aCallback,
const nsACString& aContentType);
void ErrorPropagated(nsresult aRv);
@ -69,6 +74,10 @@ public:
return mEventTarget;
}
// Returns the heap size in bytes of our internal buffers.
// Note that this intentionally ignores the data in the temp file.
size_t SizeOfCurrentMemoryBuffer() const;
private:
~MutableBlobStorage();
@ -76,7 +85,7 @@ private:
bool ShouldBeTemporaryStorage(uint64_t aSize) const;
nsresult MaybeCreateTemporaryFile();
void MaybeCreateTemporaryFile();
void DispatchToIOThread(already_AddRefed<nsIRunnable> aRunnable);
@ -106,6 +115,14 @@ private:
nsCOMPtr<nsISupports> mPendingParent;
nsCString mPendingContentType;
RefPtr<MutableBlobStorageCallback> mPendingCallback;
RefPtr<TemporaryIPCBlobChild> mActor;
// This value is used when we go from eInMemory to eWaitingForTemporaryFile
// and eventually eInTemporaryFile. If the size of the buffer is >=
// mMaxMemory, the creation of the temporary file will start.
// It's not used if mStorageState is eKeepInMemory.
uint32_t mMaxMemory;
};
} // namespace dom

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

@ -49,17 +49,6 @@ StreamBlobImpl::StreamBlobImpl(nsIInputStream* aInputStream,
mImmutable = true;
}
StreamBlobImpl::StreamBlobImpl(StreamBlobImpl* aOther,
const nsAString& aContentType,
uint64_t aStart, uint64_t aLength)
: BaseBlobImpl(aContentType, aOther->mStart + aStart, aLength)
, mInputStream(new SlicedInputStream(aOther->mInputStream, aStart, aLength))
, mIsDirectory(false)
, mFileId(-1)
{
mImmutable = true;
}
StreamBlobImpl::StreamBlobImpl(nsIInputStream* aInputStream,
const nsAString& aName,
const nsAString& aContentType,
@ -106,22 +95,29 @@ StreamBlobImpl::CreateSlice(uint64_t aStart, uint64_t aLength,
return impl.forget();
}
nsCOMPtr<nsIInputStream> clonedStream;
nsCOMPtr<nsICloneableInputStreamWithRange> stream =
do_QueryInterface(mInputStream);
if (stream) {
nsCOMPtr<nsIInputStream> clonedStream;
aRv = stream->CloneWithRange(aStart, aLength, getter_AddRefs(clonedStream));
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
} else {
CreateInputStream(getter_AddRefs(clonedStream), aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
RefPtr<BlobImpl> impl =
new StreamBlobImpl(clonedStream, aContentType, aLength);
return impl.forget();
clonedStream =
new SlicedInputStream(clonedStream.forget(), aStart, aLength);
}
RefPtr<BlobImpl> impl;
impl = new StreamBlobImpl(this, aContentType, aStart, aLength);
MOZ_ASSERT(clonedStream);
RefPtr<BlobImpl> impl =
new StreamBlobImpl(clonedStream, aContentType, aLength);
return impl.forget();
}

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

@ -90,11 +90,6 @@ private:
int64_t aLastModifiedDate,
uint64_t aLength);
StreamBlobImpl(StreamBlobImpl* aOther,
const nsAString& aContentType,
uint64_t aStart,
uint64_t aLength);
~StreamBlobImpl();
void MaybeRegisterMemoryReporter();

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

@ -1,58 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#include "TemporaryBlobImpl.h"
namespace mozilla {
namespace dom {
NS_IMPL_ISUPPORTS_INHERITED0(TemporaryBlobImpl, BlobImpl)
TemporaryBlobImpl::TemporaryBlobImpl(PRFileDesc* aFD, uint64_t aStartPos,
uint64_t aLength,
const nsAString& aContentType)
: BaseBlobImpl(aContentType, aLength)
, mStartPos(aStartPos)
{
mFileDescOwner = new nsTemporaryFileInputStream::FileDescOwner(aFD);
}
TemporaryBlobImpl::TemporaryBlobImpl(const TemporaryBlobImpl* aOther,
uint64_t aStart, uint64_t aLength,
const nsAString& aContentType)
: BaseBlobImpl(aContentType, aLength)
, mStartPos(aStart)
, mFileDescOwner(aOther->mFileDescOwner)
{}
already_AddRefed<BlobImpl>
TemporaryBlobImpl::CreateSlice(uint64_t aStart, uint64_t aLength,
const nsAString& aContentType,
ErrorResult& aRv)
{
if (aStart + aLength > mLength) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
RefPtr<BlobImpl> impl =
new TemporaryBlobImpl(this, aStart + mStartPos,
aLength, aContentType);
return impl.forget();
}
void
TemporaryBlobImpl::CreateInputStream(nsIInputStream** aStream,
ErrorResult& aRv)
{
nsCOMPtr<nsIInputStream> stream =
new nsTemporaryFileInputStream(mFileDescOwner, mStartPos,
mStartPos + mLength);
stream.forget(aStream);
}
} // namespace dom
} // namespace mozilla

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

@ -1,45 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef mozilla_dom_TemporaryBlobImpl_h
#define mozilla_dom_TemporaryBlobImpl_h
#include "BaseBlobImpl.h"
#include "nsTemporaryFileInputStream.h"
namespace mozilla {
namespace dom {
class TemporaryBlobImpl final : public BaseBlobImpl
{
public:
NS_DECL_ISUPPORTS_INHERITED
TemporaryBlobImpl(PRFileDesc* aFD, uint64_t aStartPos,
uint64_t aLength, const nsAString& aContentType);
virtual void CreateInputStream(nsIInputStream** aStream,
ErrorResult& aRv) override;
virtual already_AddRefed<BlobImpl>
CreateSlice(uint64_t aStart, uint64_t aLength,
const nsAString& aContentType, ErrorResult& aRv) override;
private:
TemporaryBlobImpl(const TemporaryBlobImpl* aOther,
uint64_t aStart, uint64_t aLength,
const nsAString& aContentType);
~TemporaryBlobImpl() = default;
uint64_t mStartPos;
RefPtr<nsTemporaryFileInputStream::FileDescOwner> mFileDescOwner;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_TemporaryBlobImpl_h

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

@ -0,0 +1,142 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#include "TemporaryFileBlobImpl.h"
#include "IPCBlobInputStreamThread.h"
#include "nsFileStreams.h"
#include "nsIFile.h"
#include "nsIFileStreams.h"
#include "nsNetUtil.h"
#include "nsThreadUtils.h"
#include "nsXULAppAPI.h"
using namespace mozilla::ipc;
namespace mozilla {
namespace dom {
namespace {
// Here the flags needed in order to keep the temporary file opened.
// 1. REOPEN_ON_REWIND -> otherwise the stream is not serializable more than
// once.
// 2. no DEFER_OPEN -> the file must be kept open on windows in order to be
// deleted when used.
// 3. no CLOSE_ON_EOF -> the file will be closed by the DTOR. No needs. Also
// because the inputStream will not be read directly.
// 4. no SHARE_DELETE -> We don't want to allow this file to be deleted.
const uint32_t sTemporaryFileStreamFlags =
nsIFileInputStream::REOPEN_ON_REWIND;
class TemporaryFileInputStream final : public nsFileInputStream
{
public:
static nsresult
Create(nsIFile* aFile, nsIInputStream** aInputStream)
{
MOZ_ASSERT(aFile);
MOZ_ASSERT(aInputStream);
MOZ_ASSERT(XRE_IsParentProcess());
RefPtr<TemporaryFileInputStream> stream =
new TemporaryFileInputStream(aFile);
nsresult rv = stream->Init(aFile, -1, -1, sTemporaryFileStreamFlags);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
stream.forget(aInputStream);
return NS_OK;
}
void
Serialize(InputStreamParams& aParams,
FileDescriptorArray& aFileDescriptors) override
{
MOZ_CRASH("This inputStream cannot be serialized.");
}
bool
Deserialize(const InputStreamParams& aParams,
const FileDescriptorArray& aFileDescriptors) override
{
MOZ_CRASH("This inputStream cannot be deserialized.");
return false;
}
private:
explicit TemporaryFileInputStream(nsIFile* aFile)
: mFile(aFile)
{
MOZ_ASSERT(XRE_IsParentProcess());
}
~TemporaryFileInputStream()
{
// Let's delete the file on the IPCBlob Thread.
RefPtr<IPCBlobInputStreamThread> thread =
IPCBlobInputStreamThread::GetOrCreate();
if (NS_WARN_IF(!thread)) {
return;
}
nsCOMPtr<nsIFile> file = Move(mFile);
thread->Dispatch(NS_NewRunnableFunction(
"TemporaryFileInputStream::Runnable",
[file]() {
file->Remove(false);
}
));
}
nsCOMPtr<nsIFile> mFile;
};
} // anonymous
TemporaryFileBlobImpl::TemporaryFileBlobImpl(nsIFile* aFile,
const nsAString& aContentType)
: FileBlobImpl(aFile, EmptyString(), aContentType)
#ifdef DEBUG
, mInputStreamCreated(false)
#endif
{
MOZ_ASSERT(XRE_IsParentProcess());
}
TemporaryFileBlobImpl::~TemporaryFileBlobImpl()
{
MOZ_ASSERT(mInputStreamCreated);
}
already_AddRefed<BlobImpl>
TemporaryFileBlobImpl::CreateSlice(uint64_t aStart, uint64_t aLength,
const nsAString& aContentType,
ErrorResult& aRv)
{
MOZ_CRASH("This BlobImpl is not meant to be sliced!");
return nullptr;
}
void
TemporaryFileBlobImpl::CreateInputStream(nsIInputStream** aStream, ErrorResult& aRv)
{
#ifdef DEBUG
MOZ_ASSERT(!mInputStreamCreated);
// CreateInputStream can be called only once.
mInputStreamCreated = true;
#endif
aRv = TemporaryFileInputStream::Create(mFile, aStream);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
}
} // namespace dom
} // namespace mozilla

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

@ -0,0 +1,46 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef mozilla_dom_TemporaryFileBlobImpl_h
#define mozilla_dom_TemporaryFileBlobImpl_h
#include "FileBlobImpl.h"
namespace mozilla {
namespace dom {
// This class is meant to be used by TemporaryIPCBlobParent only.
// Don't use it for anything else, please!
// Note that CreateInputStream() _must_ be called, and called just once!
// This class is a BlobImpl because it needs to be sent via IPC using
// IPCBlobUtils.
class TemporaryFileBlobImpl final : public FileBlobImpl
{
#ifdef DEBUG
bool mInputStreamCreated;
#endif
public:
explicit TemporaryFileBlobImpl(nsIFile* aFile, const nsAString& aContentType);
// Overrides
virtual void CreateInputStream(nsIInputStream** aInputStream,
ErrorResult& aRv) override;
protected:
virtual ~TemporaryFileBlobImpl();
private:
virtual already_AddRefed<BlobImpl>
CreateSlice(uint64_t aStart, uint64_t aLength,
const nsAString& aContentType, ErrorResult& aRv) override;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_TemporaryFileBlobImpl_h

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

@ -381,30 +381,33 @@ IPCBlobInputStream::AsyncWait(nsIInputStreamCallback* aCallback,
}
void
IPCBlobInputStream::StreamReady(nsIInputStream* aInputStream)
IPCBlobInputStream::StreamReady(already_AddRefed<nsIInputStream> aInputStream)
{
nsCOMPtr<nsIInputStream> inputStream = Move(aInputStream);
// We have been closed in the meantime.
if (mState == eClosed) {
if (aInputStream) {
aInputStream->Close();
if (inputStream) {
inputStream->Close();
}
return;
}
// If aInputStream is null, it means that the serialization went wrong or the
// If inputStream is null, it means that the serialization went wrong or the
// stream is not available anymore. We keep the state as pending just to block
// any additional operation.
if (!aInputStream) {
if (!inputStream) {
return;
}
// Now it's the right time to apply a slice if needed.
if (mStart > 0 || mLength < mActor->Size()) {
aInputStream = new SlicedInputStream(aInputStream, mStart, mLength);
inputStream =
new SlicedInputStream(inputStream.forget(), mStart, mLength);
}
mRemoteStream = aInputStream;
mRemoteStream = inputStream;
MOZ_ASSERT(mState == ePending);
mState = eRunning;
@ -475,7 +478,8 @@ IPCBlobInputStream::InitWithExistingRange(uint64_t aStart, uint64_t aLength)
// because the stream is immediately consumable.
if (mState == eRunning && mRemoteStream && XRE_IsParentProcess() &&
(mStart > 0 || mLength < mActor->Size())) {
mRemoteStream = new SlicedInputStream(mRemoteStream, mStart, mLength);
mRemoteStream =
new SlicedInputStream(mRemoteStream.forget(), mStart, mLength);
}
}

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

@ -38,7 +38,7 @@ public:
explicit IPCBlobInputStream(IPCBlobInputStreamChild* aActor);
void
StreamReady(nsIInputStream* aInputStream);
StreamReady(already_AddRefed<nsIInputStream> aInputStream);
private:
~IPCBlobInputStream();

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

@ -71,10 +71,10 @@ class StreamReadyRunnable final : public CancelableRunnable
{
public:
StreamReadyRunnable(IPCBlobInputStream* aDestinationStream,
nsIInputStream* aCreatedStream)
already_AddRefed<nsIInputStream> aCreatedStream)
: CancelableRunnable("dom::StreamReadyRunnable")
, mDestinationStream(aDestinationStream)
, mCreatedStream(aCreatedStream)
, mCreatedStream(Move(aCreatedStream))
{
MOZ_ASSERT(mDestinationStream);
// mCreatedStream can be null.
@ -83,7 +83,7 @@ public:
NS_IMETHOD
Run() override
{
mDestinationStream->StreamReady(mCreatedStream);
mDestinationStream->StreamReady(mCreatedStream.forget());
return NS_OK;
}
@ -317,7 +317,7 @@ IPCBlobInputStreamChild::RecvStreamReady(const OptionalIPCStream& aStream)
}
RefPtr<StreamReadyRunnable> runnable =
new StreamReadyRunnable(pendingStream, stream);
new StreamReadyRunnable(pendingStream, stream.forget());
// If IPCBlobInputStream::AsyncWait() has been executed without passing an
// event target, we run the callback synchronous because any thread could be

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

@ -172,7 +172,8 @@ IPCBlobInputStreamStorage::GetStream(const nsID& aID,
// Now it's the right time to apply a slice if needed.
if (aStart > 0 || aLength < size) {
clonedStream = new SlicedInputStream(clonedStream, aStart, aLength);
clonedStream =
new SlicedInputStream(clonedStream.forget(), aStart, aLength);
}
clonedStream.forget(aInputStream);

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

@ -9,6 +9,7 @@
#include "nsIObserverService.h"
#include "nsIEventTarget.h"
#include "nsIObserver.h"
class nsIThread;

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

@ -33,7 +33,6 @@
* - a memory buffer: MemoryBlobImpl
* - a string: StringBlobImpl
* - a real OS file: FileBlobImpl
* - a temporary OS file: TemporaryBlobImpl
* - a generic nsIInputStream: StreamBlobImpl
* - an empty blob: EmptyBlobImpl
* - more blobs combined together: MultipartBlobImpl

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

@ -0,0 +1,41 @@
/* 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/. */
include protocol PBackground;
include protocol PChildToParentStream;
include protocol PFileDescriptorSet;
include protocol PIPCBlobInputStream;
include protocol PParentToChildStream;
include IPCBlob;
namespace mozilla {
namespace ipc {
union IPCBlobOrError
{
IPCBlob;
nsresult;
};
protocol PTemporaryIPCBlob
{
manager PBackground;
// When this actor is created on the child side, the parent will send
// immediatelly back a FileDescriptor or a __delete__ in case of error.
// When the FileDescriptor is received, the child has to call
// OperationDone(). When OperationDone() is received on the parent side, the
// parent actor will send a __delete__.
child:
async FileDesc(FileDescriptor aFD);
async __delete__(IPCBlobOrError aBlobOrError);
parent:
async OperationDone(bool aSuccess, nsCString aContentType);
};
} // namespace dom
} // namespace mozilla

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

@ -0,0 +1,90 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#include "TemporaryIPCBlobChild.h"
#include "mozilla/dom/MutableBlobStorage.h"
#include <private/pprio.h>
namespace mozilla {
namespace dom {
TemporaryIPCBlobChild::TemporaryIPCBlobChild(MutableBlobStorage* aStorage)
: mMutableBlobStorage(aStorage)
, mActive(true)
{
MOZ_ASSERT(aStorage);
}
TemporaryIPCBlobChild::~TemporaryIPCBlobChild()
{}
mozilla::ipc::IPCResult
TemporaryIPCBlobChild::RecvFileDesc(const FileDescriptor& aFD)
{
MOZ_ASSERT(mActive);
auto rawFD = aFD.ClonePlatformHandle();
PRFileDesc* prfile = PR_ImportFile(PROsfd(rawFD.release()));
mMutableBlobStorage->TemporaryFileCreated(prfile);
mMutableBlobStorage = nullptr;
return IPC_OK();
}
mozilla::ipc::IPCResult
TemporaryIPCBlobChild::Recv__delete__(const IPCBlobOrError& aData)
{
mActive = false;
mMutableBlobStorage = nullptr;
if (aData.type() == IPCBlobOrError::TIPCBlob) {
// This must be always deserialized.
RefPtr<BlobImpl> blobImpl = IPCBlobUtils::Deserialize(aData.get_IPCBlob());
MOZ_ASSERT(blobImpl);
if (mCallback) {
mCallback->OperationSucceeded(blobImpl);
}
} else if(mCallback) {
MOZ_ASSERT(aData.type() == IPCBlobOrError::Tnsresult);
mCallback->OperationFailed(aData.get_nsresult());
}
mCallback = nullptr;
return IPC_OK();
}
void
TemporaryIPCBlobChild::ActorDestroy(ActorDestroyReason aWhy)
{
mActive = false;
mMutableBlobStorage = nullptr;
if (mCallback) {
mCallback->OperationFailed(NS_ERROR_FAILURE);
mCallback = nullptr;
}
}
void
TemporaryIPCBlobChild::AskForBlob(TemporaryIPCBlobChildCallback* aCallback,
const nsACString& aContentType)
{
MOZ_ASSERT(aCallback);
MOZ_ASSERT(!mCallback);
if (!mActive) {
aCallback->OperationFailed(NS_ERROR_FAILURE);
return;
}
mCallback = aCallback;
SendOperationDone(true, nsCString(aContentType));
}
} // dom namespace
} // mozilla namespace

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

@ -0,0 +1,58 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef mozilla_dom_ipc_TemporaryIPCBlobChild_h
#define mozilla_dom_ipc_TemporaryIPCBlobChild_h
#include "mozilla/ipc/PTemporaryIPCBlob.h"
#include "mozilla/ipc/PTemporaryIPCBlobChild.h"
namespace mozilla {
namespace dom {
class MutableBlobStorage;
class TemporaryIPCBlobChildCallback
{
public:
NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
virtual void OperationSucceeded(BlobImpl* aBlobImpl) = 0;
virtual void OperationFailed(nsresult aRv) = 0;
};
class TemporaryIPCBlobChild final : public mozilla::ipc::PTemporaryIPCBlobChild
{
public:
NS_INLINE_DECL_REFCOUNTING(TemporaryIPCBlobChild)
explicit TemporaryIPCBlobChild(MutableBlobStorage* aMutableBlobStorage);
void
AskForBlob(TemporaryIPCBlobChildCallback* aCallback,
const nsACString& aContentType);
private:
~TemporaryIPCBlobChild();
mozilla::ipc::IPCResult
RecvFileDesc(const FileDescriptor& aFD) override;
mozilla::ipc::IPCResult
Recv__delete__(const IPCBlobOrError& aBlobOrError) override;
void
ActorDestroy(ActorDestroyReason aWhy) override;
RefPtr<MutableBlobStorage> mMutableBlobStorage;
RefPtr<TemporaryIPCBlobChildCallback> mCallback;
bool mActive;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_ipc_TemporaryIPCBlobChild_h

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

@ -0,0 +1,105 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#include "TemporaryIPCBlobParent.h"
#include "mozilla/dom/FileBlobImpl.h"
#include "nsAnonymousTemporaryFile.h"
#include "nsIFileStreams.h"
#include "TemporaryFileBlobImpl.h"
namespace mozilla {
namespace dom {
TemporaryIPCBlobParent::TemporaryIPCBlobParent()
: mActive(true)
{}
TemporaryIPCBlobParent::~TemporaryIPCBlobParent()
{
// If we still have mFile, let's remove it.
if (mFile) {
mFile->Remove(false);
}
}
mozilla::ipc::IPCResult
TemporaryIPCBlobParent::CreateAndShareFile()
{
MOZ_ASSERT(mActive);
MOZ_ASSERT(!mFile);
nsresult rv = NS_OpenAnonymousTemporaryNsIFile(getter_AddRefs(mFile));
if (NS_WARN_IF(NS_FAILED(rv))) {
return SendDeleteError(rv);
}
PRFileDesc* fd;
rv = mFile->OpenNSPRFileDesc(PR_RDWR, PR_IRWXU, &fd);
if (NS_WARN_IF(NS_FAILED(rv))) {
return SendDeleteError(rv);
}
FileDescriptor fdd =
FileDescriptor(FileDescriptor::PlatformHandleType(PR_FileDesc2NativeHandle(fd)));
// The FileDescriptor object owns a duplicate of the file handle; we
// must close the original (and clean up the NSPR descriptor).
PR_Close(fd);
Unused << SendFileDesc(fdd);
return IPC_OK();
}
mozilla::ipc::IPCResult
TemporaryIPCBlobParent::RecvOperationDone(const bool& aSuccess,
const nsCString& aContentType)
{
MOZ_ASSERT(mActive);
mActive = false;
if (!aSuccess) {
// Nothing to do.
Unused << Send__delete__(this, NS_ERROR_FAILURE);
return IPC_OK();
}
// Let's create the BlobImpl.
nsCOMPtr<nsIFile> file = Move(mFile);
RefPtr<TemporaryFileBlobImpl> blobImpl =
new TemporaryFileBlobImpl(file, NS_ConvertUTF8toUTF16(aContentType));
IPCBlob ipcBlob;
nsresult rv = IPCBlobUtils::Serialize(blobImpl, Manager(), ipcBlob);
if (NS_WARN_IF(NS_FAILED(rv))) {
Unused << Send__delete__(this, NS_ERROR_FAILURE);
return IPC_OK();
}
Unused << Send__delete__(this, ipcBlob);
return IPC_OK();
}
void
TemporaryIPCBlobParent::ActorDestroy(ActorDestroyReason aWhy)
{
mActive = false;
}
mozilla::ipc::IPCResult
TemporaryIPCBlobParent::SendDeleteError(nsresult aRv)
{
MOZ_ASSERT(mActive);
mActive = false;
Unused << Send__delete__(this, aRv);
return IPC_OK();
}
} // dom namespace
} // mozilla namespace

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

@ -0,0 +1,46 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef mozilla_dom_ipc_TemporaryIPCBlobParent_h
#define mozilla_dom_ipc_TemporaryIPCBlobParent_h
#include "mozilla/ipc/PTemporaryIPCBlob.h"
#include "mozilla/ipc/PTemporaryIPCBlobParent.h"
class nsIFile;
namespace mozilla {
namespace dom {
class TemporaryIPCBlobParent final : public mozilla::ipc::PTemporaryIPCBlobParent
{
public:
explicit TemporaryIPCBlobParent();
mozilla::ipc::IPCResult
CreateAndShareFile();
private:
~TemporaryIPCBlobParent();
mozilla::ipc::IPCResult
RecvOperationDone(const bool& aSuccess,
const nsCString& aContentType) override;
void
ActorDestroy(ActorDestroyReason aWhy) override;
mozilla::ipc::IPCResult
SendDeleteError(nsresult aRv);
nsCOMPtr<nsIFile> mFile;
bool mActive;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_ipc_TemporaryIPCBlobParent_h

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

@ -11,6 +11,8 @@ EXPORTS.mozilla.dom.ipc += [
'IPCBlobInputStreamStorage.h',
'PendingIPCBlobChild.h',
'PendingIPCBlobParent.h',
'TemporaryIPCBlobChild.h',
'TemporaryIPCBlobParent.h',
]
EXPORTS.mozilla.dom += [
@ -26,6 +28,8 @@ UNIFIED_SOURCES += [
'IPCBlobUtils.cpp',
'PendingIPCBlobChild.cpp',
'PendingIPCBlobParent.cpp',
'TemporaryIPCBlobChild.cpp',
'TemporaryIPCBlobParent.cpp',
]
IPDL_SOURCES += [
@ -33,6 +37,7 @@ IPDL_SOURCES += [
'IPCBlob.ipdlh',
'PIPCBlobInputStream.ipdl',
'PPendingIPCBlob.ipdl',
'PTemporaryIPCBlob.ipdl',
]
LOCAL_INCLUDES += [

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

@ -3,3 +3,5 @@ support-files =
empty.html
[browser_ipcBlob.js]
[browser_ipcBlob_temporary.js]
support-files = temporary.sjs

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

@ -0,0 +1,114 @@
/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; js-indent-level: 2 -*- */
requestLongerTimeout(3);
const BASE_URI = "http://mochi.test:8888/browser/dom/file/ipc/tests/empty.html";
add_task(async function test() {
await SpecialPowers.pushPrefEnv({ "set" : [
["dom.blob.memoryToTemporaryFile", 1 ],
["dom.ipc.processCount", 4],
]});
let tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, BASE_URI);
let browser1 = gBrowser.getBrowserForTab(tab1);
let tab2 = await BrowserTestUtils.openNewForegroundTab(gBrowser, BASE_URI);
let browser2 = gBrowser.getBrowserForTab(tab2);
await ContentTask.spawn(browser2, null, function() {
content.window.testPromise = new content.window.Promise(resolve => {
let bc = new content.window.BroadcastChannel('foobar');
bc.onmessage = e => {
function realTest() {
return new content.window.Promise(resolve => {
let count = 10;
for (let i = 0; i < count; ++i) {
info("FileReader at the same time: " + i);
let fr = new content.window.FileReader();
fr.readAsText(e.data);
fr.onerror = () => {
ok(false, "Something wrong happened.");
}
fr.onloadend = () => {
is (fr.result.length, e.data.size, "FileReader worked fine.");
if (!--count) {
resolve(true);
}
}
}
});
}
let promises = [];
for (let i = 0; i < 5; ++i) {
promises.push(realTest());
}
Promise.all(promises).then(() => {
resolve(true);
});
};
});
});
let status = await ContentTask.spawn(browser1, null, function() {
let p = new content.window.Promise(resolve => {
let xhr = new content.window.XMLHttpRequest();
xhr.open('GET', 'temporary.sjs', true);
xhr.responseType = 'blob';
xhr.onload = () => {
resolve(xhr.response);
}
xhr.send();
});
return p.then(blob => {
function realTest() {
return new content.window.Promise(resolve => {
info("Let's broadcast the blob...");
let bc = new content.window.BroadcastChannel('foobar');
bc.postMessage(blob);
info("Here the test...");
let count = 10;
for (let i = 0; i < count; ++i) {
info("FileReader at the same time: " + i);
let fr = new content.window.FileReader();
fr.readAsText(blob);
fr.onerror = () => {
ok(false, "Something wrong happened.");
}
fr.onloadend = () => {
is (fr.result.length, blob.size, "FileReader worked fine.");
if (!--count) {
resolve(true);
}
}
}
});
}
let promises = [];
for (let i = 0; i < 5; ++i) {
promises.push(realTest());
}
return Promise.all(promises);
});
});
ok(status, "All good for tab1!");
status = await ContentTask.spawn(browser2, null, function() {
return content.window.testPromise;
});
ok(status, "All good for tab2!");
await BrowserTestUtils.removeTab(tab1);
await BrowserTestUtils.removeTab(tab2);
});

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

@ -0,0 +1,7 @@
function handleRequest(request, response)
{
response.setHeader("Content-Type", "text/plain", false);
var data = new Array(1024*64).join("1234567890ABCDEF");
response.bodyOutputStream.write(data, data.length);
}

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

@ -57,10 +57,11 @@ UNIFIED_SOURCES += [
'nsHostObjectURI.cpp',
'StreamBlobImpl.cpp',
'StringBlobImpl.cpp',
'TemporaryBlobImpl.cpp',
'TemporaryFileBlobImpl.cpp',
]
LOCAL_INCLUDES += [
'/dom/file/ipc',
'/dom/workers',
]

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

@ -403,9 +403,7 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED(HTMLCanvasElement, nsGenericHTMLElement,
mPrintState, mOriginalCanvas,
mOffscreenCanvas)
NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(HTMLCanvasElement,
nsGenericHTMLElement,
nsIDOMHTMLCanvasElement)
NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(HTMLCanvasElement, nsGenericHTMLElement)
NS_IMPL_ELEMENT_CLONE(HTMLCanvasElement)
@ -459,10 +457,6 @@ HTMLCanvasElement::GetWidthHeight()
return size;
}
NS_IMPL_UINT_ATTR_DEFAULT_VALUE(HTMLCanvasElement, Width, width, DEFAULT_CANVAS_WIDTH)
NS_IMPL_UINT_ATTR_DEFAULT_VALUE(HTMLCanvasElement, Height, height, DEFAULT_CANVAS_HEIGHT)
NS_IMPL_BOOL_ATTR(HTMLCanvasElement, MozOpaque, moz_opaque)
nsresult
HTMLCanvasElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
const nsAttrValue* aValue,

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

@ -9,7 +9,6 @@
#include "mozilla/Attributes.h"
#include "mozilla/WeakPtr.h"
#include "nsIDOMEventListener.h"
#include "nsIDOMHTMLCanvasElement.h"
#include "nsIObserver.h"
#include "nsGenericHTMLElement.h"
#include "nsGkAtoms.h"
@ -116,7 +115,6 @@ protected:
};
class HTMLCanvasElement final : public nsGenericHTMLElement,
public nsIDOMHTMLCanvasElement,
public CanvasRenderingContextHelper
{
enum {
@ -138,9 +136,6 @@ public:
// nsISupports
NS_DECL_ISUPPORTS_INHERITED
// nsIDOMHTMLCanvasElement
NS_DECL_NSIDOMHTMLCANVASELEMENT
// CC
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLCanvasElement,
nsGenericHTMLElement)

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

@ -34,7 +34,6 @@ interface nsICycleCollectorListener;
interface nsIDOMNode;
interface nsIDOMNodeList;
interface nsIDOMElement;
interface nsIDOMHTMLCanvasElement;
interface nsIDOMEvent;
interface nsIPreloadedStyleSheet;
interface nsITransferable;
@ -928,8 +927,8 @@ interface nsIDOMWindowUtils : nsISupports {
*
* This method requires chrome privileges.
*/
uint32_t compareCanvases(in nsIDOMHTMLCanvasElement aCanvas1,
in nsIDOMHTMLCanvasElement aCanvas2,
uint32_t compareCanvases(in nsISupports aCanvas1,
in nsISupports aCanvas2,
out unsigned long aMaxDifference);
/**

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

@ -9,7 +9,6 @@ with Files("**"):
XPIDL_SOURCES += [
'nsIDOMHTMLBaseElement.idl',
'nsIDOMHTMLCanvasElement.idl',
'nsIDOMHTMLCollection.idl',
'nsIDOMHTMLDocument.idl',
'nsIDOMHTMLElement.idl',

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

@ -1,29 +0,0 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsIDOMHTMLElement.idl"
/**
* The nsIDOMHTMLCanvasElement interface is the interface to a HTML
* <canvas> element.
*
* For more information on this interface, please see
* http://www.whatwg.org/specs/web-apps/current-work/#graphics
*
* @status UNDER_DEVELOPMENT
*/
interface nsIDOMBlob;
interface nsIVariant;
interface nsIInputStreamCallback;
[uuid(4e8f1316-b601-471d-8f44-3c650d91ee9b)]
interface nsIDOMHTMLCanvasElement : nsISupports
{
attribute unsigned long width;
attribute unsigned long height;
attribute boolean mozOpaque;
};

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

@ -587,13 +587,6 @@ ContentChild::RecvSetXPCOMProcessAttributes(const XPCOMInitData& aXPCOMInit,
InitXPCOM(aXPCOMInit, aInitialData);
InitGraphicsDeviceData(aXPCOMInit.contentDeviceData());
#ifdef NS_PRINTING
// Force the creation of the nsPrintingProxy so that it's IPC counterpart,
// PrintingParent, is always available for printing initiated from the parent.
// Create nsPrintingProxy instance later than the SystemGroup initialization.
RefPtr<nsPrintingProxy> printingProxy = nsPrintingProxy::GetInstance();
#endif
return IPC_OK();
}
@ -681,6 +674,12 @@ ContentChild::Init(MessageLoop* aIOLoop,
mID = aChildID;
mIsForBrowser = aIsForBrowser;
#ifdef NS_PRINTING
// Force the creation of the nsPrintingProxy so that it's IPC counterpart,
// PrintingParent, is always available for printing initiated from the parent.
RefPtr<nsPrintingProxy> printingProxy = nsPrintingProxy::GetInstance();
#endif
SetProcessName(NS_LITERAL_STRING("Web Content"));
#ifdef NIGHTLY_BUILD
@ -3036,11 +3035,16 @@ ContentChild::RecvShutdown()
#if defined(MOZ_CRASHREPORTER)
CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("IPCShutdownState"),
NS_LITERAL_CSTRING("SendFinishShutdown"));
#endif
NS_LITERAL_CSTRING("SendFinishShutdown (sending)"));
bool sent = SendFinishShutdown();
CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("IPCShutdownState"),
sent ? NS_LITERAL_CSTRING("SendFinishShutdown (sent)")
: NS_LITERAL_CSTRING("SendFinishShutdown (failed)"));
#else
// Ignore errors here. If this fails, the parent will kill us after a
// timeout.
Unused << SendFinishShutdown();
#endif
return IPC_OK();
}

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

@ -973,9 +973,11 @@ TabParent::RecvPDocAccessibleConstructor(PDocAccessibleParent* aDoc,
#ifdef XP_WIN
a11y::WrapperFor(doc)->SetID(aMsaaID);
MOZ_ASSERT(!aDocCOMProxy.IsNull());
#ifdef NIGHTLY_BUILD
if (aDocCOMProxy.IsNull()) {
return IPC_FAIL(this, "Constructing a top-level PDocAccessible with null COM proxy");
}
#endif
RefPtr<IAccessible> proxy(aDocCOMProxy.Get());
doc->SetCOMInterface(proxy);

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

@ -44,6 +44,7 @@
#include "nsIWritablePropertyBag2.h"
#include "nsIContentSecurityPolicy.h"
#include "nsSandboxFlags.h"
#include "mozilla/CycleCollectedJSContext.h"
#include "mozilla/dom/ScriptSettings.h"
#include "nsILoadInfo.h"
#include "nsContentSecurityManager.h"
@ -234,7 +235,7 @@ nsresult nsJSThunk::EvaluateScript(nsIChannel *aChannel,
// New script entry point required, due to the "Create a script" step of
// http://www.whatwg.org/specs/web-apps/current-work/#javascript-protocol
nsAutoMicroTask mt;
mozilla::nsAutoMicroTask mt;
AutoEntryScript aes(innerGlobal, "javascript: URI", true);
JSContext* cx = aes.cx();
JS::Rooted<JSObject*> globalJSObject(cx, innerGlobal->GetGlobalJSObject());

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

@ -1,140 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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/. */
#include "EncodedBufferCache.h"
#include "prio.h"
#include "nsAnonymousTemporaryFile.h"
#include "mozilla/Monitor.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/File.h"
#include "nsThreadUtils.h"
#include "nsXULAppAPI.h"
namespace mozilla {
void
EncodedBufferCache::AppendBuffer(nsTArray<uint8_t> & aBuf)
{
MOZ_ASSERT(!NS_IsMainThread());
MutexAutoLock lock(mMutex);
mDataSize += aBuf.Length();
mEncodedBuffers.AppendElement()->SwapElements(aBuf);
if (!mTempFileEnabled && mDataSize > mMaxMemoryStorage) {
nsresult rv;
PRFileDesc* tempFD = nullptr;
{
// Release the mMutex because of the sync dispatch to the main thread.
MutexAutoUnlock unlock(mMutex);
if (XRE_IsParentProcess()) {
// In case we are in the parent process, do a synchronous I/O here to open a
// temporary file.
rv = NS_OpenAnonymousTemporaryFile(&tempFD);
} else {
// In case we are in the child process, we don't have access to open a file
// directly due to sandbox restrictions, so we need to ask the parent process
// to do that for us. In order to initiate the IPC, we need to first go to
// the main thread. This is done by dispatching a runnable to the main thread.
// From there, we start an asynchronous IPC, and we block the current thread
// using a monitor while this async work is in progress. When we receive the
// resulting file descriptor from the parent process, we notify the monitor
// and unblock the current thread and continue.
typedef dom::ContentChild::AnonymousTemporaryFileCallback
AnonymousTemporaryFileCallback;
bool done = false;
Monitor monitor("EncodeBufferCache::AppendBuffer");
RefPtr<dom::ContentChild> cc = dom::ContentChild::GetSingleton();
nsCOMPtr<nsIRunnable> runnable =
NewRunnableMethod<AnonymousTemporaryFileCallback>(
"dom::ContentChild::AsyncOpenAnonymousTemporaryFile",
cc,
&dom::ContentChild::AsyncOpenAnonymousTemporaryFile,
[&](PRFileDesc* aFile) {
rv = aFile ? NS_OK : NS_ERROR_FAILURE;
tempFD = aFile;
MonitorAutoLock lock(monitor);
done = true;
lock.Notify();
});
MonitorAutoLock lock(monitor);
rv = NS_DispatchToMainThread(runnable);
if (NS_SUCCEEDED(rv)) {
while (!done) {
lock.Wait();
}
}
}
}
if (!NS_FAILED(rv)) {
// Check the mDataSize again since we release the mMutex before.
if (mDataSize > mMaxMemoryStorage) {
mFD = tempFD;
mTempFileEnabled = true;
} else {
// Close the tempFD because the data had been taken during the
// MutexAutoUnlock.
PR_Close(tempFD);
}
}
}
if (mTempFileEnabled) {
// has created temporary file, write buffer in it
for (uint32_t i = 0; i < mEncodedBuffers.Length(); i++) {
int32_t amount = PR_Write(mFD, mEncodedBuffers.ElementAt(i).Elements(), mEncodedBuffers.ElementAt(i).Length());
if (amount < 0 || size_t(amount) < mEncodedBuffers.ElementAt(i).Length()) {
NS_WARNING("Failed to write media cache block!");
}
}
mEncodedBuffers.Clear();
}
}
already_AddRefed<dom::Blob>
EncodedBufferCache::ExtractBlob(nsISupports* aParent,
const nsAString &aContentType)
{
MutexAutoLock lock(mMutex);
RefPtr<dom::Blob> blob;
if (mTempFileEnabled) {
// generate new temporary file to write
blob = dom::Blob::CreateTemporaryBlob(aParent, mFD, 0, mDataSize,
aContentType);
// fallback to memory blob
mTempFileEnabled = false;
mDataSize = 0;
mFD = nullptr;
} else {
void* blobData = malloc(mDataSize);
NS_ASSERTION(blobData, "out of memory!!");
if (blobData) {
for (uint32_t i = 0, offset = 0; i < mEncodedBuffers.Length(); i++) {
memcpy((uint8_t*)blobData + offset, mEncodedBuffers.ElementAt(i).Elements(),
mEncodedBuffers.ElementAt(i).Length());
offset += mEncodedBuffers.ElementAt(i).Length();
}
blob = dom::Blob::CreateMemoryBlob(aParent, blobData, mDataSize,
aContentType);
mEncodedBuffers.Clear();
} else
return nullptr;
}
mDataSize = 0;
return blob.forget();
}
size_t
EncodedBufferCache::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf)
{
MutexAutoLock lock(mMutex);
return mEncodedBuffers.ShallowSizeOfExcludingThis(aMallocSizeOf);
}
} // namespace mozilla

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

@ -1,66 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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/. */
#ifndef EncodedBufferCache_h_
#define EncodedBufferCache_h_
#include "nsCOMPtr.h"
#include "nsTArray.h"
#include "mozilla/Mutex.h"
struct PRFileDesc;
namespace mozilla {
namespace dom {
class Blob;
} // namespace dom
/**
* Data is moved into a temporary file when it grows beyond
* the maximal size passed in the Init function.
* The AppendBuffer and ExtractBlob methods are thread-safe and can be called on
* different threads at the same time.
*/
class EncodedBufferCache
{
public:
explicit EncodedBufferCache(uint32_t aMaxMemoryStorage)
: mFD(nullptr),
mMutex("EncodedBufferCache.Data.Mutex"),
mDataSize(0),
mMaxMemoryStorage(aMaxMemoryStorage),
mTempFileEnabled(false) { }
~EncodedBufferCache()
{
}
// Append buffers in cache, check if the queue is too large then switch to write buffer to file system
// aBuf will append to mEncodedBuffers or temporary File, aBuf also be cleared
void AppendBuffer(nsTArray<uint8_t> & aBuf);
// Read all buffer from memory or file System, also Remove the temporary file or clean the buffers in memory.
already_AddRefed<dom::Blob> ExtractBlob(nsISupports* aParent, const nsAString &aContentType);
// Returns the heap size in bytes of our internal buffers.
// Note that this intentionally ignores the data in the temp file.
size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf);
private:
//array for storing the encoded data.
nsTArray<nsTArray<uint8_t> > mEncodedBuffers;
// File handle for the temporary file
PRFileDesc* mFD;
// Used to protect the mEncodedBuffer for avoiding AppendBuffer/Consume on different thread at the same time.
Mutex mMutex;
// the current buffer size can be read
uint64_t mDataSize;
// The maximal buffer allowed in memory
uint32_t mMaxMemoryStorage;
// indicate the buffer is stored on temporary file or not
bool mTempFileEnabled;
};
} // namespace mozilla
#endif

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

@ -9,7 +9,6 @@
#include "AudioNodeEngine.h"
#include "AudioNodeStream.h"
#include "DOMMediaStream.h"
#include "EncodedBufferCache.h"
#include "GeckoProfiler.h"
#include "MediaDecoder.h"
#include "MediaEncoder.h"
@ -19,6 +18,7 @@
#include "mozilla/dom/BlobEvent.h"
#include "mozilla/dom/File.h"
#include "mozilla/dom/MediaRecorderErrorEvent.h"
#include "mozilla/dom/MutableBlobStorage.h"
#include "mozilla/dom/VideoStreamTrack.h"
#include "mozilla/media/MediaUtils.h"
#include "mozilla/MemoryReporting.h"
@ -201,11 +201,17 @@ class MediaRecorder::Session: public PrincipalChangeObserver<MediaStreamTrack>,
// Main thread task.
// Create a blob event and send back to client.
class PushBlobRunnable : public Runnable
, public MutableBlobStorageCallback
{
public:
explicit PushBlobRunnable(Session* aSession)
NS_DECL_ISUPPORTS_INHERITED
// aDestroyRunnable can be null. If it's not, it will be dispatched after
// the PushBlobRunnable::Run().
PushBlobRunnable(Session* aSession, Runnable* aDestroyRunnable)
: Runnable("dom::MediaRecorder::Session::PushBlobRunnable")
, mSession(aSession)
, mDestroyRunnable(aDestroyRunnable)
{ }
NS_IMETHOD Run() override
@ -213,21 +219,72 @@ class MediaRecorder::Session: public PrincipalChangeObserver<MediaStreamTrack>,
LOG(LogLevel::Debug, ("Session.PushBlobRunnable s=(%p)", mSession.get()));
MOZ_ASSERT(NS_IsMainThread());
mSession->GetBlobWhenReady(this);
return NS_OK;
}
void
BlobStoreCompleted(MutableBlobStorage* aBlobStorage, Blob* aBlob,
nsresult aRv) override
{
RefPtr<MediaRecorder> recorder = mSession->mRecorder;
if (!recorder) {
return NS_OK;
return;
}
nsresult rv = recorder->CreateAndDispatchBlobEvent(mSession->GetEncodedData());
if (NS_FAILED(aRv)) {
recorder->NotifyError(aRv);
return;
}
nsresult rv = recorder->CreateAndDispatchBlobEvent(aBlob);
if (NS_FAILED(rv)) {
recorder->NotifyError(rv);
recorder->NotifyError(aRv);
}
if (mDestroyRunnable &&
NS_FAILED(NS_DispatchToMainThread(mDestroyRunnable.forget()))) {
MOZ_ASSERT(false, "NS_DispatchToMainThread failed");
}
}
private:
~PushBlobRunnable() = default;
RefPtr<Session> mSession;
// The generation of the blob is async. In order to avoid dispatching the
// DestroyRunnable before pushing the blob event, we store the runnable
// here.
RefPtr<Runnable> mDestroyRunnable;
};
class StoreEncodedBufferRunnable final : public Runnable
{
RefPtr<Session> mSession;
nsTArray<nsTArray<uint8_t>> mBuffer;
public:
StoreEncodedBufferRunnable(Session* aSession,
nsTArray<nsTArray<uint8_t>>&& aBuffer)
: Runnable("StoreEncodedBufferRunnable")
, mSession(aSession)
, mBuffer(Move(aBuffer))
{}
NS_IMETHOD
Run() override
{
mSession->MaybeCreateMutableBlobStorage();
for (uint32_t i = 0; i < mBuffer.Length(); i++) {
if (!mBuffer[i].IsEmpty()) {
mSession->mMutableBlobStorage->Append(mBuffer[i].Elements(),
mBuffer[i].Length());
}
}
return NS_OK;
}
private:
RefPtr<Session> mSession;
};
// Notify encoder error, run in main thread task. (Bug 1095381)
@ -433,9 +490,8 @@ public:
{
MOZ_ASSERT(NS_IsMainThread());
uint32_t maxMem = Preferences::GetUint("media.recorder.max_memory",
MAX_ALLOW_MEMORY_BUFFER);
mEncodedBufferCache = new EncodedBufferCache(maxMem);
mMaxMemory = Preferences::GetUint("media.recorder.max_memory",
MAX_ALLOW_MEMORY_BUFFER);
mLastBlobTimeStamp = TimeStamp::Now();
}
@ -551,7 +607,7 @@ public:
LOG(LogLevel::Debug, ("Session.RequestData"));
MOZ_ASSERT(NS_IsMainThread());
if (NS_FAILED(NS_DispatchToMainThread(new PushBlobRunnable(this)))) {
if (NS_FAILED(NS_DispatchToMainThread(new PushBlobRunnable(this, nullptr)))) {
MOZ_ASSERT(false, "RequestData NS_DispatchToMainThread failed");
return NS_ERROR_FAILURE;
}
@ -559,19 +615,35 @@ public:
return NS_OK;
}
already_AddRefed<nsIDOMBlob> GetEncodedData()
void
MaybeCreateMutableBlobStorage()
{
if (!mMutableBlobStorage) {
mMutableBlobStorage =
new MutableBlobStorage(MutableBlobStorage::eCouldBeInTemporaryFile,
nullptr, mMaxMemory);
}
}
void
GetBlobWhenReady(MutableBlobStorageCallback* aCallback)
{
MOZ_ASSERT(NS_IsMainThread());
return mEncodedBufferCache->ExtractBlob(mRecorder->GetParentObject(),
mMimeType);
MaybeCreateMutableBlobStorage();
mMutableBlobStorage->GetBlobWhenReady(mRecorder->GetParentObject(),
NS_ConvertUTF16toUTF8(mMimeType),
aCallback);
mMutableBlobStorage = nullptr;
}
RefPtr<SizeOfPromise>
SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf)
{
MOZ_ASSERT(NS_IsMainThread());
size_t encodedBufferSize =
mEncodedBufferCache->SizeOfExcludingThis(aMallocSizeOf);
size_t encodedBufferSize = mMutableBlobStorage
? mMutableBlobStorage->SizeOfCurrentMemoryBuffer()
: 0;
if (!mEncoder) {
return SizeOfPromise::CreateAndResolve(encodedBufferSize, __func__);
@ -593,11 +665,11 @@ private:
MOZ_ASSERT(mShutdownPromise);
LOG(LogLevel::Debug, ("Session.~Session (%p)", this));
}
// Pull encoded media data from MediaEncoder and put into EncodedBufferCache.
// Pull encoded media data from MediaEncoder and put into MutableBlobStorage.
// Destroy this session object in the end of this function.
// If the bool aForceFlush is true, we will force to dispatch a
// PushBlobRunnable to main thread.
void Extract(bool aForceFlush)
void Extract(bool aForceFlush, Runnable* aDestroyRunnable)
{
MOZ_ASSERT(mEncoderThread->IsCurrentThreadIn());
@ -615,11 +687,8 @@ private:
}
// Append pulled data into cache buffer.
for (uint32_t i = 0; i < encodedBuf.Length(); i++) {
if (!encodedBuf[i].IsEmpty()) {
mEncodedBufferCache->AppendBuffer(encodedBuf[i]);
}
}
NS_DispatchToMainThread(new StoreEncodedBufferRunnable(this,
Move(encodedBuf)));
// Whether push encoded data back to onDataAvailable automatically or we
// need a flush.
@ -630,11 +699,15 @@ private:
pushBlob = true;
}
if (pushBlob) {
if (NS_FAILED(NS_DispatchToMainThread(new PushBlobRunnable(this)))) {
if (NS_FAILED(NS_DispatchToMainThread(new PushBlobRunnable(this, aDestroyRunnable)))) {
MOZ_ASSERT(false, "NS_DispatchToMainThread PushBlobRunnable failed");
} else {
mLastBlobTimeStamp = TimeStamp::Now();
}
} else if (aDestroyRunnable) {
if (NS_FAILED(NS_DispatchToMainThread(aDestroyRunnable))) {
MOZ_ASSERT(false, "NS_DispatchToMainThread DestroyRunnable failed");
}
}
}
@ -894,15 +967,20 @@ private:
&MediaRecorder::NotifyError,
rv));
}
RefPtr<Runnable> destroyRunnable = new DestroyRunnable(this);
if (rv != NS_ERROR_DOM_SECURITY_ERR) {
// Don't push a blob if there was a security error.
if (NS_FAILED(NS_DispatchToMainThread(new PushBlobRunnable(this)))) {
if (NS_FAILED(NS_DispatchToMainThread(new PushBlobRunnable(this, destroyRunnable)))) {
MOZ_ASSERT(false, "NS_DispatchToMainThread PushBlobRunnable failed");
}
} else {
if (NS_FAILED(NS_DispatchToMainThread(destroyRunnable))) {
MOZ_ASSERT(false, "NS_DispatchToMainThread DestroyRunnable failed");
}
}
if (NS_FAILED(NS_DispatchToMainThread(new DestroyRunnable(this)))) {
MOZ_ASSERT(false, "NS_DispatchToMainThread DestroyRunnable failed");
}
mNeedSessionEndTask = false;
}
@ -919,11 +997,8 @@ private:
}
// Append pulled data into cache buffer.
for (uint32_t i = 0; i < encodedBuf.Length(); i++) {
if (!encodedBuf[i].IsEmpty()) {
mEncodedBufferCache->AppendBuffer(encodedBuf[i]);
}
}
NS_DispatchToMainThread(new StoreEncodedBufferRunnable(this,
Move(encodedBuf)));
}
void MediaEncoderDataAvailable()
@ -936,7 +1011,7 @@ private:
mIsStartEventFired = true;
}
Extract(false);
Extract(false, nullptr);
}
void MediaEncoderError()
@ -953,14 +1028,11 @@ private:
MOZ_ASSERT(mEncoderThread->IsCurrentThreadIn());
MOZ_ASSERT(mEncoder->IsShutdown());
// Forces the last blob even if it's not time for it yet.
Extract(true);
// For the stop event. Let's the creation of the blob to dispatch this runnable.
RefPtr<Runnable> destroyRunnable = new DestroyRunnable(this);
// For the stop event.
if (NS_FAILED(NS_DispatchToMainThread(
new DestroyRunnable(this)))) {
MOZ_ASSERT(false, "NS_DispatchToMainThread DestroyRunnable failed");
}
// Forces the last blob even if it's not time for it yet.
Extract(true, destroyRunnable);
// Clean up.
mEncoderListener->Forget();
@ -1065,15 +1137,17 @@ private:
// Set in Shutdown() and resolved when shutdown is complete.
RefPtr<ShutdownPromise> mShutdownPromise;
// A buffer to cache encoded media data.
nsAutoPtr<EncodedBufferCache> mEncodedBufferCache;
RefPtr<MutableBlobStorage> mMutableBlobStorage;
// Max memory to use for the MutableBlobStorage.
uint64_t mMaxMemory;
// Current session mimeType
nsString mMimeType;
// Timestamp of the last fired dataavailable event.
TimeStamp mLastBlobTimeStamp;
// The interval of passing encoded data from EncodedBufferCache to onDataAvailable
// handler. "mTimeSlice < 0" means Session object does not push encoded data to
// onDataAvailable, instead, it passive wait the client side pull encoded data
// by calling requestData API.
// The interval of passing encoded data from MutableBlobStorage to
// onDataAvailable handler. "mTimeSlice < 0" means Session object does not
// push encoded data to onDataAvailable, instead, it passive wait the client
// side pull encoded data by calling requestData API.
const int32_t mTimeSlice;
// Indicate this session's stop has been called.
bool mStopIssued;
@ -1085,6 +1159,8 @@ private:
bool mNeedSessionEndTask;
};
NS_IMPL_ISUPPORTS_INHERITED0(MediaRecorder::Session::PushBlobRunnable, Runnable)
MediaRecorder::~MediaRecorder()
{
LOG(LogLevel::Debug, ("~MediaRecorder (%p)", this));
@ -1448,16 +1524,14 @@ MediaRecorder::IsTypeSupported(const nsAString& aMIMEType)
}
nsresult
MediaRecorder::CreateAndDispatchBlobEvent(already_AddRefed<nsIDOMBlob>&& aBlob)
MediaRecorder::CreateAndDispatchBlobEvent(Blob* aBlob)
{
MOZ_ASSERT(NS_IsMainThread(), "Not running on main thread");
BlobEventInit init;
init.mBubbles = false;
init.mCancelable = false;
nsCOMPtr<nsIDOMBlob> blob = aBlob;
init.mData = static_cast<Blob*>(blob.get());
init.mData = aBlob;
RefPtr<BlobEvent> event =
BlobEvent::Constructor(this,

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

@ -26,16 +26,17 @@ class GlobalObject;
namespace dom {
class AudioNode;
class Blob;
class DOMException;
/**
* Implementation of https://dvcs.w3.org/hg/dap/raw-file/default/media-stream-capture/MediaRecorder.html
* The MediaRecorder accepts a mediaStream as input source passed from UA. When recorder starts,
* a MediaEncoder will be created and accept the mediaStream as input source.
* Encoder will get the raw data by track data changes, encode it by selected MIME Type, then store the encoded in EncodedBufferCache object.
* Encoder will get the raw data by track data changes, encode it by selected MIME Type, then store the encoded in a MutableBlobStorage object.
* The encoded data will be extracted on every timeslice passed from Start function call or by RequestData function.
* Thread model:
* When the recorder starts, it creates a "Media Encoder" thread to read data from MediaEncoder object and store buffer in EncodedBufferCache object.
* When the recorder starts, it creates a "Media Encoder" thread to read data from MediaEncoder object and store buffer in MutableBlobStorage object.
* Also extract the encoded data and create blobs on every timeslice passed from start function or RequestData function called by UA.
*/
@ -72,7 +73,7 @@ public:
void Pause(ErrorResult& aResult);
// Resume a paused recording.
void Resume(ErrorResult& aResult);
// Extract encoded data Blob from EncodedBufferCache.
// Extract encoded data Blob from MutableBlobStorage.
void RequestData(ErrorResult& aResult);
// Return the The DOMMediaStream passed from UA.
DOMMediaStream* Stream() const { return mDOMStream; }
@ -121,7 +122,7 @@ protected:
MediaRecorder& operator = (const MediaRecorder& x) = delete;
// Create dataavailable event with Blob data and it runs in main thread
nsresult CreateAndDispatchBlobEvent(already_AddRefed<nsIDOMBlob>&& aBlob);
nsresult CreateAndDispatchBlobEvent(Blob* aBlob);
// Creating a simple event to notify UA simple event.
void DispatchSimpleEvent(const nsAString & aStr);
// Creating a error event with message.

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

@ -104,7 +104,6 @@ EXPORTS += [
'DecoderDoctorDiagnostics.h',
'DecoderTraits.h',
'DOMMediaStream.h',
'EncodedBufferCache.h',
'FileBlockCache.h',
'FrameStatistics.h',
'Intervals.h',
@ -219,7 +218,6 @@ UNIFIED_SOURCES += [
'CubebUtils.cpp',
'DecoderDoctorDiagnostics.cpp',
'DOMMediaStream.cpp',
'EncodedBufferCache.cpp',
'FileBlockCache.cpp',
'FileMediaResource.cpp',
'GetUserMediaRequest.cpp',

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

@ -71,8 +71,22 @@ PerformanceResourceTiming::~PerformanceResourceTiming()
DOMHighResTimeStamp
PerformanceResourceTiming::StartTime() const
{
DOMHighResTimeStamp startTime = mTiming->RedirectStartHighRes();
return startTime ? startTime : mTiming->FetchStartHighRes();
// Force the start time to be the earliest of:
// - RedirectStart
// - WorkerStart
// - AsyncOpen
// Ignore zero values. The RedirectStart and WorkerStart values
// can come from earlier redirected channels prior to the AsyncOpen
// time being recorded.
DOMHighResTimeStamp redirect = mTiming->RedirectStartHighRes();
redirect = redirect ? redirect : DBL_MAX;
DOMHighResTimeStamp worker = mTiming->WorkerStartHighRes();
worker = worker ? worker : DBL_MAX;
DOMHighResTimeStamp asyncOpen = mTiming->AsyncOpenHighRes();
return std::min(asyncOpen, std::min(redirect, worker));
}
JSObject*

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

@ -63,6 +63,12 @@ public:
mNextHopProtocol = aNextHopProtocol;
}
DOMHighResTimeStamp WorkerStart() const {
return mTiming && mTiming->TimingAllowed()
? mTiming->WorkerStartHighRes()
: 0;
}
DOMHighResTimeStamp FetchStart() const {
return mTiming
? mTiming->FetchStartHighRes()

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

@ -71,6 +71,7 @@ PerformanceTiming::InitializeTimingInfo(nsITimedChannel* aChannel)
{
if (aChannel) {
aChannel->GetAsyncOpen(&mAsyncOpen);
aChannel->GetDispatchFetchEventStart(&mWorkerStart);
aChannel->GetAllRedirectsSameOrigin(&mAllRedirectsSameOrigin);
aChannel->GetRedirectCount(&mRedirectCount);
aChannel->GetRedirectStart(&mRedirectStart);
@ -86,30 +87,38 @@ PerformanceTiming::InitializeTimingInfo(nsITimedChannel* aChannel)
aChannel->GetResponseEnd(&mResponseEnd);
aChannel->GetCacheReadEnd(&mCacheReadEnd);
// the performance timing api essentially requires that the event timestamps
// are >= asyncOpen().. but in truth the browser engages in a number of
// speculative activities that sometimes mean connections and lookups begin
// earlier. Workaround that here by just using asyncOpen as the minimum
// timestamp for dns and connection info.
// The performance timing api essentially requires that the event timestamps
// have a strict relation with each other. The truth, however, is the browser
// engages in a number of speculative activities that sometimes mean connections
// and lookups begin at different times. Workaround that here by clamping
// these values to what we expect FetchStart to be. This means the later of
// AsyncOpen or WorkerStart times.
if (!mAsyncOpen.IsNull()) {
if (!mDomainLookupStart.IsNull() && mDomainLookupStart < mAsyncOpen) {
mDomainLookupStart = mAsyncOpen;
// We want to clamp to the expected FetchStart value. This is later of
// the AsyncOpen and WorkerStart values.
const TimeStamp* clampTime = &mAsyncOpen;
if (!mWorkerStart.IsNull() && mWorkerStart > mAsyncOpen) {
clampTime = &mWorkerStart;
}
if (!mDomainLookupEnd.IsNull() && mDomainLookupEnd < mAsyncOpen) {
mDomainLookupEnd = mAsyncOpen;
if (!mDomainLookupStart.IsNull() && mDomainLookupStart < *clampTime) {
mDomainLookupStart = *clampTime;
}
if (!mConnectStart.IsNull() && mConnectStart < mAsyncOpen) {
mConnectStart = mAsyncOpen;
if (!mDomainLookupEnd.IsNull() && mDomainLookupEnd < *clampTime) {
mDomainLookupEnd = *clampTime;
}
if (!mSecureConnectionStart.IsNull() && mSecureConnectionStart < mAsyncOpen) {
mSecureConnectionStart = mAsyncOpen;
if (!mConnectStart.IsNull() && mConnectStart < *clampTime) {
mConnectStart = *clampTime;
}
if (!mConnectEnd.IsNull() && mConnectEnd < mAsyncOpen) {
mConnectEnd = mAsyncOpen;
if (!mSecureConnectionStart.IsNull() && mSecureConnectionStart < *clampTime) {
mSecureConnectionStart = *clampTime;
}
if (!mConnectEnd.IsNull() && mConnectEnd < *clampTime) {
mConnectEnd = *clampTime;
}
}
}
@ -129,9 +138,13 @@ PerformanceTiming::FetchStartHighRes()
}
MOZ_ASSERT(!mAsyncOpen.IsNull(), "The fetch start time stamp should always be "
"valid if the performance timing is enabled");
mFetchStart = (!mAsyncOpen.IsNull())
? TimeStampToDOMHighRes(mAsyncOpen)
: 0.0;
if (!mAsyncOpen.IsNull()) {
if (!mWorkerStart.IsNull() && mWorkerStart > mAsyncOpen) {
mFetchStart = TimeStampToDOMHighRes(mWorkerStart);
} else {
mFetchStart = TimeStampToDOMHighRes(mAsyncOpen);
}
}
}
return mFetchStart;
}
@ -178,7 +191,7 @@ PerformanceTiming::TimingAllowed() const
return mTimingAllowed;
}
uint16_t
uint8_t
PerformanceTiming::GetRedirectCount() const
{
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
@ -205,6 +218,26 @@ PerformanceTiming::ShouldReportCrossOriginRedirect() const
return (mRedirectCount != 0) && mReportCrossOriginRedirect;
}
DOMHighResTimeStamp
PerformanceTiming::AsyncOpenHighRes()
{
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
nsContentUtils::ShouldResistFingerprinting() || mAsyncOpen.IsNull()) {
return mZeroTime;
}
return TimeStampToDOMHighRes(mAsyncOpen);
}
DOMHighResTimeStamp
PerformanceTiming::WorkerStartHighRes()
{
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
nsContentUtils::ShouldResistFingerprinting() || mWorkerStart.IsNull()) {
return mZeroTime;
}
return TimeStampToDOMHighRes(mWorkerStart);
}
/**
* RedirectStartHighRes() is used by both the navigation timing and the
* resource timing. Since, navigation timing and resource timing check and

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

@ -141,7 +141,7 @@ public:
return GetDOMTiming()->GetUnloadEventEnd();
}
uint16_t GetRedirectCount() const;
uint8_t GetRedirectCount() const;
// Checks if the resource is either same origin as the page that started
// the load, or if the response contains the Timing-Allow-Origin header
@ -157,7 +157,12 @@ public:
// the timing-allow-origin check in HttpBaseChannel::TimingAllowCheck
bool ShouldReportCrossOriginRedirect() const;
// The last channel's AsyncOpen time. This may occur before the FetchStart
// in some cases.
DOMHighResTimeStamp AsyncOpenHighRes();
// High resolution (used by resource timing)
DOMHighResTimeStamp WorkerStartHighRes();
DOMHighResTimeStamp FetchStartHighRes();
DOMHighResTimeStamp RedirectStartHighRes();
DOMHighResTimeStamp RedirectEndHighRes();
@ -273,6 +278,7 @@ private:
DOMHighResTimeStamp mZeroTime;
TimeStamp mAsyncOpen;
TimeStamp mWorkerStart;
TimeStamp mRedirectStart;
TimeStamp mRedirectEnd;
TimeStamp mDomainLookupStart;
@ -285,7 +291,7 @@ private:
TimeStamp mCacheReadStart;
TimeStamp mResponseEnd;
TimeStamp mCacheReadEnd;
uint16_t mRedirectCount;
uint8_t mRedirectCount;
bool mTimingAllowed;
bool mAllRedirectsSameOrigin;
bool mInitialized;

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

@ -38,6 +38,7 @@ class nsSMILTimeValueSpec
{
public:
typedef mozilla::dom::Element Element;
typedef mozilla::dom::IDTracker IDTracker;
nsSMILTimeValueSpec(nsSMILTimedElement& aOwner, bool aIsBegin);
~nsSMILTimeValueSpec();
@ -86,10 +87,22 @@ protected:
// the target.
nsSMILTimeValueSpecParams mParams;
class TimeReferenceElement : public mozilla::dom::IDTracker
/**
* If our nsSMILTimeValueSpec exists for a 'begin' or 'end' attribute with a
* value that specifies a time that is relative to the animation of some
* other element, it will create an instance of this class to reference and
* track that other element. For example, if the nsSMILTimeValueSpec is for
* end='a.end+2s', an instance of this class will be created to track the
* element associated with the element ID "a". This class will notify the
* nsSMILTimeValueSpec if the element that that ID identifies changes to a
* different element (or none).
*/
class TimeReferenceTracker final : public IDTracker
{
public:
explicit TimeReferenceElement(nsSMILTimeValueSpec* aOwner) : mSpec(aOwner) { }
explicit TimeReferenceTracker(nsSMILTimeValueSpec* aOwner)
: mSpec(aOwner)
{}
void ResetWithElement(Element* aTo) {
RefPtr<Element> from = get();
Unlink();
@ -107,7 +120,7 @@ protected:
nsSMILTimeValueSpec* mSpec;
};
TimeReferenceElement mReferencedElement;
TimeReferenceTracker mReferencedElement;
class EventListener final : public nsIDOMEventListener
{

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

@ -99,10 +99,19 @@ public:
const nsAString& aHrefStr);
void AnimationTargetChanged();
class TargetReference : public mozilla::dom::IDTracker {
/**
* Helper that provides a reference to the element with the ID that is
* referenced by the animation element's 'href' attribute, if any, and that
* will notify the animation element if the element that that ID identifies
* changes to a different element (or none). (If the 'href' attribute is not
* specified, then the animation target is the parent element and this helper
* is not used.)
*/
class HrefTargetTracker final : public IDTracker {
public:
explicit TargetReference(SVGAnimationElement* aAnimationElement) :
mAnimationElement(aAnimationElement) {}
explicit HrefTargetTracker(SVGAnimationElement* aAnimationElement)
: mAnimationElement(aAnimationElement)
{}
protected:
// We need to be notified when target changes, in order to request a
// sample (which will clear animation effects from old target and apply
@ -119,7 +128,7 @@ public:
SVGAnimationElement* const mAnimationElement;
};
TargetReference mHrefTarget;
HrefTargetTracker mHrefTarget;
nsSMILTimedElement mTimedElement;
};

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

@ -41,7 +41,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(SVGMPathElement,
SVGMPathElementBase)
tmp->mHrefTarget.Traverse(&cb);
tmp->mPathTracker.Traverse(&cb);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
//----------------------------------------------------------------------
@ -56,8 +56,8 @@ NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(SVGMPathElement,
// Constructor
SVGMPathElement::SVGMPathElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
: SVGMPathElementBase(aNodeInfo),
mHrefTarget(this)
: SVGMPathElementBase(aNodeInfo)
, mPathTracker(this)
{
}
@ -88,7 +88,7 @@ SVGMPathElement::BindToTree(nsIDocument* aDocument,
nsIContent* aBindingParent,
bool aCompileEventHandlers)
{
MOZ_ASSERT(!mHrefTarget.get(),
MOZ_ASSERT(!mPathTracker.get(),
"Shouldn't have href-target yet (or it should've been cleared)");
nsresult rv = SVGMPathElementBase::BindToTree(aDocument, aParent,
aBindingParent,
@ -205,13 +205,13 @@ SVGMPathElement::GetReferencedPath()
{
if (!HasAttr(kNameSpaceID_XLink, nsGkAtoms::href) &&
!HasAttr(kNameSpaceID_None, nsGkAtoms::href)) {
MOZ_ASSERT(!mHrefTarget.get(),
MOZ_ASSERT(!mPathTracker.get(),
"We shouldn't have a href target "
"if we don't have an xlink:href or href attribute");
return nullptr;
}
nsIContent* genericTarget = mHrefTarget.get();
nsIContent* genericTarget = mPathTracker.get();
if (genericTarget && genericTarget->IsSVGElement(nsGkAtoms::path)) {
return static_cast<SVGPathElement*>(genericTarget);
}
@ -231,24 +231,24 @@ SVGMPathElement::UpdateHrefTarget(nsIContent* aParent,
aHrefStr, OwnerDoc(), baseURI);
// Stop observing old target (if any)
if (mHrefTarget.get()) {
mHrefTarget.get()->RemoveMutationObserver(this);
if (mPathTracker.get()) {
mPathTracker.get()->RemoveMutationObserver(this);
}
if (aParent) {
// Pass in |aParent| instead of |this| -- first argument is only used
// for a call to GetComposedDoc(), and |this| might not have a current
// document yet (if our caller is BindToTree).
mHrefTarget.Reset(aParent, targetURI);
mPathTracker.Reset(aParent, targetURI);
} else {
// if we don't have a parent, then there's no animateMotion element
// depending on our target, so there's no point tracking it right now.
mHrefTarget.Unlink();
mPathTracker.Unlink();
}
// Start observing new target (if any)
if (mHrefTarget.get()) {
mHrefTarget.get()->AddMutationObserver(this);
if (mPathTracker.get()) {
mPathTracker.get()->AddMutationObserver(this);
}
NotifyParentOfMpathChange(aParent);
@ -258,10 +258,10 @@ void
SVGMPathElement::UnlinkHrefTarget(bool aNotifyParent)
{
// Stop observing old target (if any)
if (mHrefTarget.get()) {
mHrefTarget.get()->RemoveMutationObserver(this);
if (mPathTracker.get()) {
mPathTracker.get()->RemoveMutationObserver(this);
}
mHrefTarget.Unlink();
mPathTracker.Unlink();
if (aNotifyParent) {
NotifyParentOfMpathChange(GetParent());

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

@ -66,10 +66,18 @@ public:
already_AddRefed<SVGAnimatedString> Href();
protected:
class PathReference : public mozilla::dom::IDTracker {
/**
* Helper that provides a reference to the 'path' element with the ID that is
* referenced by the 'mpath' element's 'href' attribute, and that will
* invalidate the parent of the 'mpath' and update mutation observers to the
* new path element if the element that that ID identifies changes to a
* different element (or none).
*/
class PathElementTracker final : public IDTracker {
public:
explicit PathReference(SVGMPathElement* aMpathElement) :
mMpathElement(aMpathElement) {}
explicit PathElementTracker(SVGMPathElement* aMpathElement)
: mMpathElement(aMpathElement)
{}
protected:
// We need to be notified when target changes, in order to request a sample
// (which will clear animation effects that used the old target-path
@ -101,7 +109,7 @@ protected:
enum { HREF, XLINK_HREF };
nsSVGString mStringAttributes[2];
static StringInfo sStringInfo[2];
PathReference mHrefTarget;
PathElementTracker mPathTracker;
};
} // namespace dom

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

@ -62,7 +62,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(SVGUseElement,
SVGUseElementBase)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOriginal)
tmp->mSource.Traverse(&cb);
tmp->mReferencedElementTracker.Traverse(&cb);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(SVGUseElement,
@ -73,7 +73,8 @@ NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(SVGUseElement,
// Implementation
SVGUseElement::SVGUseElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
: SVGUseElementBase(aNodeInfo), mSource(this)
: SVGUseElementBase(aNodeInfo)
, mReferencedElementTracker(this)
{
}
@ -210,12 +211,12 @@ SVGUseElement::NodeWillBeDestroyed(const nsINode *aNode)
already_AddRefed<nsIContent>
SVGUseElement::CreateAnonymousContent()
{
if (mSource.get()) {
mSource.get()->RemoveMutationObserver(this);
if (mReferencedElementTracker.get()) {
mReferencedElementTracker.get()->RemoveMutationObserver(this);
}
LookupHref();
nsIContent* targetContent = mSource.get();
nsIContent* targetContent = mReferencedElementTracker.get();
if (!targetContent)
return nullptr;
@ -300,7 +301,7 @@ SVGUseElement::CreateAnonymousContent()
nsIURI*
SVGUseElement::GetSourceDocURI()
{
nsIContent* targetContent = mSource.get();
nsIContent* targetContent = mReferencedElementTracker.get();
if (!targetContent)
return nullptr;
@ -378,7 +379,7 @@ SVGUseElement::LookupHref()
nsCOMPtr<nsIURI> targetURI;
nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(targetURI), href,
GetComposedDoc(), baseURI);
mSource.Reset(this, targetURI);
mReferencedElementTracker.Reset(this, targetURI);
}
void
@ -396,10 +397,10 @@ SVGUseElement::TriggerReclone()
void
SVGUseElement::UnlinkSource()
{
if (mSource.get()) {
mSource.get()->RemoveMutationObserver(this);
if (mReferencedElementTracker.get()) {
mReferencedElementTracker.get()->RemoveMutationObserver(this);
}
mSource.Unlink();
mReferencedElementTracker.Unlink();
}
//----------------------------------------------------------------------

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

@ -81,19 +81,27 @@ public:
URLExtraData* GetContentURLData() const { return mContentURLData; }
protected:
class SourceReference : public mozilla::dom::IDTracker {
/**
* Helper that provides a reference to the element with the ID that is
* referenced by the 'use' element's 'href' attribute, and that will update
* the 'use' element if the element that that ID identifies changes to a
* different element (or none).
*/
class ElementTracker final : public IDTracker {
public:
explicit SourceReference(SVGUseElement* aContainer) : mContainer(aContainer) {}
explicit ElementTracker(SVGUseElement* aOwningUseElement)
: mOwningUseElement(aOwningUseElement)
{}
protected:
virtual void ElementChanged(Element* aFrom, Element* aTo) override {
IDTracker::ElementChanged(aFrom, aTo);
if (aFrom) {
aFrom->RemoveMutationObserver(mContainer);
aFrom->RemoveMutationObserver(mOwningUseElement);
}
mContainer->TriggerReclone();
mOwningUseElement->TriggerReclone();
}
private:
SVGUseElement* mContainer;
SVGUseElement* mOwningUseElement;
};
nsSVGUseFrame* GetFrame() const;
@ -122,7 +130,7 @@ protected:
nsCOMPtr<nsIContent> mOriginal; // if we've been cloned, our "real" copy
nsCOMPtr<nsIContent> mClone; // cloned tree
SourceReference mSource; // observed element
ElementTracker mReferencedElementTracker;
RefPtr<URLExtraData> mContentURLData; // URL data for its anonymous content
};

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

@ -247,14 +247,8 @@ U2F::Register(const nsAString& aAppId,
{
MOZ_ASSERT(NS_IsMainThread());
RefPtr<U2FManager> mgr = U2FManager::GetOrCreate();
MOZ_ASSERT(mgr);
if (!mgr || mRegisterCallback.isSome()) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
Cancel();
MOZ_ASSERT(mRegisterCallback.isNothing());
mRegisterCallback = Some(nsMainThreadPtrHandle<U2FRegisterCallback>(
new nsMainThreadPtrHolder<U2FRegisterCallback>(
@ -307,6 +301,7 @@ U2F::Register(const nsAString& aAppId,
auto& localReqHolder = mPromiseHolder;
auto& localCb = mRegisterCallback;
RefPtr<U2FManager> mgr = U2FManager::GetOrCreate();
RefPtr<U2FPromise> p = mgr->Register(mParent, cAppId,
NS_ConvertUTF16toUTF8(clientDataJSON),
adjustedTimeoutMillis, excludeList);
@ -344,14 +339,8 @@ U2F::Sign(const nsAString& aAppId,
{
MOZ_ASSERT(NS_IsMainThread());
RefPtr<U2FManager> mgr = U2FManager::GetOrCreate();
MOZ_ASSERT(mgr);
if (!mgr || mSignCallback.isSome()) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
Cancel();
MOZ_ASSERT(mSignCallback.isNothing());
mSignCallback = Some(nsMainThreadPtrHandle<U2FSignCallback>(
new nsMainThreadPtrHolder<U2FSignCallback>(
@ -389,6 +378,7 @@ U2F::Sign(const nsAString& aAppId,
permittedList);
auto& localReqHolder = mPromiseHolder;
auto& localCb = mSignCallback;
RefPtr<U2FManager> mgr = U2FManager::GetOrCreate();
RefPtr<U2FPromise> p = mgr->Sign(mParent, cAppId,
NS_ConvertUTF16toUTF8(clientDataJSON),
adjustedTimeoutMillis, permittedList);

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

@ -4,7 +4,7 @@
* You can obtain one at http://mozilla.org/MPL/2.0/.
*
* The origin of this IDL file is
* http://w3c-test.org/webperf/specs/ResourceTiming/#performanceresourcetiming
* https://w3c.github.io/resource-timing/#performanceresourcetiming
*
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* liability, trademark and document use rules apply.
@ -12,14 +12,10 @@
interface PerformanceResourceTiming : PerformanceEntry
{
// A string with the name of that element that initiated the load.
// If the initiator is a CSS resource, the initiatorType attribute must return
// the string "css".
// If the initiator is an XMLHttpRequest object, the initiatorType attribute
// must return the string "xmlhttprequest".
readonly attribute DOMString initiatorType;
readonly attribute DOMString nextHopProtocol;
readonly attribute DOMHighResTimeStamp workerStart;
readonly attribute DOMHighResTimeStamp redirectStart;
readonly attribute DOMHighResTimeStamp redirectEnd;
readonly attribute DOMHighResTimeStamp fetchStart;

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