MozReview-Commit-ID: CaSKFN9T7N4
This commit is contained in:
Wes Kocher 2017-06-21 18:05:27 -07:00
Родитель 171f11740d ac0fd2038c
Коммит bb24138b9d
392 изменённых файлов: 33927 добавлений и 24813 удалений

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

@ -26,8 +26,14 @@ jobs:
treeherder-symbol: Nd-OSX
target-tasks-method: nightly_macosx
run-on-projects:
- mozilla-central
- date
when: [] # never (hook only)
when:
by-project:
# Match buildbot starts for now
date: [{hour: 15, minute: 0}]
mozilla-central: [{hour: 10, minute: 0}]
# No default
- name: nightly-desktop-win64
job:

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

@ -1561,7 +1561,7 @@ pref("extensions.allow-non-mpc-extensions", false);
#endif
// Enable blocking of e10s and e10s-multi for add-on users on beta/release.
#ifdef RELEASE_OR_BETA
#if defined(RELEASE_OR_BETA) && !defined(MOZ_DEV_EDITION)
pref("extensions.e10sBlocksEnabling", true);
pref("extensions.e10sMultiBlocksEnabling", true);
#endif

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

@ -2459,7 +2459,7 @@
// transition in that case.
let animate = !aSkipAnimation &&
this.tabContainer.getAttribute("overflow") != "true" &&
Services.prefs.getBoolPref("toolkit.cosmeticAnimations.enabled");
this.animationsEnabled;
if (!animate) {
t.setAttribute("fadein", "true");
@ -2814,7 +2814,7 @@
this._removingTabs.length > 3 /* don't want lots of concurrent animations */ ||
aTab.getAttribute("fadein") != "true" /* fade-in transition hasn't been triggered yet */ ||
window.getComputedStyle(aTab).maxWidth == "0.1px" /* fade-in transition hasn't moved yet */ ||
!Services.prefs.getBoolPref("toolkit.cosmeticAnimations.enabled")) {
!this.animationsEnabled) {
// We're not animating, so we can cancel the animation stopwatch.
TelemetryStopwatch.cancel("FX_TAB_CLOSE_TIME_ANIM_MS", aTab);
this._endRemoveTab(aTab);
@ -5418,6 +5418,9 @@
messageManager.addMessageListener("Prerender:Request", this);
messageManager.addMessageListener("Prerender:Cancel", this);
messageManager.addMessageListener("Prerender:Swap", this);
XPCOMUtils.defineLazyPreferenceGetter(this, "animationsEnabled",
"toolkit.cosmeticAnimations.enabled", true);
]]>
</constructor>
@ -7060,7 +7063,8 @@
if (dropIndex && dropIndex > draggedTab._tPos)
dropIndex--;
if (oldTranslateX && oldTranslateX != newTranslateX) {
let animate = this.tabbrowser.animationsEnabled;
if (oldTranslateX && oldTranslateX != newTranslateX && animate) {
draggedTab.setAttribute("tabdrop-samewindow", "true");
draggedTab.style.transform = "translateX(" + newTranslateX + "px)";
let onTransitionEnd = transitionendEvent => {

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

@ -246,6 +246,9 @@ var CustomizableUIInternal = {
"home-button",
];
if (AppConstants.MOZ_PHOTON_THEME) {
navbarPlacements.push("sidebar-button");
}
if (AppConstants.MOZ_DEV_EDITION) {
navbarPlacements.splice(2, 0, "developer-button");
}

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

@ -61,15 +61,9 @@ class ParentDevToolsPanel {
this.id = this.panelOptions.id;
this.onToolboxPanelSelect = this.onToolboxPanelSelect.bind(this);
this.onToolboxReady = this.onToolboxReady.bind(this);
this.panelAdded = false;
if (this.toolbox.isReady) {
this.onToolboxReady();
} else {
this.toolbox.once("ready", this.onToolboxReady);
}
this.addPanel();
this.waitTopLevelContext = new Promise(resolve => {
this._resolveTopLevelContext = resolve;
@ -99,6 +93,8 @@ class ParentDevToolsPanel {
return {toolbox, destroy};
},
});
this.panelAdded = true;
}
buildPanel(window, toolbox) {
@ -180,13 +176,6 @@ class ParentDevToolsPanel {
};
}
onToolboxReady() {
if (!this.panelAdded) {
this.panelAdded = true;
this.addPanel();
}
}
onToolboxPanelSelect(what, id) {
if (!this.waitTopLevelContext || !this.panelAdded) {
return;
@ -214,11 +203,9 @@ class ParentDevToolsPanel {
throw new Error("Unable to destroy a closed devtools panel");
}
toolbox.off("ready", this.onToolboxReady);
// Explicitly remove the panel if it is registered and the toolbox is not
// closing itself.
if (toolbox.isToolRegistered(this.id) && !toolbox._destroyer) {
if (this.panelAdded && toolbox.isToolRegistered(this.id) && !toolbox._destroyer) {
toolbox.removeAdditionalTool(this.id);
}

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

@ -1127,9 +1127,9 @@
<handler event="popuphiding"><![CDATA[
this._isHiding = true;
setTimeout(() => {
Services.tm.dispatchToMainThread(() => {
this._isHiding = false;
}, 0);
});
]]></handler>
<!-- This handles clicks on the topmost "Foo Search" header in the

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

@ -3255,7 +3255,6 @@ var SessionStoreInternal = {
}
let tabbrowser = aWindow.gBrowser;
let tabsToRemove = overwriteTabs ? tabbrowser.browsers.length : 0;
let newTabCount = winData.tabs.length;
var tabs = [];
@ -3266,11 +3265,20 @@ var SessionStoreInternal = {
// We need to keep track of the initially open tabs so that they
// can be moved to the end of the restored tabs.
let initialTabs = [];
let initialTabs;
if (!overwriteTabs && firstWindow) {
initialTabs = Array.slice(tabbrowser.tabs);
}
// Get rid of tabs that aren't needed anymore.
if (overwriteTabs) {
for (let i = tabbrowser.browsers.length - 1; i >= 0; i--) {
if (!tabbrowser.tabs[i].selected) {
tabbrowser.removeTab(tabbrowser.tabs[i]);
}
}
}
let restoreTabsLazily = this._prefBranch.getBoolPref("sessionstore.restore_tabs_lazily") &&
this._prefBranch.getBoolPref("sessionstore.restore_on_demand");
@ -3279,61 +3287,67 @@ var SessionStoreInternal = {
let userContextId = tabData.userContextId;
let select = t == selectTab - 1;
let createLazyBrowser = restoreTabsLazily && !select && !tabData.pinned;
let tab;
let url = "about:blank";
if (createLazyBrowser && tabData.entries && tabData.entries.length) {
// Let tabbrowser know the future URI because progress listeners won't
// get onLocationChange notification before the browser is inserted.
let activeIndex = (tabData.index || tabData.entries.length) - 1;
// Ensure the index is in bounds.
activeIndex = Math.min(activeIndex, tabData.entries.length - 1);
activeIndex = Math.max(activeIndex, 0);
url = tabData.entries[activeIndex].url;
// Re-use existing selected tab if possible to avoid the overhead of
// selecting a new tab.
if (select &&
tabbrowser.selectedTab.userContextId == userContextId) {
tab = tabbrowser.selectedTab;
if (!tabData.pinned) {
tabbrowser.unpinTab(tab);
}
tabbrowser.moveTabToEnd();
if (aWindow.gMultiProcessBrowser && !tab.linkedBrowser.isRemoteBrowser) {
tabbrowser.updateBrowserRemoteness(tab.linkedBrowser, true);
}
}
// Setting noInitialLabel is a perf optimization. Rendering tab labels
// would make resizing the tabs more expensive as we're adding them.
// Each tab will get its initial label set in restoreTab.
let tab = tabbrowser.addTab(url,
{ createLazyBrowser,
skipAnimation: true,
noInitialLabel: true,
userContextId,
skipBackgroundNotify: true });
// Add a new tab if needed.
if (!tab) {
let createLazyBrowser = restoreTabsLazily && !select && !tabData.pinned;
if (select) {
// Select a new tab first to prevent the removeTab loop from changing
// the selected tab over and over again.
tabbrowser.selectedTab = tab;
// Remove superfluous tabs.
for (let i = 0; i < tabsToRemove; i++) {
tabbrowser.removeTab(tabbrowser.tabs[0]);
let url = "about:blank";
if (createLazyBrowser && tabData.entries && tabData.entries.length) {
// Let tabbrowser know the future URI because progress listeners won't
// get onLocationChange notification before the browser is inserted.
let activeIndex = (tabData.index || tabData.entries.length) - 1;
// Ensure the index is in bounds.
activeIndex = Math.min(activeIndex, tabData.entries.length - 1);
activeIndex = Math.max(activeIndex, 0);
url = tabData.entries[activeIndex].url;
}
// Setting noInitialLabel is a perf optimization. Rendering tab labels
// would make resizing the tabs more expensive as we're adding them.
// Each tab will get its initial label set in restoreTab.
tab = tabbrowser.addTab(url,
{ createLazyBrowser,
skipAnimation: true,
noInitialLabel: true,
userContextId,
skipBackgroundNotify: true });
if (select) {
let leftoverTab = tabbrowser.selectedTab;
tabbrowser.selectedTab = tab;
tabbrowser.removeTab(leftoverTab);
}
tabsToRemove = 0;
}
tabs.push(tab);
if (tabData.hidden) {
tabbrowser.hideTab(tabs[t]);
tabbrowser.hideTab(tab);
}
if (tabData.pinned) {
tabbrowser.pinTab(tab);
}
}
for (let i = 0; i < newTabCount; ++i) {
if (winData.tabs[i].pinned) {
tabbrowser.pinTab(tabs[i]);
} else {
// Pinned tabs are clustered at the start of the tab strip. As
// soon as we reach a tab that isn't pinned, we know there aren't
// any more for this window.
break;
}
}
if (!overwriteTabs && firstWindow) {
// Move the originally open tabs to the end
// Move the originally open tabs to the end.
if (initialTabs) {
let endPosition = tabbrowser.tabs.length - 1;
for (let i = 0; i < initialTabs.length; i++) {
tabbrowser.unpinTab(initialTabs[i]);

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

@ -239,6 +239,7 @@ run-if = e10s
run-if = e10s
[browser_sessionStoreContainer.js]
[browser_windowStateContainer.js]
skip-if = os == "linux" && !debug
[browser_1234021.js]
[browser_remoteness_flip_on_restore.js]
run-if = e10s

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

@ -1,6 +1,13 @@
. "$topsrcdir/browser/config/mozconfigs/common"
. "$topsrcdir/build/mozconfig.no-compile"
# We need to indicate the target for cross builds
ac_add_options --target=x86_64-apple-darwin
export MKFSHFS=$topsrcdir/hfsplus-tools/newfs_hfs
export DMG_TOOL=$topsrcdir/dmg/dmg
export HFS_TOOL=$topsrcdir/dmg/hfsplus
ac_add_options --with-l10n-base=../../l10n
ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
ac_add_options --with-branding=browser/branding/nightly

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

@ -1,6 +1,13 @@
. "$topsrcdir/browser/config/mozconfigs/common"
. "$topsrcdir/build/mozconfig.no-compile"
# We need to indicate the target for cross builds
ac_add_options --target=x86_64-apple-darwin
export MKFSHFS=$topsrcdir/hfsplus-tools/newfs_hfs
export DMG_TOOL=$topsrcdir/dmg/dmg
export HFS_TOOL=$topsrcdir/dmg/hfsplus
ac_add_options --with-l10n-base=../../l10n
ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
ac_add_options --with-branding=browser/branding/aurora

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

@ -14,7 +14,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "Services",
"resource://gre/modules/Services.jsm");
const ACTIVITY_STREAM_ENABLED_PREF = "browser.newtabpage.activity-stream.enabled";
const BROWSER_READY_NOTIFICATION = "browser-ui-startup-complete";
const BROWSER_READY_NOTIFICATION = "browser-delayed-startup-finished";
const REASON_SHUTDOWN_ON_PREF_CHANGE = "PREF_OFF";
const REASON_STARTUP_ON_PREF_CHANGE = "PREF_ON";
const RESOURCE_BASE = "resource://activity-stream";

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

@ -0,0 +1,95 @@
/* globals Services */
"use strict";
let usablePerfObj;
let Cu;
const isRunningInChrome = typeof Window === "undefined";
/* istanbul ignore if */
if (isRunningInChrome) {
Cu = Components.utils;
} else {
Cu = {import() {}};
}
Cu.import("resource://gre/modules/Services.jsm");
/* istanbul ignore if */
if (isRunningInChrome) {
// Borrow the high-resolution timer from the hidden window....
usablePerfObj = Services.appShell.hiddenDOMWindow.performance;
} else { // we must be running in content space
usablePerfObj = performance;
}
this._PerfService = function _PerfService(options) {
// For testing, so that we can use a fake Window.performance object with
// known state.
if (options && options.performanceObj) {
this._perf = options.performanceObj;
} else {
this._perf = usablePerfObj;
}
};
_PerfService.prototype = {
/**
* Calls the underlying mark() method on the appropriate Window.performance
* object to add a mark with the given name to the appropriate performance
* timeline.
*
* @param {String} name the name to give the current mark
* @return {void}
*/
mark: function mark(str) {
this._perf.mark(str);
},
/**
* Calls the underlying getEntriesByName on the appropriate Window.performance
* object.
*
* @param {String} name
* @param {String} type eg "mark"
* @return {Array} Performance* objects
*/
getEntriesByName: function getEntriesByName(name, type) {
return this._perf.getEntriesByName(name, type);
},
/**
* The timeOrigin property from the appropriate performance object.
* Used to ensure that timestamps from the add-on code and the content code
* are comparable.
*
* @return {Number} A double of milliseconds with a precision of 0.5us.
*/
get timeOrigin() {
return this._perf.timeOrigin;
},
/**
* This returns the startTime from the most recen!t performance.mark()
* with the given name.
*
* @param {String} name the name to lookup the start time for
*
* @return {Number} the returned start time, as a DOMHighResTimeStamp
*
* @throws {Error} "No Marks with the name ..." if none are available
*/
getMostRecentAbsMarkStartByName(name) {
let entries = this.getEntriesByName(name, "mark");
if (!entries.length) {
throw new Error(`No marks with the name ${name}`);
}
let mostRecentEntry = entries[entries.length - 1];
return this._perf.timeOrigin + mostRecentEntry.startTime;
}
};
this.perfService = new _PerfService();
this.EXPORTED_SYMBOLS = ["_PerfService", "perfService"];

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

@ -63,7 +63,7 @@
/******/ __webpack_require__.p = "";
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 17);
/******/ return __webpack_require__(__webpack_require__.s = 18);
/******/ })
/************************************************************************/
/******/ ([
@ -394,6 +394,10 @@ var _require = __webpack_require__(1);
const at = _require.actionTypes;
var _require2 = __webpack_require__(15);
const perfSvc = _require2.perfService;
const VISIBLE = "visible";
const VISIBILITY_CHANGE_EVENT = "visibilitychange";
@ -405,7 +409,7 @@ module.exports = class DetectUserSessionStart {
// Overrides for testing
this.sendAsyncMessage = options.sendAsyncMessage || window.sendAsyncMessage;
this.document = options.document || document;
this._perfService = options.perfService || perfSvc;
this._onVisibilityChange = this._onVisibilityChange.bind(this);
}
@ -427,11 +431,19 @@ module.exports = class DetectUserSessionStart {
}
/**
* _sendEvent - Sends a message to the main process to indicate the current tab
* is now visible to the user.
* _sendEvent - Sends a message to the main process to indicate the current
* tab is now visible to the user, includes the
* visibility-change-event time in ms from the UNIX epoch.
*/
_sendEvent() {
this.sendAsyncMessage("ActivityStream:ContentToMain", { type: at.NEW_TAB_VISIBLE });
this._perfService.mark("visibility-change-event");
let absVisChangeTime = this._perfService.getMostRecentAbsMarkStartByName("visibility-change-event");
this.sendAsyncMessage("ActivityStream:ContentToMain", {
type: at.NEW_TAB_VISIBLE,
data: { absVisibilityChangeTime: absVisChangeTime }
});
}
/**
@ -455,7 +467,7 @@ module.exports = class DetectUserSessionStart {
/* eslint-env mozilla/frame-script */
var _require = __webpack_require__(16);
var _require = __webpack_require__(17);
const createStore = _require.createStore,
combineReducers = _require.combineReducers,
@ -892,7 +904,7 @@ var _require2 = __webpack_require__(3);
const injectIntl = _require2.injectIntl,
FormattedMessage = _require2.FormattedMessage;
const classNames = __webpack_require__(15);
const classNames = __webpack_require__(16);
var _require3 = __webpack_require__(1);
@ -1044,7 +1056,12 @@ class Search extends React.Component {
}
onInputMount(input) {
if (input) {
this.controller = new ContentSearchUIController(input, input.parentNode, "activity", "newtab");
// The first "newtab" parameter here is called the "healthReportKey" and needs
// to be "newtab" so that BrowserUsageTelemetry.jsm knows to handle events with
// this name, and can add the appropriate telemetry probes for search. Without the
// correct name, certain tests like browser_UsageTelemetry_content.js will fail (See
// github ticket #2348 for more details)
this.controller = new ContentSearchUIController(input, input.parentNode, "newtab", "newtab");
addEventListener("ContentSearchClient", this);
} else {
this.controller = null;
@ -1052,13 +1069,18 @@ class Search extends React.Component {
}
}
/*
* Do not change the ID on the input field, as legacy newtab code
* specifically looks for the id 'newtab-search-text' on input fields
* in order to execute searches in various tests
*/
render() {
return React.createElement(
"form",
{ className: "search-wrapper" },
React.createElement(
"label",
{ htmlFor: "search-input", className: "search-label" },
{ htmlFor: "newtab-search-text", className: "search-label" },
React.createElement(
"span",
{ className: "sr-only" },
@ -1066,7 +1088,7 @@ class Search extends React.Component {
)
),
React.createElement("input", {
id: "search-input",
id: "newtab-search-text",
maxLength: "256",
placeholder: this.props.intl.formatMessage({ id: "search_web_placeholder" }),
ref: this.onInputMount,
@ -1251,6 +1273,111 @@ module.exports = function shortURL(link) {
/* 15 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
/* globals Services */
let usablePerfObj;
let Cu;
const isRunningInChrome = typeof Window === "undefined";
/* istanbul ignore if */
if (isRunningInChrome) {
Cu = Components.utils;
} else {
Cu = { import() {} };
}
Cu.import("resource://gre/modules/Services.jsm");
/* istanbul ignore if */
if (isRunningInChrome) {
// Borrow the high-resolution timer from the hidden window....
usablePerfObj = Services.appShell.hiddenDOMWindow.performance;
} else {
// we must be running in content space
usablePerfObj = performance;
}
var _PerfService = function _PerfService(options) {
// For testing, so that we can use a fake Window.performance object with
// known state.
if (options && options.performanceObj) {
this._perf = options.performanceObj;
} else {
this._perf = usablePerfObj;
}
};
_PerfService.prototype = {
/**
* Calls the underlying mark() method on the appropriate Window.performance
* object to add a mark with the given name to the appropriate performance
* timeline.
*
* @param {String} name the name to give the current mark
* @return {void}
*/
mark: function mark(str) {
this._perf.mark(str);
},
/**
* Calls the underlying getEntriesByName on the appropriate Window.performance
* object.
*
* @param {String} name
* @param {String} type eg "mark"
* @return {Array} Performance* objects
*/
getEntriesByName: function getEntriesByName(name, type) {
return this._perf.getEntriesByName(name, type);
},
/**
* The timeOrigin property from the appropriate performance object.
* Used to ensure that timestamps from the add-on code and the content code
* are comparable.
*
* @return {Number} A double of milliseconds with a precision of 0.5us.
*/
get timeOrigin() {
return this._perf.timeOrigin;
},
/**
* This returns the startTime from the most recen!t performance.mark()
* with the given name.
*
* @param {String} name the name to lookup the start time for
*
* @return {Number} the returned start time, as a DOMHighResTimeStamp
*
* @throws {Error} "No Marks with the name ..." if none are available
*/
getMostRecentAbsMarkStartByName(name) {
let entries = this.getEntriesByName(name, "mark");
if (!entries.length) {
throw new Error(`No marks with the name ${name}`);
}
let mostRecentEntry = entries[entries.length - 1];
return this._perf.timeOrigin + mostRecentEntry.startTime;
}
};
var perfService = new _PerfService();
module.exports = {
_PerfService,
perfService
};
/***/ }),
/* 16 */
/***/ (function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*!
Copyright (c) 2016 Jed Watson.
Licensed under the MIT License (MIT), see
@ -1303,13 +1430,13 @@ var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*!
/***/ }),
/* 16 */
/* 17 */
/***/ (function(module, exports) {
module.exports = Redux;
/***/ }),
/* 17 */
/* 18 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";

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

@ -861,6 +861,7 @@
"header_top_sites": "Top Sites",
"header_highlights": "Highlights",
"header_stories": "Top Stories",
"header_visit_again": "Visit Again",
"header_bookmarks": "Recent Bookmarks",
"header_bookmarks_placeholder": "You don't have any bookmarks yet.",
"header_stories_from": "from",
@ -903,6 +904,8 @@
"settings_pane_highlights_body": "Look back at your recent browsing history and newly created bookmarks.",
"settings_pane_bookmarks_header": "Recent Bookmarks",
"settings_pane_bookmarks_body": "Your newly created bookmarks in one handy location.",
"settings_pane_visit_again_header": "Visit Again",
"settings_pane_visit_again_body": "Firefox will show you parts of your browsing history that you might want to remember or get back to.",
"settings_pane_pocketstories_header": "Top Stories",
"settings_pane_pocketstories_body": "Pocket, a part of the Mozilla family, will help connect you to high-quality content that you may not have found otherwise.",
"settings_pane_done_button": "Done",

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

@ -1,14 +1,17 @@
/* 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/. */
/* globals Services */
"use strict";
const {utils: Cu} = Components;
const {interfaces: Ci, utils: Cu} = Components;
const {actionTypes: at, actionUtils: au} = Cu.import("resource://activity-stream/common/Actions.jsm", {});
const {perfService} = Cu.import("resource://activity-stream/common/PerfService.jsm", {});
Cu.import("resource://gre/modules/ClientID.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "gUUIDGenerator",
"@mozilla.org/uuid-generator;1",
@ -24,6 +27,8 @@ this.TelemetryFeed = class TelemetryFeed {
}
async init() {
Services.obs.addObserver(this.browserOpenNewtabStart, "browser-open-newtab-start");
// TelemetrySender adds pref observers, so we initialize it after INIT
this.telemetrySender = new TelemetrySender();
@ -31,16 +36,55 @@ this.TelemetryFeed = class TelemetryFeed {
this.telemetryClientId = id;
}
browserOpenNewtabStart() {
perfService.mark("browser-open-newtab-start");
}
/**
* addSession - Start tracking a new session
*
* @param {string} id the portID of the open session
* @param {number} absVisChangeTime absolute timestamp of
* document.visibilityState becoming visible
*/
addSession(id) {
addSession(id, absVisChangeTime) {
// XXX note that there is a race condition here; we're assuming that no
// other tab will be interleaving calls to browserOpenNewtabStart and
// addSession on this object. For manually created windows, it's hard to
// imagine us hitting this race condition.
//
// However, for session restore, where multiple windows with multiple tabs
// might be restored much closer together in time, it's somewhat less hard,
// though it should still be pretty rare.
//
// The fix to this would be making all of the load-trigger notifications
// return some data with their notifications, and somehow propagate that
// data through closures into the tab itself so that we could match them
//
// As of this writing (very early days of system add-on perf telemetry),
// the hypothesis is that hitting this race should be so rare that makes
// more sense to live with the slight data inaccuracy that it would
// introduce, rather than doing the correct by complicated thing. It may
// well be worth reexamining this hypothesis after we have more experience
// with the data.
let absBrowserOpenTabStart =
perfService.getMostRecentAbsMarkStartByName("browser-open-newtab-start");
this.sessions.set(id, {
start_time: Components.utils.now(),
session_id: String(gUUIDGenerator.generateUUID()),
page: "about:newtab" // TODO: Handle about:home
page: "about:newtab", // TODO: Handle about:home here and in perf below
perf: {
load_trigger_ts: absBrowserOpenTabStart,
load_trigger_type: "menu_plus_or_keyboard",
visibility_event_rcvd_ts: absVisChangeTime
}
});
let duration = absVisChangeTime - absBrowserOpenTabStart;
this.store.dispatch({
type: at.TELEMETRY_PERFORMANCE_EVENT,
data: {visability_duration: duration}
});
}
@ -119,7 +163,8 @@ this.TelemetryFeed = class TelemetryFeed {
session_id: session.session_id,
page: session.page,
session_duration: session.session_duration,
action: "activity_stream_session"
action: "activity_stream_session",
perf: session.perf
}
);
}
@ -134,7 +179,8 @@ this.TelemetryFeed = class TelemetryFeed {
this.init();
break;
case at.NEW_TAB_VISIBLE:
this.addSession(au.getPortIdOfSender(action));
this.addSession(au.getPortIdOfSender(action),
action.data.absVisibilityChangeTime);
break;
case at.NEW_TAB_UNLOAD:
this.endSession(au.getPortIdOfSender(action));
@ -152,6 +198,9 @@ this.TelemetryFeed = class TelemetryFeed {
}
uninit() {
Services.obs.removeObserver(this.browserOpenNewtabStart,
"browser-open-newtab-start");
this.telemetrySender.uninit();
this.telemetrySender = null;
// TODO: Send any unfinished sessions

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

@ -6,7 +6,6 @@ const {interfaces: Ci, utils: Cu} = Components;
Cu.import("resource://gre/modules/Preferences.jsm");
Cu.importGlobalProperties(["fetch"]);
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Console.jsm"); // eslint-disable-line no-console
@ -15,9 +14,11 @@ Cu.import("resource://gre/modules/Console.jsm"); // eslint-disable-line no-conso
// installed. Though maybe we should just forcibly disable the old add-on?
const PREF_BRANCH = "browser.newtabpage.activity-stream.";
const ENDPOINT_PREF = "telemetry.ping.endpoint";
const TELEMETRY_PREF = "telemetry";
const LOGGING_PREF = "telemetry.log";
const ENDPOINT_PREF = `${PREF_BRANCH}telemetry.ping.endpoint`;
const TELEMETRY_PREF = `${PREF_BRANCH}telemetry`;
const LOGGING_PREF = `${PREF_BRANCH}telemetry.log`;
const FHR_UPLOAD_ENABLED_PREF = "datareporting.healthreport.uploadEnabled";
/**
* Observe various notifications and send them to a telemetry endpoint.
@ -27,10 +28,9 @@ const LOGGING_PREF = "telemetry.log";
* inside the Prefs constructor. Typically used from tests
* to save off a pointer to a fake Prefs instance so that
* stubs and spies can be inspected by the test code.
*
*/
function TelemetrySender(args) {
let prefArgs = {branch: PREF_BRANCH};
let prefArgs = {};
if (args) {
if ("prefInitHook" in args) {
prefArgs.initHook = args.prefInitHook;
@ -39,10 +39,14 @@ function TelemetrySender(args) {
this._prefs = new Preferences(prefArgs);
this.enabled = this._prefs.get(TELEMETRY_PREF);
this._enabled = this._prefs.get(TELEMETRY_PREF);
this._onTelemetryPrefChange = this._onTelemetryPrefChange.bind(this);
this._prefs.observe(TELEMETRY_PREF, this._onTelemetryPrefChange);
this._fhrEnabled = this._prefs.get(FHR_UPLOAD_ENABLED_PREF);
this._onFhrPrefChange = this._onFhrPrefChange.bind(this);
this._prefs.observe(FHR_UPLOAD_ENABLED_PREF, this._onFhrPrefChange);
this.logging = this._prefs.get(LOGGING_PREF);
this._onLoggingPrefChange = this._onLoggingPrefChange.bind(this);
this._prefs.observe(LOGGING_PREF, this._onLoggingPrefChange);
@ -51,13 +55,20 @@ function TelemetrySender(args) {
}
TelemetrySender.prototype = {
get enabled() {
return this._enabled && this._fhrEnabled;
},
_onLoggingPrefChange(prefVal) {
this.logging = prefVal;
},
_onTelemetryPrefChange(prefVal) {
this.enabled = prefVal;
this._enabled = prefVal;
},
_onFhrPrefChange(prefVal) {
this._fhrEnabled = prefVal;
},
async sendPing(data) {
@ -83,6 +94,7 @@ TelemetrySender.prototype = {
try {
this._prefs.ignore(TELEMETRY_PREF, this._onTelemetryPrefChange);
this._prefs.ignore(LOGGING_PREF, this._onLoggingPrefChange);
this._prefs.ignore(FHR_UPLOAD_ENABLED_PREF, this._onFhrPrefChange);
} catch (e) {
Cu.reportError(e);
}
@ -92,6 +104,7 @@ TelemetrySender.prototype = {
this.TelemetrySender = TelemetrySender;
this.TelemetrySenderConstants = {
ENDPOINT_PREF,
FHR_UPLOAD_ENABLED_PREF,
TELEMETRY_PREF,
LOGGING_PREF
};

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

@ -65,14 +65,39 @@ const SessionPing = Joi.object().keys(Object.assign({}, baseKeys, {
session_id: baseKeys.session_id.required(),
page: baseKeys.page.required(),
session_duration: Joi.number().integer().required(),
action: Joi.valid("activity_stream_session").required()
action: Joi.valid("activity_stream_session").required(),
perf: Joi.object().keys({
// Timestamp of the action perceived by the user to trigger the load
// of this page.
//
// Not required at least for the error cases where the
// observer event doesn't fire
load_trigger_ts: Joi.number().positive()
.notes(["server counter", "server counter alert"]),
// What was the perceived trigger of the load action?
//
// Not required at least for the error cases where the observer event
// doesn't fire
load_trigger_type: Joi.valid(["menu_plus_or_keyboard"])
.notes(["server counter", "server counter alert"]),
// When the page itself receives an event that document.visibilityState
// == visible.
//
// Not required at least for the (error?) case where the
// visibility_event doesn't fire. (It's not clear whether this
// can happen in practice, but if it does, we'd like to know about it).
visibility_event_rcvd_ts: Joi.number().positive()
.notes(["server counter", "server counter alert"])
}).required()
}));
function chaiAssertions(_chai, utils) {
const {Assertion} = _chai;
Assertion.addMethod("validate", function(schema, schemaName) {
const {error} = Joi.validate(this._obj, schema);
const {error} = Joi.validate(this._obj, schema, {allowUnknown: false});
this.assert(
!error,
`Expected to be ${schemaName ? `a valid ${schemaName}` : "valid"} but there were errors: ${error}`

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

@ -0,0 +1,84 @@
/* globals assert, beforeEach, describe, it */
const {_PerfService} = require("common/PerfService.jsm");
const {FakePerformance} = require("test/unit/utils.js");
let perfService;
describe("_PerfService", () => {
let sandbox;
let fakePerfObj;
beforeEach(() => {
sandbox = sinon.sandbox.create();
fakePerfObj = new FakePerformance();
perfService = new _PerfService({performanceObj: fakePerfObj});
});
afterEach(() => {
sandbox.restore();
});
describe("#getEntriesByName", () => {
it("should call getEntriesByName on the appropriate Window.performance",
() => {
sandbox.spy(fakePerfObj, "getEntriesByName");
perfService.getEntriesByName("monkey", "mark");
assert.calledOnce(fakePerfObj.getEntriesByName);
assert.calledWithExactly(fakePerfObj.getEntriesByName, "monkey", "mark");
});
it("should return entries with the given name", () => {
sandbox.spy(fakePerfObj, "getEntriesByName");
perfService.mark("monkey");
perfService.mark("dog");
let marks = perfService.getEntriesByName("monkey", "mark");
assert.isArray(marks);
assert.lengthOf(marks, 1);
assert.propertyVal(marks[0], "name", "monkey");
});
});
describe("#getMostRecentAbsMarkStartByName", () => {
it("should throw an error if there is no mark with the given name", () => {
function bogusGet() {
perfService.getMostRecentAbsMarkStartByName("rheeeet");
}
assert.throws(bogusGet, Error, /No marks with the name/);
});
it("should return the Number from the most recent mark with the given name + the time origin",
() => {
perfService.mark("dog");
perfService.mark("dog");
let absMarkStart = perfService.getMostRecentAbsMarkStartByName("dog");
// 2 because we want the result of the 2nd call to mark, and an instance
// of FakePerformance just returns the number of time mark has been
// called.
assert.equal(absMarkStart - perfService.timeOrigin, 2);
});
});
describe("#mark", () => {
it("should call the wrapped version of mark", () => {
sandbox.spy(fakePerfObj, "mark");
perfService.mark("monkey");
assert.calledOnce(fakePerfObj.mark);
assert.calledWithExactly(fakePerfObj.mark, "monkey");
});
});
describe("#timeOrigin", () => {
it("should get the origin of the wrapped performance object", () => {
assert.equal(perfService.timeOrigin, 10000); // fake origin from utils.js
});
});
});

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

@ -1,3 +1,5 @@
/* global Services */
const injector = require("inject!lib/TelemetryFeed.jsm");
const {GlobalOverrider} = require("test/unit/utils");
const {actionCreators: ac, actionTypes: at} = require("common/Actions.jsm");
@ -15,10 +17,18 @@ const FAKE_UUID = "{foo-123-foo}";
describe("TelemetryFeed", () => {
let globals;
let sandbox;
let store = {getState() { return {App: {version: "1.0.0", locale: "en-US"}}; }};
let store = {
dispatch() {},
getState() { return {App: {version: "1.0.0", locale: "en-US"}}; }
};
let instance;
class TelemetrySender {sendPing() {} uninit() {}}
const {TelemetryFeed} = injector({"lib/TelemetrySender.jsm": {TelemetrySender}});
class PerfService {getMostRecentAbsMarkStartByName() { return 1234; } mark() {}}
const perfService = new PerfService();
const {TelemetryFeed} = injector({
"lib/TelemetrySender.jsm": {TelemetrySender},
"common/PerfService.jsm": {perfService}
});
function addSession(id) {
instance.addSession(id);
@ -47,6 +57,15 @@ describe("TelemetryFeed", () => {
await instance.init();
assert.equal(instance.telemetryClientId, FAKE_TELEMETRY_ID);
});
it("should make this.browserOpenNewtabStart() observe browser-open-newtab-start", async () => {
sandbox.spy(Services.obs, "addObserver");
await instance.init();
assert.calledOnce(Services.obs.addObserver);
assert.calledWithExactly(Services.obs.addObserver,
instance.browserOpenNewtabStart, "browser-open-newtab-start");
});
});
describe("#addSession", () => {
it("should add a session", () => {
@ -70,6 +89,17 @@ describe("TelemetryFeed", () => {
assert.equal(session.page, "about:newtab"); // This is hardcoded for now.
});
});
describe("#browserOpenNewtabStart", () => {
it("should call perfService.mark with browser-open-newtab-start", () => {
sandbox.stub(perfService, "mark");
instance.browserOpenNewtabStart();
assert.calledOnce(perfService.mark);
assert.calledWithExactly(perfService.mark, "browser-open-newtab-start");
});
});
describe("#endSession", () => {
it("should not throw if there is no session for the given port ID", () => {
assert.doesNotThrow(() => instance.endSession("doesn't exist"));
@ -189,7 +219,12 @@ describe("TelemetryFeed", () => {
const ping = instance.createSessionEndEvent({
session_id: FAKE_UUID,
page: "about:newtab",
session_duration: 12345
session_duration: 12345,
perf: {
load_trigger_ts: 10,
load_trigger_type: "menu_plus_or_keyboard",
visibility_event_rcvd_ts: 20
}
});
// Is it valid?
assert.validate(ping, SessionPing);
@ -216,6 +251,17 @@ describe("TelemetryFeed", () => {
assert.calledOnce(stub);
assert.isNull(instance.telemetrySender);
});
it("should make this.browserOpenNewtabStart() stop observing browser-open-newtab-start", async () => {
await instance.init();
sandbox.spy(Services.obs, "removeObserver");
sandbox.stub(instance.telemetrySender, "uninit");
await instance.uninit();
assert.calledOnce(Services.obs.removeObserver);
assert.calledWithExactly(Services.obs.removeObserver,
instance.browserOpenNewtabStart, "browser-open-newtab-start");
});
});
describe("#onAction", () => {
it("should call .init() on an INIT action", () => {
@ -225,7 +271,10 @@ describe("TelemetryFeed", () => {
});
it("should call .addSession() on a NEW_TAB_VISIBLE action", () => {
const stub = sandbox.stub(instance, "addSession");
instance.onAction(ac.SendToMain({type: at.NEW_TAB_VISIBLE}, "port123"));
instance.onAction(ac.SendToMain({
type: at.NEW_TAB_VISIBLE,
data: {absVisibilityChangeTime: 789}
}, "port123"));
assert.calledWith(stub, "port123");
});
it("should call .endSession() on a NEW_TAB_UNLOAD action", () => {

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

@ -3,7 +3,8 @@
const {GlobalOverrider, FakePrefs} = require("test/unit/utils");
const {TelemetrySender, TelemetrySenderConstants} = require("lib/TelemetrySender.jsm");
const {ENDPOINT_PREF, TELEMETRY_PREF, LOGGING_PREF} = TelemetrySenderConstants;
const {ENDPOINT_PREF, FHR_UPLOAD_ENABLED_PREF, TELEMETRY_PREF, LOGGING_PREF} =
TelemetrySenderConstants;
/**
* A reference to the fake preferences object created by the TelemetrySender
@ -13,6 +14,7 @@ let fakePrefs;
const prefInitHook = function() {
fakePrefs = this; // eslint-disable-line consistent-this
};
const tsArgs = {prefInitHook};
describe("TelemetrySender", () => {
@ -48,34 +50,108 @@ describe("TelemetrySender", () => {
assert.calledOnce(global.Preferences);
});
it("should set the enabled prop to false if the pref is false", () => {
FakePrefs.prototype.prefs = {};
FakePrefs.prototype.prefs[TELEMETRY_PREF] = false;
describe("#enabled", () => {
let testParams = [
{enabledPref: true, fhrPref: true, result: true},
{enabledPref: false, fhrPref: true, result: false},
{enabledPref: true, fhrPref: false, result: false},
{enabledPref: false, fhrPref: false, result: false}
];
tSender = new TelemetrySender(tsArgs);
function testEnabled(p) {
FakePrefs.prototype.prefs[TELEMETRY_PREF] = p.enabledPref;
FakePrefs.prototype.prefs[FHR_UPLOAD_ENABLED_PREF] = p.fhrPref;
assert.isFalse(tSender.enabled);
});
tSender = new TelemetrySender(tsArgs);
it("should set the enabled prop to true if the pref is true", () => {
FakePrefs.prototype.prefs = {};
FakePrefs.prototype.prefs[TELEMETRY_PREF] = true;
assert.equal(tSender.enabled, p.result);
}
tSender = new TelemetrySender(tsArgs);
for (let p of testParams) {
it(`should return ${p.result} if the fhrPref is ${p.fhrPref} and telemetry.enabled is ${p.enabledPref}`, () => {
testEnabled(p);
});
}
assert.isTrue(tSender.enabled);
describe("telemetry.enabled pref changes from true to false", () => {
beforeEach(() => {
FakePrefs.prototype.prefs = {};
FakePrefs.prototype.prefs[TELEMETRY_PREF] = true;
FakePrefs.prototype.prefs[FHR_UPLOAD_ENABLED_PREF] = true;
tSender = new TelemetrySender(tsArgs);
assert.propertyVal(tSender, "enabled", true);
});
it("should set the enabled property to false", () => {
fakePrefs.set(TELEMETRY_PREF, false);
assert.propertyVal(tSender, "enabled", false);
});
});
describe("telemetry.enabled pref changes from false to true", () => {
beforeEach(() => {
FakePrefs.prototype.prefs = {};
FakePrefs.prototype.prefs[FHR_UPLOAD_ENABLED_PREF] = true;
FakePrefs.prototype.prefs[TELEMETRY_PREF] = false;
tSender = new TelemetrySender(tsArgs);
assert.propertyVal(tSender, "enabled", false);
});
it("should set the enabled property to true", () => {
fakePrefs.set(TELEMETRY_PREF, true);
assert.propertyVal(tSender, "enabled", true);
});
});
describe("FHR enabled pref changes from true to false", () => {
beforeEach(() => {
FakePrefs.prototype.prefs = {};
FakePrefs.prototype.prefs[TELEMETRY_PREF] = true;
FakePrefs.prototype.prefs[FHR_UPLOAD_ENABLED_PREF] = true;
tSender = new TelemetrySender(tsArgs);
assert.propertyVal(tSender, "enabled", true);
});
it("should set the enabled property to false", () => {
fakePrefs.set(FHR_UPLOAD_ENABLED_PREF, false);
assert.propertyVal(tSender, "enabled", false);
});
});
describe("FHR enabled pref changes from false to true", () => {
beforeEach(() => {
FakePrefs.prototype.prefs = {};
FakePrefs.prototype.prefs[FHR_UPLOAD_ENABLED_PREF] = false;
FakePrefs.prototype.prefs[TELEMETRY_PREF] = true;
tSender = new TelemetrySender(tsArgs);
assert.propertyVal(tSender, "enabled", false);
});
it("should set the enabled property to true", () => {
fakePrefs.set(FHR_UPLOAD_ENABLED_PREF, true);
assert.propertyVal(tSender, "enabled", true);
});
});
});
describe("#sendPing()", () => {
beforeEach(() => {
FakePrefs.prototype.prefs = {};
FakePrefs.prototype.prefs[FHR_UPLOAD_ENABLED_PREF] = true;
FakePrefs.prototype.prefs[TELEMETRY_PREF] = true;
FakePrefs.prototype.prefs[ENDPOINT_PREF] = fakeEndpointUrl;
tSender = new TelemetrySender(tsArgs);
});
it("should not send if the TelemetrySender is disabled", async () => {
tSender.enabled = false;
FakePrefs.prototype.prefs[TELEMETRY_PREF] = false;
tSender = new TelemetrySender(tsArgs);
await tSender.sendPing(fakePingJSON);
@ -132,6 +208,15 @@ describe("TelemetrySender", () => {
assert.notProperty(fakePrefs.observers, TELEMETRY_PREF);
});
it("should remove the fhrpref listener", () => {
tSender = new TelemetrySender(tsArgs);
assert.property(fakePrefs.observers, FHR_UPLOAD_ENABLED_PREF);
tSender.uninit();
assert.notProperty(fakePrefs.observers, FHR_UPLOAD_ENABLED_PREF);
});
it("should remove the telemetry log listener", () => {
tSender = new TelemetrySender(tsArgs);
assert.property(fakePrefs.observers, LOGGING_PREF);
@ -152,36 +237,6 @@ describe("TelemetrySender", () => {
});
describe("Misc pref changes", () => {
describe("telemetry changes from true to false", () => {
beforeEach(() => {
FakePrefs.prototype.prefs = {};
FakePrefs.prototype.prefs[TELEMETRY_PREF] = true;
tSender = new TelemetrySender(tsArgs);
assert.propertyVal(tSender, "enabled", true);
});
it("should set the enabled property to false", () => {
fakePrefs.set(TELEMETRY_PREF, false);
assert.propertyVal(tSender, "enabled", false);
});
});
describe("telemetry changes from false to true", () => {
beforeEach(() => {
FakePrefs.prototype.prefs = {};
FakePrefs.prototype.prefs[TELEMETRY_PREF] = false;
tSender = new TelemetrySender(tsArgs);
assert.propertyVal(tSender, "enabled", false);
});
it("should set the enabled property to true", () => {
fakePrefs.set(TELEMETRY_PREF, true);
assert.propertyVal(tSender, "enabled", true);
});
});
describe("performance.log changes from false to true", () => {
it("should change this.logging from false to true", () => {
FakePrefs.prototype.prefs = {};

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

@ -1,4 +1,4 @@
const {GlobalOverrider, FakePrefs} = require("test/unit/utils");
const {GlobalOverrider, FakePrefs, FakePerformance} = require("test/unit/utils");
const {chaiAssertions} = require("test/schemas/pings");
const req = require.context(".", true, /\.test\.jsx?$/);
@ -10,6 +10,7 @@ sinon.assert.expose(assert, {prefix: ""});
chai.use(chaiAssertions);
let overrider = new GlobalOverrider();
overrider.set({
Components: {
interfaces: {},
@ -31,6 +32,7 @@ overrider.set({
addMessageListener: (msg, cb) => cb(),
removeMessageListener() {}
},
appShell: {hiddenDOMWindow: {performance: new FakePerformance()}},
obs: {
addObserver() {},
removeObserver() {}

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

@ -116,6 +116,46 @@ FakePrefs.prototype = {
}
};
function FakePerformance() {}
FakePerformance.prototype = {
marks: new Map(),
now() {
return window.performance.now();
},
timing: {navigationStart: 222222},
get timeOrigin() {
return 10000;
},
// XXX assumes type == "mark"
getEntriesByName(name, type) {
if (this.marks.has(name)) {
return this.marks.get(name);
}
return [];
},
callsToMark: 0,
/**
* @note The "startTime" for each mark is simply the number of times mark
* has been called in this object.
*/
mark(name) {
let markObj = {
name,
"entryType": "mark",
"startTime": ++this.callsToMark,
"duration": 0
};
if (this.marks.has(name)) {
this.marks.get(name).push(markObj);
return;
}
this.marks.set(name, [markObj]);
}
};
/**
* addNumberReducer - a simple dummy reducer for testing that adds a number
*/
@ -142,6 +182,7 @@ function mountWithIntl(node) {
}
module.exports = {
FakePerformance,
FakePrefs,
GlobalOverrider,
addNumberReducer,

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

@ -130,9 +130,10 @@ function setCohort(cohortName) {
}
function watchForPrefChanges() {
Preferences.observe(PREF_FLASH_STATE, function() {
Preferences.observe(PREF_FLASH_STATE, function prefWatcher() {
let currentCohort = Preferences.get(PREF_COHORT_NAME, "unknown");
setCohort(`user-changed-from-${currentCohort}`);
Preferences.ignore(PREF_FLASH_STATE, prefWatcher);
});
}

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

@ -10,7 +10,7 @@
<Description about="urn:mozilla:install-manifest">
<em:id>clicktoplay-rollout@mozilla.org</em:id>
<em:version>1.1</em:version>
<em:version>1.2</em:version>
<em:type>2</em:type>
<em:bootstrap>true</em:bootstrap>
<em:multiprocessCompatible>true</em:multiprocessCompatible>

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

@ -11,7 +11,7 @@
<script src="chrome://formautofill/content/editProfile.js"></script>
</head>
<body>
<form>
<form autocomplete="off">
<label id="given-name-container">
<span>First Name</span>
<input id="given-name" type="text"/>

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

@ -111,6 +111,7 @@ webextPerms.description.privacy=Read and modify privacy settings
webextPerms.description.sessions=Access recently closed tabs
webextPerms.description.tabs=Access browser tabs
webextPerms.description.topSites=Access browsing history
webextPerms.description.unlimitedStorage=Store unlimited amount of client-side data
webextPerms.description.webNavigation=Access browser activity during navigation
webextPerms.hostDescription.allUrls=Access your data for all websites

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

@ -76,6 +76,10 @@ XPCOMUtils.defineLazyGetter(this, "DEFAULT_AREA_PLACEMENTS", function() {
],
};
if (AppConstants.MOZ_PHOTON_THEME) {
result["nav-bar"].push("sidebar-button");
}
if (gPhotonStructure) {
result["widget-overflow-fixed-list"] = [];
} else {

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

@ -105,8 +105,7 @@ photonpanelmultiview .panel-banner-item > .toolbarbutton-multiline-text {
margin: 0;
}
photonpanelmultiview .subviewbutton > .toolbarbutton-icon,
photonpanelmultiview .panel-banner-item > .toolbarbutton-multiline-text {
photonpanelmultiview .subviewbutton > .toolbarbutton-icon {
padding: 0;
}

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

@ -1261,8 +1261,13 @@ photonpanelmultiview .subviewbutton > .toolbarbutton-text {
photonpanelmultiview .subviewbutton-iconic:not(.subviewbutton-back) > .toolbarbutton-text,
photonpanelmultiview .cui-withicon > .toolbarbutton-text,
photonpanelmultiview .subviewbutton[image] > .toolbarbutton-text,
photonpanelmultiview .subviewbutton[checked="true"] > .toolbarbutton-text,
photonpanelmultiview .subviewbutton[checked="true"] > .toolbarbutton-text {
padding-inline-start: 8px; /* See '.subviewbutton-iconic > .toolbarbutton-text' rule above. */
}
photonpanelmultiview .panel-banner-item > .toolbarbutton-multiline-text {
font: menu;
padding: 0;
padding-inline-start: 8px; /* See '.subviewbutton-iconic > .toolbarbutton-text' rule above. */
}

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

@ -155,8 +155,7 @@ photonpanelmultiview .panel-banner-item > .toolbarbutton-multiline-text {
margin: 0;
}
photonpanelmultiview .subviewbutton > .toolbarbutton-icon,
photonpanelmultiview .panel-banner-item > .toolbarbutton-multiline-text {
photonpanelmultiview .subviewbutton > .toolbarbutton-icon {
padding: 0;
}

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

@ -219,7 +219,9 @@ Toolbox.prototype = {
set visibleAdditionalTools(tools) {
this._visibleAdditionalTools = tools;
this._combineAndSortPanelDefinitions();
if (this.isReady) {
this._combineAndSortPanelDefinitions();
}
},
/**
@ -1384,11 +1386,17 @@ Toolbox.prototype = {
throw new Error("Tool definition already registered: " +
definition.id);
}
this.additionalToolDefinitions.set(definition.id, definition);
this.visibleAdditionalTools = [...this.visibleAdditionalTools, definition.id];
this._combineAndSortPanelDefinitions();
this._buildPanelForTool(definition);
const buildPanel = () => this._buildPanelForTool(definition);
if (this.isReady) {
buildPanel();
} else {
this.once("ready", buildPanel);
}
},
/**

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

@ -0,0 +1,96 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
/**
* Redux middleware for debouncing actions.
*
* Schedules actions with { meta: { debounce: true } } to be delayed
* by wait milliseconds. If another action is fired during this
* time-frame both actions are inserted into a queue and delayed.
* Maximum delay is defined by maxWait argument.
*
* Handling more actions at once results in better performance since
* components need to be re-rendered less often.
*
* @param string wait Wait for specified amount of milliseconds
* before executing an action. The time is used
* to collect more actions and handle them all
* at once.
* @param string maxWait Max waiting time. It's used in case of
* a long stream of actions.
*/
function debounceActions(wait, maxWait) {
let queuedActions = [];
return store => next => {
let debounced = debounce(() => {
next(batchActions(queuedActions));
queuedActions = [];
}, wait, maxWait);
return action => {
if (!action.meta || !action.meta.debounce) {
return next(action);
}
if (!wait || !maxWait) {
return next(action);
}
if (action.type == BATCH_ACTIONS) {
queuedActions.push(...action.actions);
} else {
queuedActions.push(action);
}
return debounced();
};
};
}
function debounce(cb, wait, maxWait) {
let timeout, maxTimeout;
let doFunction = () => {
clearTimeout(timeout);
clearTimeout(maxTimeout);
timeout = maxTimeout = null;
cb();
};
return () => {
return new Promise(resolve => {
let onTimeout = () => {
doFunction();
resolve();
};
clearTimeout(timeout);
timeout = setTimeout(onTimeout, wait);
if (!maxTimeout) {
maxTimeout = setTimeout(onTimeout, maxWait);
}
});
};
}
const BATCH_ACTIONS = Symbol("BATCH_ACTIONS");
/**
* Action creator for action-batching.
*/
function batchActions(batchedActions, debounceFlag = true) {
return {
type: BATCH_ACTIONS,
meta: { debounce: debounceFlag },
actions: batchedActions,
};
}
module.exports = {
BATCH_ACTIONS,
batchActions,
debounceActions,
};

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

@ -5,6 +5,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DevToolsModules(
'debounce.js',
'history.js',
'log.js',
'promise.js',

5
devtools/client/shared/vendor/moz.build поставляемый
Просмотреть файл

@ -3,6 +3,11 @@
# 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/.
DIRS += [
'stringvalidator',
]
modules = []
modules += [
'immutable.js',

142
devtools/client/shared/vendor/stringvalidator/UPDATING.md поставляемый Normal file
Просмотреть файл

@ -0,0 +1,142 @@
# Updating this library
1. Replace the contents of validator.js with the contents of https://github.com/chriso/validator.js/blob/master/validator.js.
2. Add the following methods:
```
// see http://isrc.ifpi.org/en/isrc-standard/code-syntax
var isrc = /^[A-Z]{2}[0-9A-Z]{3}\d{2}\d{5}$/;
function isISRC(str) {
assertString(str);
return isrc.test(str);
}
```
```
var cultureCodes = new Set(["ar", "bg", "ca", "zh-Hans", "cs", "da", "de",
"el", "en", "es", "fi", "fr", "he", "hu", "is", "it", "ja", "ko", "nl", "no",
"pl", "pt", "rm", "ro", "ru", "hr", "sk", "sq", "sv", "th", "tr", "ur", "id",
"uk", "be", "sl", "et", "lv", "lt", "tg", "fa", "vi", "hy", "az", "eu", "hsb",
"mk", "tn", "xh", "zu", "af", "ka", "fo", "hi", "mt", "se", "ga", "ms", "kk",
"ky", "sw", "tk", "uz", "tt", "bn", "pa", "gu", "or", "ta", "te", "kn", "ml",
"as", "mr", "sa", "mn", "bo", "cy", "km", "lo", "gl", "kok", "syr", "si", "iu",
"am", "tzm", "ne", "fy", "ps", "fil", "dv", "ha", "yo", "quz", "nso", "ba", "lb",
"kl", "ig", "ii", "arn", "moh", "br", "ug", "mi", "oc", "co", "gsw", "sah",
"qut", "rw", "wo", "prs", "gd", "ar-SA", "bg-BG", "ca-ES", "zh-TW", "cs-CZ",
"da-DK", "de-DE", "el-GR", "en-US", "fi-FI", "fr-FR", "he-IL", "hu-HU", "is-IS",
"it-IT", "ja-JP", "ko-KR", "nl-NL", "nb-NO", "pl-PL", "pt-BR", "rm-CH", "ro-RO",
"ru-RU", "hr-HR", "sk-SK", "sq-AL", "sv-SE", "th-TH", "tr-TR", "ur-PK", "id-ID",
"uk-UA", "be-BY", "sl-SI", "et-EE", "lv-LV", "lt-LT", "tg-Cyrl-TJ", "fa-IR",
"vi-VN", "hy-AM", "az-Latn-AZ", "eu-ES", "hsb-DE", "mk-MK", "tn-ZA", "xh-ZA",
"zu-ZA", "af-ZA", "ka-GE", "fo-FO", "hi-IN", "mt-MT", "se-NO", "ms-MY", "kk-KZ",
"ky-KG", "sw-KE", "tk-TM", "uz-Latn-UZ", "tt-RU", "bn-IN", "pa-IN", "gu-IN",
"or-IN", "ta-IN", "te-IN", "kn-IN", "ml-IN", "as-IN", "mr-IN", "sa-IN", "mn-MN",
"bo-CN", "cy-GB", "km-KH", "lo-LA", "gl-ES", "kok-IN", "syr-SY", "si-LK",
"iu-Cans-CA", "am-ET", "ne-NP", "fy-NL", "ps-AF", "fil-PH", "dv-MV",
"ha-Latn-NG", "yo-NG", "quz-BO", "nso-ZA", "ba-RU", "lb-LU", "kl-GL", "ig-NG",
"ii-CN", "arn-CL", "moh-CA", "br-FR", "ug-CN", "mi-NZ", "oc-FR", "co-FR",
"gsw-FR", "sah-RU", "qut-GT", "rw-RW", "wo-SN", "prs-AF", "gd-GB", "ar-IQ",
"zh-CN", "de-CH", "en-GB", "es-MX", "fr-BE", "it-CH", "nl-BE", "nn-NO", "pt-PT",
"sr-Latn-CS", "sv-FI", "az-Cyrl-AZ", "dsb-DE", "se-SE", "ga-IE", "ms-BN",
"uz-Cyrl-UZ", "bn-BD", "mn-Mong-CN", "iu-Latn-CA", "tzm-Latn-DZ", "quz-EC",
"ar-EG", "zh-HK", "de-AT", "en-AU", "es-ES", "fr-CA", "sr-Cyrl-CS", "se-FI",
"quz-PE", "ar-LY", "zh-SG", "de-LU", "en-CA", "es-GT", "fr-CH", "hr-BA",
"smj-NO", "ar-DZ", "zh-MO", "de-LI", "en-NZ", "es-CR", "fr-LU", "bs-Latn-BA",
"smj-SE", "ar-MA", "en-IE", "es-PA", "fr-MC", "sr-Latn-BA", "sma-NO", "ar-TN",
"en-ZA", "es-DO", "sr-Cyrl-BA", "sma-SE", "ar-OM", "en-JM", "es-VE",
"bs-Cyrl-BA", "sms-FI", "ar-YE", "en-029", "es-CO", "sr-Latn-RS", "smn-FI",
"ar-SY", "en-BZ", "es-PE", "sr-Cyrl-RS", "ar-JO", "en-TT", "es-AR", "sr-Latn-ME",
"ar-LB", "en-ZW", "es-EC", "sr-Cyrl-ME", "ar-KW", "en-PH", "es-CL", "ar-AE",
"es-UY", "ar-BH", "es-PY", "ar-QA", "en-IN", "es-BO", "en-MY", "es-SV", "en-SG",
"es-HN", "es-NI", "es-PR", "es-US", "bs-Cyrl", "bs-Latn", "sr-Cyrl", "sr-Latn",
"smn", "az-Cyrl", "sms", "zh", "nn", "bs", "az-Latn", "sma", "uz-Cyrl",
"mn-Cyrl", "iu-Cans", "zh-Hant", "nb", "sr", "tg-Cyrl", "dsb", "smj", "uz-Latn",
"mn-Mong", "iu-Latn", "tzm-Latn", "ha-Latn", "zh-CHS", "zh-CHT"]);
function isRFC5646(str) {
assertString(str);
// According to the spec these codes are case sensitive so we can check the
// string directly.
return cultureCodes.has(str);
}
```
```
var semver = /^v?(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(-(0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(\.(0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*)?(\+[0-9a-zA-Z-]+(\.[0-9a-zA-Z-]+)*)?$/i
function isSemVer(str) {
assertString(str);
return semver.test(str);
}
```
```
var rgbcolor = /^rgb?\(\s*(0|[1-9]\d?|1\d\d?|2[0-4]\d|25[0-5])\s*,\s*(0|[1-9]\d?|1\d\d?|2[0-4]\d|25[0-5])\s*,\s*(0|[1-9]\d?|1\d\d?|2[0-4]\d|25[0-5])\s*\)$/i
function isRGBColor(str) {
assertString(str);
return rgbcolor.test(str);
}
```
3. Add the following to the validator object towards the end of the file:
```
isISRC: isISRC,
isRFC5646: isRFC5646,
isSemVer: isSemVer,
isRGBColor: isRGBColor,
```
4. Look for the phones array just above the isMobilePhone() method.
1. Replace the en-HK regex with:
```
// According to http://www.ofca.gov.hk/filemanager/ofca/en/content_311/no_plan.pdf
'en-HK': /^(\+?852-?)?((4(04[01]|06\d|09[3-9]|20\d|2[2-9]\d|3[3-9]\d|[467]\d{2}|5[1-9]\d|81\d|82[1-9]|8[69]\d|92[3-9]|95[2-9]|98\d)|5([1-79]\d{2})|6(0[1-9]\d|[1-9]\d{2})|7(0[1-9]\d|10[4-79]|11[458]|1[24578]\d|13[24-9]|16[0-8]|19[24579]|21[02-79]|2[456]\d|27[13-6]|3[456]\d|37[4578]|39[0146])|8(1[58]\d|2[45]\d|267|27[5-9]|2[89]\d|3[15-9]\d|32[5-8]|[46-9]\d{2}|5[013-9]\d)|9(0[1-9]\d|1[02-9]\d|[2-8]\d{2}))-?\d{4}|7130-?[0124-8]\d{3}|8167-?2\d{3})$/,
```
2. Add:
```
'ko-KR': /^((\+?82)[ \-]?)?0?1([0|1|6|7|8|9]{1})[ \-]?\d{3,4}[ \-]?\d{4}$/,
'lt-LT': /^(\+370|8)\d{8}$/,
```
5. Replace the isMobilePhone() method with:
```
function isMobilePhone(str, locale) {
assertString(str);
if (locale in phones) {
return phones[locale].test(str);
} else if (locale === 'any') {
return !!Object.values(phones).find(phone => phone.test(str));
}
return false;
}
```
6. Delete the notBase64 regex and replace the isBase64 with:
```
function isBase64(str) {
assertString(str);
// Value length must be divisible by 4.
var len = str.length;
if (!len || len % 4 !== 0) {
return false;
}
try {
if (atob(str)) {
return true;
}
} catch (e) {
return false;
}
}
```
7. Do not replace the test files as they have been converted to xpcshell tests. If there are new methods then add their tests to the `test_sanitizers.js` or `test_validators.js` files as appropriate.
8. To test the library please run the following:
```
./mach xpcshell-test devtools/client/shared/vendor/stringvalidator/
```

15
devtools/client/shared/vendor/stringvalidator/moz.build поставляемый Normal file
Просмотреть файл

@ -0,0 +1,15 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
DIRS += [
'util'
]
XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini']
DevToolsModules(
'validator.js',
)

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

@ -0,0 +1,20 @@
"use strict";
var Cc = Components.classes;
var Ci = Components.interfaces;
var Cu = Components.utils;
var Cr = Components.results;
const { require } = Cu.import("resource://devtools/shared/Loader.jsm", {});
const { console } = Cu.import("resource://gre/modules/Console.jsm", {});
this.validator = require("devtools/client/shared/vendor/stringvalidator/validator");
function describe(suite, testFunc) {
do_print(`\n Test suite: ${suite}`.toUpperCase());
testFunc();
}
function it(description, testFunc) {
do_print(`\n - ${description}:\n`.toUpperCase());
testFunc();
}

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

@ -0,0 +1,420 @@
/* -*- Mode: js; tab-width: 2; indent-tabs-mode: nil; js-indent-level: 2; fill-column: 80 -*- */
/*
* Copyright 2013 Mozilla Foundation and contributors
* Licensed under the New BSD license. See LICENSE.md or:
* http://opensource.org/licenses/BSD-2-Clause
*/
"use strict";
function test(options) {
var args = options.args || [];
args.unshift(null);
Object.keys(options.expect).forEach(function (input) {
args[0] = input;
var result = validator[options.sanitizer](...args);
var expected = options.expect[input];
let argsString = args.join(', ');
if (isNaN(result) && !result.length && isNaN(expected)) {
ok(true, `validator.${options.sanitizer}(${argsString}) returned "${result}"`);
} else {
equal(result, expected, `validator.${options.sanitizer}("${argsString}") ` +
`returned "${result}"`);
}
});
}
function run_test() {
describe('Sanitizers', function () {
it('should sanitize boolean strings', function () {
test({
sanitizer: 'toBoolean',
expect: {
'0': false,
'': false,
'1': true,
'true': true,
'foobar': true,
' ': true,
},
});
test({
sanitizer: 'toBoolean',
args: [true], // strict
expect: {
'0': false,
'': false,
'1': true,
'true': true,
'foobar': false,
' ': false,
},
});
});
it('should trim whitespace', function () {
test({
sanitizer: 'trim',
expect: {
' \r\n\tfoo \r\n\t ': 'foo',
' \r': '',
},
});
test({
sanitizer: 'ltrim',
expect: {
' \r\n\tfoo \r\n\t ': 'foo \r\n\t ',
' \t \n': '',
},
});
test({
sanitizer: 'rtrim',
expect: {
' \r\n\tfoo \r\n\t ': ' \r\n\tfoo',
' \r\n \t': '',
},
});
});
it('should trim custom characters', function () {
test({
sanitizer: 'trim',
args: ['01'],
expect: { '010100201000': '2' },
});
test({
sanitizer: 'ltrim',
args: ['01'],
expect: { '010100201000': '201000' },
});
test({
sanitizer: 'rtrim',
args: ['01'],
expect: { '010100201000': '0101002' },
});
});
it('should convert strings to integers', function () {
test({
sanitizer: 'toInt',
expect: {
'3': 3,
' 3 ': 3,
'2.4': 2,
'foo': NaN,
},
});
test({
sanitizer: 'toInt',
args: [16],
expect: { 'ff': 255 },
});
});
it('should convert strings to floats', function () {
test({
sanitizer: 'toFloat',
expect: {
'2': 2.0,
'2.': 2.0,
'-2.5': -2.5,
'.5': 0.5,
'foo': NaN,
},
});
});
it('should escape HTML', function () {
test({
sanitizer: 'escape',
expect: {
'<script> alert("xss&fun"); </script>':
'&lt;script&gt; alert(&quot;xss&amp;fun&quot;); &lt;&#x2F;script&gt;',
"<script> alert('xss&fun'); </script>":
'&lt;script&gt; alert(&#x27;xss&amp;fun&#x27;); &lt;&#x2F;script&gt;',
'Backtick: `':
'Backtick: &#96;',
'Backslash: \\':
'Backslash: &#x5C;',
},
});
});
it('should unescape HTML', function () {
test({
sanitizer: 'unescape',
expect: {
'&lt;script&gt; alert(&quot;xss&amp;fun&quot;); &lt;&#x2F;script&gt;':
'<script> alert("xss&fun"); </script>',
'&lt;script&gt; alert(&#x27;xss&amp;fun&#x27;); &lt;&#x2F;script&gt;':
"<script> alert('xss&fun'); </script>",
'Backtick: &#96;':
'Backtick: `',
},
});
});
it('should remove control characters (<32 and 127)', function () {
// Check basic functionality
test({
sanitizer: 'stripLow',
expect: {
'foo\x00': 'foo',
'\x7Ffoo\x02': 'foo',
'\x01\x09': '',
'foo\x0A\x0D': 'foo',
},
});
// Unicode safety
test({
sanitizer: 'stripLow',
expect: {
'perch\u00e9': 'perch\u00e9',
'\u20ac': '\u20ac',
'\u2206\x0A': '\u2206',
'\ud83d\ude04': '\ud83d\ude04',
},
});
// Preserve newlines
test({
sanitizer: 'stripLow',
args: [true], // keep_new_lines
expect: {
'foo\x0A\x0D': 'foo\x0A\x0D',
'\x03foo\x0A\x0D': 'foo\x0A\x0D',
},
});
});
it('should sanitize a string based on a whitelist', function () {
test({
sanitizer: 'whitelist',
args: ['abc'],
expect: {
'abcdef': 'abc',
'aaaaaaaaaabbbbbbbbbb': 'aaaaaaaaaabbbbbbbbbb',
'a1b2c3': 'abc',
' ': '',
},
});
});
it('should sanitize a string based on a blacklist', function () {
test({
sanitizer: 'blacklist',
args: ['abc'],
expect: {
'abcdef': 'def',
'aaaaaaaaaabbbbbbbbbb': '',
'a1b2c3': '123',
' ': ' ',
},
});
});
it('should normalize an email based on domain', function () {
test({
sanitizer: 'normalizeEmail',
expect: {
'test@me.com': 'test@me.com',
'some.name@gmail.com': 'somename@gmail.com',
'some.name@googleMail.com': 'somename@gmail.com',
'some.name+extension@gmail.com': 'somename@gmail.com',
'some.Name+extension@GoogleMail.com': 'somename@gmail.com',
'some.name.middleName+extension@gmail.com': 'somenamemiddlename@gmail.com',
'some.name.middleName+extension@GoogleMail.com': 'somenamemiddlename@gmail.com',
'some.name.midd.leNa.me.+extension@gmail.com': 'somenamemiddlename@gmail.com',
'some.name.midd.leNa.me.+extension@GoogleMail.com': 'somenamemiddlename@gmail.com',
'some.name+extension@unknown.com': 'some.name+extension@unknown.com',
'hans@m端ller.com': 'hans@m端ller.com',
'an invalid email address': false,
'': false,
'+extension@gmail.com': false,
'...@gmail.com': false,
'.+extension@googlemail.com': false,
'+a@icloud.com': false,
'+a@outlook.com': false,
'-a@yahoo.com': false,
'some.name.midd..leNa...me...+extension@GoogleMail.com': 'somenamemiddlename@gmail.com',
'"foo@bar"@baz.com': '"foo@bar"@baz.com',
},
});
// Testing all_lowercase switch, should apply to domains not known to be case-insensitive
test({
sanitizer: 'normalizeEmail',
args: [{ all_lowercase: false }],
expect: {
'test@foo.com': 'test@foo.com',
'hans@m端ller.com': 'hans@m端ller.com',
'test@FOO.COM': 'test@foo.com', // Hostname is always lowercased
'blAH@x.com': 'blAH@x.com',
// In case of domains that are known to be case-insensitive, there's a separate switch
'TEST@me.com': 'test@me.com',
'TEST@ME.COM': 'test@me.com',
'SOME.name@GMAIL.com': 'somename@gmail.com',
'SOME.name.middleName+extension@GoogleMail.com': 'somenamemiddlename@gmail.com',
'SOME.name.midd.leNa.me.+extension@gmail.com': 'somenamemiddlename@gmail.com',
'SOME.name@gmail.com': 'somename@gmail.com',
'SOME.name@yahoo.ca': 'some.name@yahoo.ca',
'SOME.name@outlook.ie': 'some.name@outlook.ie',
'SOME.name@me.com': 'some.name@me.com',
},
});
// Testing *_lowercase
test({
sanitizer: 'normalizeEmail',
args: [{
all_lowercase: false,
gmail_lowercase: false,
icloud_lowercase: false,
outlookdotcom_lowercase: false,
yahoo_lowercase: false,
}],
expect: {
'TEST@FOO.COM': 'TEST@foo.com', // all_lowercase
'ME@gMAil.com': 'ME@gmail.com', // gmail_lowercase
'ME@me.COM': 'ME@me.com', // icloud_lowercase
'ME@icloud.COM': 'ME@icloud.com', // icloud_lowercase
'ME@outlook.COM': 'ME@outlook.com', // outlookdotcom_lowercase
'JOHN@live.CA': 'JOHN@live.ca', // outlookdotcom_lowercase
'ME@ymail.COM': 'ME@ymail.com', // yahoo_lowercase
},
});
// Testing all_lowercase
// Should overwrite all the *_lowercase options
test({
sanitizer: 'normalizeEmail',
args: [{
all_lowercase: true,
gmail_lowercase: false, // Overruled
icloud_lowercase: false, // Overruled
outlookdotcom_lowercase: false, // Overruled
yahoo_lowercase: false, // Overruled
}],
expect: {
'TEST@FOO.COM': 'test@foo.com', // all_lowercase
'ME@gMAil.com': 'me@gmail.com', // gmail_lowercase
'ME@me.COM': 'me@me.com', // icloud_lowercase
'ME@icloud.COM': 'me@icloud.com', // icloud_lowercase
'ME@outlook.COM': 'me@outlook.com', // outlookdotcom_lowercase
'JOHN@live.CA': 'john@live.ca', // outlookdotcom_lowercase
'ME@ymail.COM': 'me@ymail.com', // yahoo_lowercase
},
});
// Testing *_remove_dots
test({
sanitizer: 'normalizeEmail',
args: [{
gmail_remove_dots: false,
}],
expect: {
'SOME.name@GMAIL.com': 'some.name@gmail.com',
'SOME.name+me@GMAIL.com': 'some.name@gmail.com',
'my.self@foo.com': 'my.self@foo.com',
},
});
test({
sanitizer: 'normalizeEmail',
args: [{
gmail_remove_dots: true,
}],
expect: {
'SOME.name@GMAIL.com': 'somename@gmail.com',
'SOME.name+me@GMAIL.com': 'somename@gmail.com',
'my.self@foo.com': 'my.self@foo.com',
},
});
// Testing *_remove_subaddress
test({
sanitizer: 'normalizeEmail',
args: [{
gmail_remove_subaddress: false,
icloud_remove_subaddress: false,
outlookdotcom_remove_subaddress: false,
yahoo_remove_subaddress: false, // Note Yahoo uses "-"
}],
expect: {
'foo+bar@unknown.com': 'foo+bar@unknown.com',
'foo+bar@gmail.com': 'foo+bar@gmail.com', // gmail_remove_subaddress
'foo+bar@me.com': 'foo+bar@me.com', // icloud_remove_subaddress
'foo+bar@icloud.com': 'foo+bar@icloud.com', // icloud_remove_subaddress
'foo+bar@live.fr': 'foo+bar@live.fr', // outlookdotcom_remove_subaddress
'foo+bar@hotmail.co.uk': 'foo+bar@hotmail.co.uk', // outlookdotcom_remove_subaddress
'foo-bar@yahoo.com': 'foo-bar@yahoo.com', // yahoo_remove_subaddress
'foo+bar@yahoo.com': 'foo+bar@yahoo.com', // yahoo_remove_subaddress
},
});
test({
sanitizer: 'normalizeEmail',
args: [{
gmail_remove_subaddress: true,
icloud_remove_subaddress: true,
outlookdotcom_remove_subaddress: true,
yahoo_remove_subaddress: true, // Note Yahoo uses "-"
}],
expect: {
'foo+bar@unknown.com': 'foo+bar@unknown.com',
'foo+bar@gmail.com': 'foo@gmail.com', // gmail_remove_subaddress
'foo+bar@me.com': 'foo@me.com', // icloud_remove_subaddress
'foo+bar@icloud.com': 'foo@icloud.com', // icloud_remove_subaddress
'foo+bar@live.fr': 'foo@live.fr', // outlookdotcom_remove_subaddress
'foo+bar@hotmail.co.uk': 'foo@hotmail.co.uk', // outlookdotcom_remove_subaddress
'foo-bar@yahoo.com': 'foo@yahoo.com', // yahoo_remove_subaddress
'foo+bar@yahoo.com': 'foo+bar@yahoo.com', // yahoo_remove_subaddress
},
});
// Testing gmail_convert_googlemaildotcom
test({
sanitizer: 'normalizeEmail',
args: [{
gmail_convert_googlemaildotcom: false,
}],
expect: {
'SOME.name@GMAIL.com': 'somename@gmail.com',
'SOME.name+me@GMAIL.com': 'somename@gmail.com',
'SOME.name+me@googlemail.com': 'somename@googlemail.com',
'SOME.name+me@googlemail.COM': 'somename@googlemail.com',
'SOME.name+me@googlEmail.com': 'somename@googlemail.com',
'my.self@foo.com': 'my.self@foo.com',
},
});
test({
sanitizer: 'normalizeEmail',
args: [{
gmail_convert_googlemaildotcom: true,
}],
expect: {
'SOME.name@GMAIL.com': 'somename@gmail.com',
'SOME.name+me@GMAIL.com': 'somename@gmail.com',
'SOME.name+me@googlemail.com': 'somename@gmail.com',
'SOME.name+me@googlemail.COM': 'somename@gmail.com',
'SOME.name+me@googlEmail.com': 'somename@gmail.com',
'my.self@foo.com': 'my.self@foo.com',
},
});
});
});
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -0,0 +1,8 @@
[DEFAULT]
tags = devtools
head = head_stringvalidator.js
firefox-appdir = browser
skip-if = toolkit == 'android'
[test_sanitizers.js]
[test_validators.js]

215
devtools/client/shared/vendor/stringvalidator/util/assert.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,215 @@
// // based on node assert, original notice:
// // NB: The URL to the CommonJS spec is kept just for tradition.
// // node-assert has evolved a lot since then, both in API and behavior.
//
// // http://wiki.commonjs.org/wiki/Unit_Testing/1.0
// //
// // THIS IS NOT TESTED NOR LIKELY TO WORK OUTSIDE V8!
// //
// // Originally from narwhal.js (http://narwhaljs.org)
// // Copyright (c) 2009 Thomas Robinson <280north.com>
// //
// // Permission is hereby granted, free of charge, to any person obtaining a copy
// // of this software and associated documentation files (the 'Software'), to
// // deal in the Software without restriction, including without limitation the
// // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// // sell copies of the Software, and to permit persons to whom the Software is
// // furnished to do so, subject to the following conditions:
// //
// // The above copyright notice and this permission notice shall be included in
// // all copies or substantial portions of the Software.
// //
// // THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// // AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
"use strict";
var regex = /\s*function\s+([^\(\s]*)\s*/;
var functionsHaveNames = (function () {
return function foo() {}.name === "foo";
}());
function assert(value, message) {
if (!value) {
fail(value, true, message, "==", assert.ok);
}
}
assert.equal = function equal(actual, expected, message) {
if (actual != expected) {
fail(actual, expected, message, "==", assert.equal);
}
};
assert.throws = function (block, error, message) {
_throws(true, block, error, message);
};
function _throws(shouldThrow, block, expected, message) {
var actual;
if (typeof block !== "function") {
throw new TypeError(`"block" argument must be a function`);
}
if (typeof expected === "string") {
message = expected;
expected = null;
}
actual = _tryBlock(block);
message = (expected && expected.name ? " (" + expected.name + ")." : ".") +
(message ? " " + message : ".");
if (shouldThrow && !actual) {
fail(actual, expected, "Missing expected exception" + message);
}
var userProvidedMessage = typeof message === "string";
var isUnwantedException = !shouldThrow && isError(actual);
var isUnexpectedException = !shouldThrow && actual && !expected;
if ((isUnwantedException &&
userProvidedMessage &&
expectedException(actual, expected)) ||
isUnexpectedException) {
fail(actual, expected, "Got unwanted exception" + message);
}
if ((shouldThrow && actual && expected &&
!expectedException(actual, expected)) || (!shouldThrow && actual)) {
throw actual;
}
}
function fail(actual, expected, message, operator, stackStartFunction) {
throw new assert.AssertionError({
message: message,
actual: actual,
expected: expected,
operator: operator,
stackStartFunction: stackStartFunction
});
}
assert.fail = fail;
assert.AssertionError = function AssertionError(options) {
this.name = "AssertionError";
this.actual = options.actual;
this.expected = options.expected;
this.operator = options.operator;
if (options.message) {
this.message = options.message;
this.generatedMessage = false;
} else {
this.message = getMessage(this);
this.generatedMessage = true;
}
var stackStartFunction = options.stackStartFunction || fail;
if (Error.captureStackTrace) {
Error.captureStackTrace(this, stackStartFunction);
} else {
// non v8 browsers so we can have a stacktrace
var err = new Error();
if (err.stack) {
var out = err.stack;
// try to strip useless frames
var fn_name = getName(stackStartFunction);
var idx = out.indexOf("\n" + fn_name);
if (idx >= 0) {
// once we have located the function frame
// we need to strip out everything before it (and its line)
var next_line = out.indexOf("\n", idx + 1);
out = out.substring(next_line + 1);
}
this.stack = out;
}
}
};
function expectedException(actual, expected) {
if (!actual || !expected) {
return false;
}
if (Object.prototype.toString.call(expected) == "[object RegExp]") {
return expected.test(actual);
}
try {
if (actual instanceof expected) {
return true;
}
} catch (e) {
// Ignore. The instanceof check doesn"t work for arrow functions.
}
if (Error.isPrototypeOf(expected)) {
return false;
}
return expected.call({}, actual) === true;
}
function _tryBlock(block) {
var error;
try {
block();
} catch (e) {
error = e;
}
return error;
}
function isError(obj) {
return obj instanceof Error;
}
function isFunction(value) {
return typeof value === "function";
}
function getMessage(self) {
return truncate(inspect(self.actual), 128) + " " +
self.operator + " " +
truncate(inspect(self.expected), 128);
}
function getName(func) {
if (!isFunction(func)) {
return null;
}
if (functionsHaveNames) {
return func.name;
}
var str = func.toString();
var match = str.match(regex);
return match && match[1];
}
function truncate(s, n) {
if (typeof s === "string") {
return s.length < n ? s : s.slice(0, n);
}
return s;
}
function inspect(something) {
if (functionsHaveNames || !isFunction(something)) {
throw new Error(something);
}
var rawname = getName(something);
var name = rawname ? ": " + rawname : "";
return "[Function" + name + "]";
}
exports.assert = assert;

9
devtools/client/shared/vendor/stringvalidator/util/moz.build поставляемый Normal file
Просмотреть файл

@ -0,0 +1,9 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
DevToolsModules(
'assert.js',
)

1489
devtools/client/shared/vendor/stringvalidator/validator.js поставляемый Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -1,20 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=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/. */
"use strict";
const { BATCH_ACTIONS } = require("../constants");
function batchActions(batchedActions) {
return {
type: BATCH_ACTIONS,
actions: batchedActions,
};
}
module.exports = {
batchActions
};

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

@ -7,7 +7,6 @@
"use strict";
const actionModules = [
require("./enhancers"),
require("./filters"),
require("./messages"),
require("./ui"),

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

@ -10,7 +10,7 @@ const {
prepareMessage
} = require("devtools/client/webconsole/new-console-output/utils/messages");
const { IdGenerator } = require("devtools/client/webconsole/new-console-output/utils/id-generator");
const { batchActions } = require("devtools/client/webconsole/new-console-output/actions/enhancers");
const { batchActions } = require("devtools/client/shared/redux/middleware/debounce");
const {
MESSAGE_ADD,
NETWORK_MESSAGE_UPDATE,

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

@ -4,7 +4,6 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DevToolsModules(
'enhancers.js',
'filters.js',
'index.js',
'messages.js',

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

@ -12,6 +12,7 @@ const {
const { connect } = require("devtools/client/shared/vendor/react-redux");
const {
getAllMessagesById,
getAllMessagesUiById,
getAllMessagesTableDataById,
getAllNetworkMessagesUpdateById,
@ -25,6 +26,7 @@ const ConsoleOutput = createClass({
displayName: "ConsoleOutput",
propTypes: {
messages: PropTypes.object.isRequired,
messagesUi: PropTypes.object.isRequired,
serviceContainer: PropTypes.shape({
attachRefToHud: PropTypes.func.isRequired,
@ -77,6 +79,7 @@ const ConsoleOutput = createClass({
let {
dispatch,
visibleMessages,
messages,
messagesUi,
messagesTableData,
messagesRepeat,
@ -85,22 +88,17 @@ const ConsoleOutput = createClass({
timestampsVisible,
} = this.props;
let messageNodes = visibleMessages.map((message) => {
return (
MessageContainer({
dispatch,
message,
key: message.id,
serviceContainer,
open: messagesUi.includes(message.id),
tableData: messagesTableData.get(message.id),
indent: message.indent,
timestampsVisible,
repeat: messagesRepeat[message.id],
networkMessageUpdate: networkMessagesUpdate[message.id],
})
);
});
let messageNodes = visibleMessages.map((messageId) => MessageContainer({
dispatch,
key: messageId,
serviceContainer,
open: messagesUi.includes(messageId),
tableData: messagesTableData.get(messageId),
timestampsVisible,
repeat: messagesRepeat[messageId],
networkMessageUpdate: networkMessagesUpdate[messageId],
getMessage: () => messages.get(messageId)
}));
return (
dom.div({
@ -128,6 +126,7 @@ function isScrolledToBottom(outputNode, scrollNode) {
function mapStateToProps(state, props) {
return {
messages: getAllMessagesById(state),
visibleMessages: getVisibleMessages(state),
messagesUi: getAllMessagesUiById(state),
messagesTableData: getAllMessagesTableDataById(state),

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

@ -9,7 +9,6 @@
// React & Redux
const {
createClass,
PropTypes
} = require("devtools/client/shared/vendor/react");
@ -31,20 +30,18 @@ const MessageContainer = createClass({
displayName: "MessageContainer",
propTypes: {
message: PropTypes.object.isRequired,
open: PropTypes.bool.isRequired,
serviceContainer: PropTypes.object.isRequired,
indent: PropTypes.number.isRequired,
tableData: PropTypes.object,
timestampsVisible: PropTypes.bool.isRequired,
repeat: PropTypes.number,
networkMessageUpdate: PropTypes.object,
getMessage: PropTypes.func.isRequired,
},
getDefaultProps: function () {
return {
open: false,
indent: 0,
};
},
@ -52,8 +49,6 @@ const MessageContainer = createClass({
const repeatChanged = this.props.repeat !== nextProps.repeat;
const openChanged = this.props.open !== nextProps.open;
const tableDataChanged = this.props.tableData !== nextProps.tableData;
const responseChanged = this.props.message.response !== nextProps.message.response;
const totalTimeChanged = this.props.message.totalTime !== nextProps.message.totalTime;
const timestampVisibleChanged =
this.props.timestampsVisible !== nextProps.timestampsVisible;
const networkMessageUpdateChanged =
@ -62,17 +57,15 @@ const MessageContainer = createClass({
return repeatChanged
|| openChanged
|| tableDataChanged
|| responseChanged
|| totalTimeChanged
|| timestampVisibleChanged
|| networkMessageUpdateChanged;
},
render() {
const { message } = this.props;
const message = this.props.getMessage();
let MessageComponent = getMessageComponent(message);
return MessageComponent(this.props);
return MessageComponent(Object.assign({message, indent: message.indent}, this.props));
}
});

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

@ -9,6 +9,7 @@ const ReactDOM = require("devtools/client/shared/vendor/react-dom");
const { Provider } = require("devtools/client/shared/vendor/react-redux");
const actions = require("devtools/client/webconsole/new-console-output/actions/index");
const { batchActions } = require("devtools/client/shared/redux/middleware/debounce");
const { createContextMenu } = require("devtools/client/webconsole/new-console-output/utils/context-menu");
const { configureStore } = require("devtools/client/webconsole/new-console-output/store");
@ -172,7 +173,7 @@ NewConsoleOutputWrapper.prototype = {
dispatchMessagesAdd: function (messages) {
const batchedActions = messages.map(message => actions.messageAdd(message));
store.dispatch(actions.batchActions(batchedActions));
store.dispatch(batchActions(batchedActions));
},
dispatchMessagesClear: function () {
@ -204,7 +205,7 @@ function batchedMessageAdd(action) {
queuedActions.push(action);
if (!throttledDispatchTimeout) {
throttledDispatchTimeout = setTimeout(() => {
store.dispatch(actions.batchActions(queuedActions));
store.dispatch(batchActions(queuedActions));
queuedActions = [];
throttledDispatchTimeout = null;
}, 50);

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

@ -30,7 +30,7 @@ function getCurrentGroup(state) {
}
function getVisibleMessages(state) {
return state.messages.visibleMessages.map(id => getMessage(state, id));
return state.messages.visibleMessages;
}
function getAllRepeatById(state) {

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

@ -12,11 +12,13 @@ const {
createStore
} = require("devtools/client/shared/vendor/redux");
const { thunk } = require("devtools/client/shared/redux/middleware/thunk");
const {
BATCH_ACTIONS
} = require("devtools/client/shared/redux/middleware/debounce");
const {
MESSAGE_ADD,
MESSAGES_CLEAR,
REMOVED_MESSAGES_CLEAR,
BATCH_ACTIONS,
PREFS,
} = require("devtools/client/webconsole/new-console-output/constants");
const { reducers } = require("./reducers/index");

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

@ -21,7 +21,10 @@ const serviceContainer = require("devtools/client/webconsole/new-console-output/
describe("MessageContainer component:", () => {
it("pipes data to children as expected", () => {
const message = stubPreparedMessages.get("console.log('foobar', 'test')");
const rendered = renderComponent(MessageContainer, {message, serviceContainer});
const rendered = renderComponent(MessageContainer, {
getMessage: () => message,
serviceContainer
});
expect(rendered.textContent.includes("foobar")).toBe(true);
});

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

@ -0,0 +1,62 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const expect = require("expect");
const {
debounceActions,
} = require("devtools/client/shared/redux/middleware/debounce");
describe("Debounce Middleware", () => {
let nextArgs = [];
const fakeStore = {};
const fakeNext = (...args) => {
nextArgs.push(args);
};
beforeEach(() => {
nextArgs = [];
});
it("should pass the intercepted action to next", () => {
const fakeAction = {
type: "FAKE_ACTION"
};
debounceActions()(fakeStore)(fakeNext)(fakeAction);
expect(nextArgs.length).toEqual(1);
expect(nextArgs[0]).toEqual([fakeAction]);
});
it("should debounce if specified", () => {
const fakeAction = {
type: "FAKE_ACTION",
meta: {
debounce: true
}
};
const executed = debounceActions(1, 1)(fakeStore)(fakeNext)(fakeAction);
expect(nextArgs.length).toEqual(0);
return executed.then(() => {
expect(nextArgs.length).toEqual(1);
});
});
it("should have no effect if no timeout", () => {
const fakeAction = {
type: "FAKE_ACTION",
meta: {
debounce: true
}
};
debounceActions()(fakeStore)(fakeNext)(fakeAction);
expect(nextArgs.length).toEqual(1);
expect(nextArgs[0]).toEqual([fakeAction]);
});
});

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

@ -14,6 +14,7 @@ support-files =
test-location-styleeditor-link-1.css
test-location-styleeditor-link-2.css
test-location-styleeditor-link.html
test-network-request.html
test-stacktrace-location-debugger-link.html
!/devtools/client/framework/test/shared-head.js
@ -38,6 +39,7 @@ skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32
[browser_webconsole_location_debugger_link.js]
[browser_webconsole_location_scratchpad_link.js]
[browser_webconsole_location_styleeditor_link.js]
[browser_webconsole_network_messages_click.js]
[browser_webconsole_nodes_highlight.js]
[browser_webconsole_nodes_select.js]
[browser_webconsole_observer_notifications.js]

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

@ -32,7 +32,7 @@ add_task(async function task() {
}]
});
await loadDocument(currentTab.linkedBrowser);
await loadDocument(currentTab.linkedBrowser, TEST_PATH);
info("Document loaded.");
await onMessageAdded;

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

@ -0,0 +1,78 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const TEST_URI = "data:text/html;charset=utf8,Test that clicking on a network message " +
"in the console opens the netmonitor panel.";
const TEST_FILE = "test-network-request.html";
const JSON_TEST_URL = "test-network-request.html";
const TEST_PATH = "http://example.com/browser/devtools/client/webconsole/new-console-output/test/mochitest/";
const NET_PREF = "devtools.webconsole.filter.net";
const XHR_PREF = "devtools.webconsole.filter.netxhr";
Services.prefs.setBoolPref(NET_PREF, true);
Services.prefs.setBoolPref(XHR_PREF, true);
registerCleanupFunction(() => {
Services.prefs.clearUserPref(NET_PREF);
Services.prefs.clearUserPref(XHR_PREF);
});
add_task(async function task() {
const hud = await openNewTabAndConsole(TEST_URI);
const currentTab = gBrowser.selectedTab;
let target = TargetFactory.forTab(currentTab);
let toolbox = gDevTools.getToolbox(target);
const documentUrl = TEST_PATH + TEST_FILE;
await loadDocument(currentTab.linkedBrowser, documentUrl);
info("Document loaded.");
await testNetmonitorLink(toolbox, hud, documentUrl);
// Go back to console.
await toolbox.selectTool("webconsole");
info("console panel open again.");
// Fire an XHR request.
await ContentTask.spawn(gBrowser.selectedBrowser, null, function () {
content.wrappedJSObject.testXhrGet();
});
const jsonUrl = TEST_PATH + JSON_TEST_URL;
await testNetmonitorLink(toolbox, hud, jsonUrl);
});
async function testNetmonitorLink(toolbox, hud, url) {
let messageNode = await waitFor(() => findMessage(hud, url));
let urlNode = messageNode.querySelector(".url");
info("Network message found.");
let onNetmonitorSelected = new Promise((resolve) => {
toolbox.once("netmonitor-selected", (event, panel) => {
resolve(panel);
});
});
info("Simulate click on the network message url.");
EventUtils.sendMouseEvent({ type: "click" }, urlNode);
const {panelWin} = await onNetmonitorSelected;
ok(true, "The netmonitor panel is selected when clicking on the network message");
let { store, windowRequire } = panelWin;
let actions = windowRequire("devtools/client/netmonitor/src/actions/index");
let { getSelectedRequest } =
windowRequire("devtools/client/netmonitor/src/selectors/index");
store.dispatch(actions.batchEnable(false));
await waitUntil(() => {
const selected = getSelectedRequest(store.getState());
return selected && selected.url === url;
});
ok(true, "The attached url is correct.");
}

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

@ -24,7 +24,7 @@ add_task(async function () {
const currentTab = gBrowser.selectedTab;
info("Network panel is open.");
await loadDocument(currentTab.linkedBrowser);
await loadDocument(currentTab.linkedBrowser, TEST_PATH);
info("Document loaded.");
// Test that the request appears in the network panel.

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

@ -180,9 +180,9 @@ function hideContextMenu(hud) {
return onPopupHidden;
}
function loadDocument(browser) {
function loadDocument(browser, url) {
return new Promise(resolve => {
browser.addEventListener("load", resolve, {capture: true, once: true});
BrowserTestUtils.loadURI(gBrowser.selectedBrowser, TEST_PATH);
BrowserTestUtils.loadURI(gBrowser.selectedBrowser, url);
});
}

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

@ -0,0 +1,46 @@
<!-- 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/. -->
<!DOCTYPE HTML>
<html dir="ltr" xml:lang="en-US" lang="en-US">
<head>
<meta charset="utf-8">
<title>Console HTTP test page</title>
<script type="text/javascript">
/* exported testXhrGet, testXhrWarn, testXhrPost */
"use strict";
function makeXhr(method, url, requestBody, callback) {
let xmlhttp = new XMLHttpRequest();
xmlhttp.open(method, url, true);
xmlhttp.onreadystatechange = function () {
if (callback && xmlhttp.readyState == 4) {
callback();
}
};
xmlhttp.send(requestBody);
}
function testXhrGet(callback) {
makeXhr("get", "test-data.json", null, callback);
}
function testXhrWarn(callback) {
makeXhr("get", "http://example.com/browser/devtools/client/netmonitor/test/sjs_cors-test-server.sjs", null, callback);
}
function testXhrPost(callback) {
makeXhr("post", "test-data.json", "Hello world!", callback);
}
</script>
</head>
<body>
<h1>Heads Up Display HTTP Logging Testpage</h1>
<h2>This page is used to test the HTTP logging.</h2>
<form action="https://example.com/browser/devtools/client/webconsole/test/test-network-request.html" method="post">
<input name="name" type="text" value="foo bar"><br>
<input name="age" type="text" value="144"><br>
</form>
</body>
</html>

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

@ -229,8 +229,9 @@ describe("Message reducer:", () => {
expect(messages.count()).toBe(logLimit);
expect(visibleMessages.length).toBe(logLimit);
expect(visibleMessages[0].parameters[0]).toBe(`message-0`);
expect(visibleMessages[logLimit - 1].parameters[0]).toBe(`message-${logLimit - 1}`);
expect(messages.get(visibleMessages[0]).parameters[0]).toBe(`message-0`);
expect(messages.get(visibleMessages[logLimit - 1]).parameters[0])
.toBe(`message-${logLimit - 1}`);
// The groups were cleaned up.
const groups = getAllGroupsById(getState());
@ -263,7 +264,7 @@ describe("Message reducer:", () => {
const groups = getAllGroupsById(getState());
expect(groups.count()).toBe(logLimit);
expect(visibleMessages[1].parameters[0]).toBe(`message-2-a`);
expect(messages.get(visibleMessages[1]).parameters[0]).toBe(`message-2-a`);
expect(messages.last().parameters[0]).toBe(`message-${logLimit + 1}-b`);
});
@ -299,8 +300,9 @@ describe("Message reducer:", () => {
const visibleMessages = getVisibleMessages(getState());
expect(visibleMessages.length).toBe(logLimit);
const lastVisibleMessage = visibleMessages[visibleMessages.length - 1];
expect(lastVisibleMessage.parameters[0]).toBe(`group-${logLimit + 1}`);
const lastVisibleMessageId = visibleMessages[visibleMessages.length - 1];
expect(messages.get(lastVisibleMessageId).parameters[0])
.toBe(`group-${logLimit + 1}`);
});
it("does not add null messages to the store", () => {

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

@ -347,7 +347,7 @@ let SourceActor = ActorClassWithSpec(sourceSpec, {
}
}
if (isWasm) {
if (isWasm && this.dbg.allowWasmBinarySource) {
let wasm = this.source.binary;
let buffer = wasm.buffer;
assert(

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

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<title>Bug 1373712 - Assertions of SpecifiedKeyframeArraysAreEqual(mKeyframes, keyframesCopy) with large color value
</title>
<meta charset="UTF-8">
<script>
document.documentElement.animate([{ "color": "hsl(63e292,41%,34%)" }]);
</script>
</head>
</html>

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

@ -27,3 +27,4 @@ pref(dom.animations-api.core.enabled,true) load 1334583-1.html
pref(dom.animations-api.core.enabled,true) load 1335998-1.html
pref(dom.animations-api.core.enabled,true) load 1343589-1.html
pref(dom.animations-api.core.enabled,true) load 1359658-1.html
pref(dom.animations-api.core.enabled,true) load 1373712-1.html

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

@ -10119,8 +10119,12 @@ nsGlobalWindow::ShowModalDialog(JSContext* aCx, const nsAString& aUrl,
JS::Rooted<JS::Value> result(aCx);
if (retVal) {
JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
if (!global) {
global = FastGetGlobalJSObject();
}
aError = nsContentUtils::XPConnect()->VariantToJS(aCx,
FastGetGlobalJSObject(),
global,
retVal, aRetval);
} else {
aRetval.setNull();

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

@ -87,7 +87,6 @@
#include "nsCycleCollectionNoteRootCallback.h"
#include "GeckoProfiler.h"
#include "mozilla/IdleTaskRunner.h"
using namespace mozilla;
using namespace mozilla::dom;
@ -121,7 +120,7 @@ const size_t gStackSize = 8192;
#define NS_CC_SKIPPABLE_DELAY 250 // ms
// ForgetSkippable is usually fast, so we can use small budgets.
// This isn't a real budget but a hint to IdleTaskRunner whether there
// This isn't a real budget but a hint to CollectorRunner whether there
// is enough time to call ForgetSkippable.
static const int64_t kForgetSkippableSliceDuration = 2;
@ -150,14 +149,16 @@ static const uint32_t kMaxICCDuration = 2000; // ms
// Large value used to specify that a script should run essentially forever
#define NS_UNLIMITED_SCRIPT_RUNTIME (0x40000000LL << 32)
class CollectorRunner;
// if you add statics here, add them to the list in StartupJSEnvironment
static nsITimer *sGCTimer;
static nsITimer *sShrinkingGCTimer;
static StaticRefPtr<IdleTaskRunner> sCCRunner;
static StaticRefPtr<IdleTaskRunner> sICCRunner;
static StaticRefPtr<CollectorRunner> sCCRunner;
static StaticRefPtr<CollectorRunner> sICCRunner;
static nsITimer *sFullGCTimer;
static StaticRefPtr<IdleTaskRunner> sInterSliceGCRunner;
static StaticRefPtr<CollectorRunner> sInterSliceGCRunner;
static TimeStamp sLastCCEndTime;
@ -227,6 +228,183 @@ static int32_t sExpensiveCollectorPokes = 0;
static const int32_t kPokesBetweenExpensiveCollectorTriggers = 5;
static TimeDuration sGCUnnotifiedTotalTime;
// Return true if some meaningful work was done.
typedef bool (*CollectorRunnerCallback) (TimeStamp aDeadline, void* aData);
// Repeating callback runner for CC and GC.
class CollectorRunner final : public IdleRunnable
{
public:
static already_AddRefed<CollectorRunner>
Create(CollectorRunnerCallback aCallback, uint32_t aDelay,
int64_t aBudget, bool aRepeating, void* aData = nullptr)
{
if (sShuttingDown) {
return nullptr;
}
RefPtr<CollectorRunner> runner =
new CollectorRunner(aCallback, aDelay, aBudget, aRepeating, aData);
runner->Schedule(false); // Initial scheduling shouldn't use idle dispatch.
return runner.forget();
}
NS_IMETHOD Run() override
{
if (!mCallback) {
return NS_OK;
}
// Deadline is null when called from timer.
bool deadLineWasNull = mDeadline.IsNull();
bool didRun = false;
if (deadLineWasNull || ((TimeStamp::Now() + mBudget) < mDeadline)) {
CancelTimer();
didRun = mCallback(mDeadline, mData);
}
if (mCallback && (mRepeating || !didRun)) {
// If we didn't do meaningful work, don't schedule using immediate
// idle dispatch, since that could lead to a loop until the idle
// period ends.
Schedule(didRun);
}
return NS_OK;
}
static void
TimedOut(nsITimer* aTimer, void* aClosure)
{
RefPtr<CollectorRunner> runnable = static_cast<CollectorRunner*>(aClosure);
runnable->Run();
}
void SetDeadline(mozilla::TimeStamp aDeadline) override
{
mDeadline = aDeadline;
};
void SetTimer(uint32_t aDelay, nsIEventTarget* aTarget) override
{
if (mTimerActive) {
return;
}
mTarget = aTarget;
if (!mTimer) {
mTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
} else {
mTimer->Cancel();
}
if (mTimer) {
mTimer->SetTarget(mTarget);
mTimer->InitWithFuncCallback(TimedOut, this, aDelay,
nsITimer::TYPE_ONE_SHOT);
mTimerActive = true;
}
}
nsresult Cancel() override
{
CancelTimer();
mTimer = nullptr;
mScheduleTimer = nullptr;
mCallback = nullptr;
return NS_OK;
}
static void
ScheduleTimedOut(nsITimer* aTimer, void* aClosure)
{
RefPtr<CollectorRunner> runnable = static_cast<CollectorRunner*>(aClosure);
runnable->Schedule(true);
}
void Schedule(bool aAllowIdleDispatch)
{
if (!mCallback) {
return;
}
if (sShuttingDown) {
Cancel();
return;
}
mDeadline = TimeStamp();
TimeStamp now = TimeStamp::Now();
TimeStamp hint = nsRefreshDriver::GetIdleDeadlineHint(now);
if (hint != now) {
// RefreshDriver is ticking, let it schedule the idle dispatch.
nsRefreshDriver::DispatchIdleRunnableAfterTick(this, mDelay);
// Ensure we get called at some point, even if RefreshDriver is stopped.
SetTimer(mDelay, mTarget);
} else {
// RefreshDriver doesn't seem to be running.
if (aAllowIdleDispatch) {
nsCOMPtr<nsIRunnable> runnable = this;
NS_IdleDispatchToCurrentThread(runnable.forget(), mDelay);
SetTimer(mDelay, mTarget);
} else {
if (!mScheduleTimer) {
mScheduleTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
if (!mScheduleTimer) {
return;
}
} else {
mScheduleTimer->Cancel();
}
// We weren't allowed to do idle dispatch immediately, do it after a
// short timeout.
mScheduleTimer->InitWithFuncCallback(ScheduleTimedOut, this, 16,
nsITimer::TYPE_ONE_SHOT_LOW_PRIORITY);
}
}
}
private:
explicit CollectorRunner(CollectorRunnerCallback aCallback,
uint32_t aDelay, int64_t aBudget,
bool aRepeating, void* aData)
: mCallback(aCallback), mDelay(aDelay)
, mBudget(TimeDuration::FromMilliseconds(aBudget))
, mRepeating(aRepeating), mTimerActive(false), mData(aData)
{
}
~CollectorRunner()
{
CancelTimer();
}
void CancelTimer()
{
nsRefreshDriver::CancelIdleRunnable(this);
if (mTimer) {
mTimer->Cancel();
}
if (mScheduleTimer) {
mScheduleTimer->Cancel();
}
mTimerActive = false;
}
nsCOMPtr<nsITimer> mTimer;
nsCOMPtr<nsITimer> mScheduleTimer;
nsCOMPtr<nsIEventTarget> mTarget;
CollectorRunnerCallback mCallback;
uint32_t mDelay;
TimeStamp mDeadline;
TimeDuration mBudget;
bool mRepeating;
bool mTimerActive;
void* mData;
};
static const char*
ProcessNameForCollectorLog()
{
@ -1602,7 +1780,7 @@ nsJSContext::GetMaxCCSliceTimeSinceClear()
}
static bool
ICCRunnerFired(TimeStamp aDeadline)
ICCRunnerFired(TimeStamp aDeadline, void* aData)
{
if (sDidShutdown) {
return false;
@ -1643,8 +1821,8 @@ nsJSContext::BeginCycleCollectionCallback()
// Create an ICC timer even if ICC is globally disabled, because we could be manually triggering
// an incremental collection, and we want to be sure to finish it.
sICCRunner = IdleTaskRunner::Create(ICCRunnerFired, kICCIntersliceDelay,
kIdleICCSliceBudget, true, []{ return sShuttingDown; });
sICCRunner = CollectorRunner::Create(ICCRunnerFired, kICCIntersliceDelay,
kIdleICCSliceBudget, true);
}
static_assert(NS_GC_DELAY > kMaxICCDuration, "A max duration ICC shouldn't reduce GC delay to 0");
@ -1856,9 +2034,11 @@ GCTimerFired(nsITimer *aTimer, void *aClosure)
{
nsJSContext::KillGCTimer();
// Now start the actual GC after initial timer has fired.
sInterSliceGCRunner = IdleTaskRunner::Create([aClosure](TimeStamp aDeadline) {
return InterSliceGCRunnerFired(aDeadline, aClosure);
}, NS_INTERSLICE_GC_DELAY, sActiveIntersliceGCBudget, false, []{ return sShuttingDown; });
sInterSliceGCRunner = CollectorRunner::Create(InterSliceGCRunnerFired,
NS_INTERSLICE_GC_DELAY,
sActiveIntersliceGCBudget,
false,
aClosure);
}
// static
@ -1882,7 +2062,7 @@ ShouldTriggerCC(uint32_t aSuspected)
}
static bool
CCRunnerFired(TimeStamp aDeadline)
CCRunnerFired(TimeStamp aDeadline, void* aData)
{
if (sDidShutdown) {
return false;
@ -2034,13 +2214,13 @@ nsJSContext::RunNextCollectorTimer()
if (sCCRunner) {
if (ReadyToTriggerExpensiveCollectorTimer()) {
CCRunnerFired(TimeStamp());
CCRunnerFired(TimeStamp(), nullptr);
}
return;
}
if (sICCRunner) {
ICCRunnerFired(TimeStamp());
ICCRunnerFired(TimeStamp(), nullptr);
return;
}
}
@ -2147,9 +2327,8 @@ nsJSContext::MaybePokeCC()
nsCycleCollector_dispatchDeferredDeletion();
sCCRunner =
IdleTaskRunner::Create(CCRunnerFired, NS_CC_SKIPPABLE_DELAY,
kForgetSkippableSliceDuration, true,
[]{ return sShuttingDown; });
CollectorRunner::Create(CCRunnerFired, NS_CC_SKIPPABLE_DELAY,
kForgetSkippableSliceDuration, true);
}
}
@ -2329,9 +2508,8 @@ DOMGCSliceCallback(JSContext* aCx, JS::GCProgress aProgress, const JS::GCDescrip
nsJSContext::KillInterSliceGCRunner();
if (!sShuttingDown && !aDesc.isComplete_) {
sInterSliceGCRunner =
IdleTaskRunner::Create([](TimeStamp aDeadline) {
return InterSliceGCRunnerFired(aDeadline, nullptr);
}, NS_INTERSLICE_GC_DELAY, sActiveIntersliceGCBudget, false, []{ return sShuttingDown; });
CollectorRunner::Create(InterSliceGCRunnerFired, NS_INTERSLICE_GC_DELAY,
sActiveIntersliceGCBudget, false);
}
if (ShouldTriggerCC(nsCycleCollector_suspectedCount())) {

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

@ -16,8 +16,16 @@
*/
SimpleTest.waitForExplicitFinish();
function openModal() {
showModalDialog("javascript:opener.winRef = window; \
async function openModal() {
await SpecialPowers.pushPrefEnv({ set: [[
"dom.disable_window_showModalDialog", false ]] });
let iframe = document.createElement("iframe");
document.body.appendChild(iframe);
await new Promise(resolve => {
iframe.addEventListener("load", resolve);
});
iframe.contentWindow.showModalDialog("javascript:opener.winRef = window; \
window.opener.setTimeout(\'winRef.dialogArguments;\', 0);\
window.close();");

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

@ -487,7 +487,14 @@ function testSyncXHR2() {
then(testModalDialog);
}
function testModalDialog() {
async function testModalDialog() {
await SpecialPowers.pushPrefEnv({ set: [[ "dom.disable_window_showModalDialog", false ]] });
let iframe = document.createElement("iframe");
document.body.appendChild(iframe);
await new Promise(resolve => {
iframe.addEventListener("load", resolve);
});
window.showModalDialog = iframe.contentWindow.showModalDialog;
var didHandleCallback = false;
div.innerHTML = "<span>1</span><span>2</span>";
m = new M(function(records, observer) {

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

@ -100,11 +100,11 @@ skip-if = toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests
skip-if = toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests
[test_fuzzing_bugs.html]
[test_video_fastpath_mp4.html]
fail-if = (os == 'mac') || (os == 'win' && !(e10s && os_version == '6.1'))
fail-if = (os == 'mac') || (os == 'win' && !(e10s && os_version == '6.1')) # no fast path on windows yet (bug 1373165 or 1373770), and mac (bug 1373669)
[test_video_fastpath_theora.html]
fail-if = (os == 'mac')
fail-if = (os == 'mac') || (os == 'win' && os_version != '6.1') # no fast path on windows yet (bug 1373192), and mac (bug 1373702)
[test_video_fastpath_vp8.html]
fail-if = (os == 'mac')
fail-if = (os == 'mac') || (os == 'win' && os_version != '6.1') # no fast path on windows yet (bug 1373192), and mac (bug 1373702)
[test_video_fastpath_vp9.html]
fail-if = (os == 'mac')
fail-if = (os == 'mac') || (os == 'win' && os_version != '6.1') # no fast path on windows yet (bug 1373192), and mac (bug 1373702)
[test_webglcontextcreationerror.html]

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

@ -14,11 +14,23 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=391777
<script class="testbody" type="text/javascript">
/** Test for Bug 391777 **/
var arg = {};
arg.testVal = "foo";
var result = window.showModalDialog("javascript:window.returnValue = window.dialogArguments.testVal; window.close(); 'This window should close on its own.';", arg);
ok(true, "We should get here without user interaction");
is(result, "foo", "Unexpected result from showModalDialog");
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({ set: [[ "dom.disable_window_showModalDialog", false ]] }, doTest);
async function doTest() {
let iframe = document.createElement("iframe");
document.body.appendChild(iframe);
await new Promise(resolve => {
iframe.addEventListener("load", resolve);
});
window.showModalDialog = iframe.contentWindow.showModalDialog;
var arg = {};
arg.testVal = "foo";
var result = window.showModalDialog("javascript:window.returnValue = window.dialogArguments.testVal; window.close(); 'This window should close on its own.';", arg);
ok(true, "We should get here without user interaction");
is(result, "foo", "Unexpected result from showModalDialog");
SimpleTest.finish();
}
</script>
</body>

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

@ -109,7 +109,9 @@ function doTest() {
// file_iframe_j_if3.html has an ok() function that calls window.parent.ok_wrapper.
}
addLoadEvent(doTest);
let loaded = new Promise(resolve => { addLoadEvent(resolve) });
let prefSet = SpecialPowers.pushPrefEnv({ set: [[ "dom.disable_window_showModalDialog", false ]] });
Promise.all([ loaded, prefSet ]).then(doTest);
</script>
<body>

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

@ -5198,6 +5198,15 @@ ContentParent::RecvRecordChildEvents(nsTArray<mozilla::Telemetry::ChildEventData
return IPC_OK();
}
mozilla::ipc::IPCResult
ContentParent::RecvRecordDiscardedData(
const mozilla::Telemetry::DiscardedData& aDiscardedData)
{
TelemetryIPC::RecordDiscardedData(GetTelemetryProcessID(mRemoteType),
aDiscardedData);
return IPC_OK();
}
//////////////////////////////////////////////////////////////////
// PURLClassifierParent

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

@ -1177,6 +1177,8 @@ private:
InfallibleTArray<KeyedScalarAction>&& aScalarActions) override;
virtual mozilla::ipc::IPCResult RecvRecordChildEvents(
nsTArray<ChildEventData>&& events) override;
virtual mozilla::ipc::IPCResult RecvRecordDiscardedData(
const DiscardedData& aDiscardedData) override;
public:
void SendGetFilesResponseAndForget(const nsID& aID,
const GetFilesResponseResult& aResult);

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

@ -95,6 +95,7 @@ using mozilla::Telemetry::KeyedAccumulation from "mozilla/TelemetryComms.h";
using mozilla::Telemetry::ScalarAction from "mozilla/TelemetryComms.h";
using mozilla::Telemetry::KeyedScalarAction from "mozilla/TelemetryComms.h";
using mozilla::Telemetry::ChildEventData from "mozilla/TelemetryComms.h";
using mozilla::Telemetry::DiscardedData from "mozilla/TelemetryComms.h";
using mozilla::CrossProcessMutexHandle from "mozilla/ipc/CrossProcessMutex.h";
union ChromeRegistryItem
@ -1091,6 +1092,7 @@ parent:
async UpdateChildScalars(ScalarAction[] updates);
async UpdateChildKeyedScalars(KeyedScalarAction[] updates);
async RecordChildEvents(ChildEventData[] events);
async RecordDiscardedData(DiscardedData data);
sync GetA11yContentId() returns (uint32_t aContentId);
async A11yHandlerControl(uint32_t aPid,

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

@ -102,7 +102,6 @@ PEExpectedNumberOrAngle=Expected a number or an angle but found %1$S.
PEExpectedNumberOrPercent=Expected a number or a percentage but found %1$S.
PEColorBadRGBContents=Expected number or percentage in rgb() but found %1$S.
PEColorComponentBadTerm=Expected %2$S but found %1$S.
PEColorHueEOF=hue
PEExpectedComma=Expected , but found %1$S.
PEColorSaturationEOF=saturation
PEColorLightnessEOF=lightness

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

@ -5,14 +5,18 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "Benchmark.h"
#include "BufferMediaResource.h"
#include "MediaData.h"
#include "MediaPrefs.h"
#include "PDMFactory.h"
#include "VideoUtils.h"
#include "WebMDemuxer.h"
#include "gfxPrefs.h"
#include "mozilla/AbstractThread.h"
#include "mozilla/Preferences.h"
#include "mozilla/SharedThreadPool.h"
#include "mozilla/TaskQueue.h"
#include "mozilla/Telemetry.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/gfx/gfxVars.h"
@ -21,6 +25,8 @@
#include "WebMSample.h"
#endif
using namespace mozilla::gfx;
namespace mozilla {
// Update this version number to force re-running the benchmark. Such as when

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

@ -8,11 +8,10 @@
#define MOZILLA_BENCHMARK_H
#include "MediaDataDemuxer.h"
#include "QueueObject.h"
#include "PlatformDecoderModule.h"
#include "QueueObject.h"
#include "mozilla/Maybe.h"
#include "mozilla/RefPtr.h"
#include "mozilla/TaskQueue.h"
#include "mozilla/TimeStamp.h"
#include "nsCOMPtr.h"

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

@ -4,13 +4,15 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "CanvasCaptureMediaStream.h"
#include "DOMMediaStream.h"
#include "gfxPlatform.h"
#include "ImageContainer.h"
#include "MediaStreamGraph.h"
#include "MediaStreamListener.h"
#include "gfxPlatform.h"
#include "mozilla/Atomics.h"
#include "mozilla/dom/CanvasCaptureMediaStreamBinding.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/Atomics.h"
#include "nsContentUtils.h"
using namespace mozilla::layers;

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

@ -4,20 +4,23 @@
* 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 <stdint.h>
#include <algorithm>
#include "nsIStringBundle.h"
#include "nsDebug.h"
#include "nsString.h"
#include "CubebUtils.h"
#include "MediaInfo.h"
#include "mozilla/Logging.h"
#include "mozilla/Preferences.h"
#include "mozilla/Services.h"
#include "mozilla/StaticMutex.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/Telemetry.h"
#include "mozilla/Logging.h"
#include "nsThreadUtils.h"
#include "CubebUtils.h"
#include "nsAutoRef.h"
#include "nsDebug.h"
#include "nsIStringBundle.h"
#include "nsString.h"
#include "nsThreadUtils.h"
#include "prdtoa.h"
#include <algorithm>
#include <stdint.h>
#define PREF_VOLUME_SCALE "media.volume_scale"
#define PREF_CUBEB_BACKEND "media.cubeb.backend"

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

@ -4,28 +4,31 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "DOMMediaStream.h"
#include "AudioCaptureStream.h"
#include "AudioChannelAgent.h"
#include "AudioStreamTrack.h"
#include "Layers.h"
#include "MediaStreamGraph.h"
#include "MediaStreamListener.h"
#include "VideoStreamTrack.h"
#include "mozilla/dom/AudioNode.h"
#include "mozilla/dom/AudioTrack.h"
#include "mozilla/dom/AudioTrackList.h"
#include "mozilla/dom/DocGroup.h"
#include "mozilla/dom/HTMLCanvasElement.h"
#include "mozilla/dom/LocalMediaStreamBinding.h"
#include "mozilla/dom/MediaStreamBinding.h"
#include "mozilla/dom/MediaStreamTrackEvent.h"
#include "mozilla/dom/VideoTrack.h"
#include "mozilla/dom/VideoTrackList.h"
#include "mozilla/media/MediaUtils.h"
#include "nsContentUtils.h"
#include "nsRFPService.h"
#include "nsServiceManagerUtils.h"
#include "nsIScriptError.h"
#include "nsIUUIDGenerator.h"
#include "nsPIDOMWindow.h"
#include "mozilla/dom/DocGroup.h"
#include "mozilla/dom/MediaStreamBinding.h"
#include "mozilla/dom/MediaStreamTrackEvent.h"
#include "mozilla/dom/LocalMediaStreamBinding.h"
#include "mozilla/dom/AudioNode.h"
#include "AudioChannelAgent.h"
#include "mozilla/dom/AudioTrack.h"
#include "mozilla/dom/AudioTrackList.h"
#include "mozilla/dom/VideoTrack.h"
#include "mozilla/dom/VideoTrackList.h"
#include "mozilla/dom/HTMLCanvasElement.h"
#include "mozilla/media/MediaUtils.h"
#include "MediaStreamGraph.h"
#include "AudioStreamTrack.h"
#include "VideoStreamTrack.h"
#include "Layers.h"
#include "nsRFPService.h"
#include "nsServiceManagerUtils.h"
// GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
// GetTickCount() and conflicts with NS_DECL_NSIDOMMEDIASTREAM, containing

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

@ -67,12 +67,14 @@ IsAndroidMediaType(const MediaContainerType& aType)
/* static */ bool
DecoderTraits::IsHttpLiveStreamingType(const MediaContainerType& aType)
{
const auto& mimeType = aType.Type();
return // For m3u8.
// https://tools.ietf.org/html/draft-pantos-http-live-streaming-19#section-10
aType.Type() == MEDIAMIMETYPE("application/vnd.apple.mpegurl")
mimeType == MEDIAMIMETYPE("application/vnd.apple.mpegurl")
// Some sites serve these as the informal m3u type.
|| aType.Type() == MEDIAMIMETYPE("application/x-mpegurl")
|| aType.Type() == MEDIAMIMETYPE("audio/x-mpegurl");
|| mimeType == MEDIAMIMETYPE("application/x-mpegurl")
|| mimeType == MEDIAMIMETYPE("audio/mpegurl")
|| mimeType == MEDIAMIMETYPE("audio/x-mpegurl");
}
/* static */ bool

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

@ -4,25 +4,25 @@
* 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 "mozilla/ReentrantMonitor.h"
#include "MediaCache.h"
#include "prio.h"
#include "nsContentUtils.h"
#include "nsThreadUtils.h"
#include "MediaResource.h"
#include "mozilla/Logging.h"
#include "mozilla/Preferences.h"
#include "FileBlockCache.h"
#include "MediaBlockCacheBase.h"
#include "MediaResource.h"
#include "MemoryBlockCache.h"
#include "nsIObserverService.h"
#include "nsISeekableStream.h"
#include "nsIPrincipal.h"
#include "mozilla/Attributes.h"
#include "mozilla/Logging.h"
#include "mozilla/Preferences.h"
#include "mozilla/ReentrantMonitor.h"
#include "mozilla/Services.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/Telemetry.h"
#include "nsContentUtils.h"
#include "nsIObserverService.h"
#include "nsIPrincipal.h"
#include "nsISeekableStream.h"
#include "nsThreadUtils.h"
#include "prio.h"
#include <algorithm>
namespace mozilla {

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

@ -7,12 +7,12 @@
#ifndef MediaCache_h_
#define MediaCache_h_
#include "nsTArray.h"
#include "nsCOMPtr.h"
#include "nsHashKeys.h"
#include "nsTHashtable.h"
#include "Intervals.h"
#include "mozilla/UniquePtr.h"
#include "nsCOMPtr.h"
#include "nsHashKeys.h"
#include "nsTArray.h"
#include "nsTHashtable.h"
class nsIPrincipal;

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

@ -5,17 +5,24 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "MediaData.h"
#include "ImageContainer.h"
#include "MediaInfo.h"
#include "VideoUtils.h"
#include "ImageContainer.h"
#include "mozilla/layers/SharedRGBImage.h"
#include "YCbCrUtils.h"
#include "mozilla/layers/ImageBridgeChild.h"
#include "mozilla/layers/KnowsCompositor.h"
#include "mozilla/layers/SharedRGBImage.h"
#ifdef MOZ_WIDGET_GONK
#include <cutils/properties.h>
#endif
#include <stdint.h>
#ifdef XP_WIN
#include "mozilla/layers/D3D11YCbCrImage.h"
#endif
namespace mozilla {
using namespace mozilla::gfx;
@ -241,19 +248,14 @@ VideoData::UpdateTimestamp(const TimeUnit& aTimestamp)
mDuration = updatedDuration;
}
/* static */
bool VideoData::SetVideoDataToImage(PlanarYCbCrImage* aVideoImage,
const VideoInfo& aInfo,
const YCbCrBuffer &aBuffer,
const IntRect& aPicture,
bool aCopyData)
PlanarYCbCrData
ConstructPlanarYCbCrData(const VideoInfo& aInfo,
const VideoData::YCbCrBuffer& aBuffer,
const IntRect& aPicture)
{
if (!aVideoImage) {
return false;
}
const YCbCrBuffer::Plane &Y = aBuffer.mPlanes[0];
const YCbCrBuffer::Plane &Cb = aBuffer.mPlanes[1];
const YCbCrBuffer::Plane &Cr = aBuffer.mPlanes[2];
const VideoData::YCbCrBuffer::Plane& Y = aBuffer.mPlanes[0];
const VideoData::YCbCrBuffer::Plane& Cb = aBuffer.mPlanes[1];
const VideoData::YCbCrBuffer::Plane& Cr = aBuffer.mPlanes[2];
PlanarYCbCrData data;
data.mYChannel = Y.mData + Y.mOffset;
@ -271,6 +273,21 @@ bool VideoData::SetVideoDataToImage(PlanarYCbCrImage* aVideoImage,
data.mPicSize = aPicture.Size();
data.mStereoMode = aInfo.mStereoMode;
data.mYUVColorSpace = aBuffer.mYUVColorSpace;
return data;
}
/* static */ bool
VideoData::SetVideoDataToImage(PlanarYCbCrImage* aVideoImage,
const VideoInfo& aInfo,
const YCbCrBuffer &aBuffer,
const IntRect& aPicture,
bool aCopyData)
{
if (!aVideoImage) {
return false;
}
PlanarYCbCrData data = ConstructPlanarYCbCrData(aInfo, aBuffer, aPicture);
aVideoImage->SetDelayedConversion(true);
if (aCopyData) {
@ -290,7 +307,8 @@ VideoData::CreateAndCopyData(const VideoInfo& aInfo,
const YCbCrBuffer& aBuffer,
bool aKeyframe,
const TimeUnit& aTimecode,
const IntRect& aPicture)
const IntRect& aPicture,
layers::KnowsCompositor* aAllocator)
{
if (!aContainer) {
// Create a dummy VideoData with no image. This gives us something to
@ -328,6 +346,19 @@ VideoData::CreateAndCopyData(const VideoInfo& aInfo,
if (IsYV12Format(Y, Cb, Cr) && !IsInEmulator()) {
v->mImage = new layers::GrallocImage();
}
#elif XP_WIN
if (aAllocator && aAllocator->GetCompositorBackendType()
== layers::LayersBackend::LAYERS_D3D11) {
RefPtr<layers::D3D11YCbCrImage> d3d11Image = new layers::D3D11YCbCrImage();
PlanarYCbCrData data = ConstructPlanarYCbCrData(aInfo, aBuffer, aPicture);
if (d3d11Image->SetData(layers::ImageBridgeChild::GetSingleton()
? layers::ImageBridgeChild::GetSingleton().get()
: aAllocator,
aContainer, data)) {
v->mImage = d3d11Image;
return v.forget();
}
}
#endif
if (!v->mImage) {
v->mImage = aContainer->CreatePlanarYCbCrImage();

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

@ -8,25 +8,26 @@
#include "AudioSampleFormat.h"
#include "ImageTypes.h"
#include "nsSize.h"
#include "mozilla/gfx/Rect.h"
#include "nsRect.h"
#include "nsIMemoryReporter.h"
#include "SharedBuffer.h"
#include "TimeUnits.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/PodOperations.h"
#include "mozilla/RefPtr.h"
#include "mozilla/Span.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/UniquePtrExtensions.h"
#include "mozilla/gfx/Rect.h"
#include "nsIMemoryReporter.h"
#include "nsRect.h"
#include "nsSize.h"
#include "nsTArray.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/PodOperations.h"
#include "TimeUnits.h"
namespace mozilla {
namespace layers {
class Image;
class ImageContainer;
class KnowsCompositor;
} // namespace layers
class MediaByteBuffer;
@ -497,7 +498,8 @@ public:
const YCbCrBuffer& aBuffer,
bool aKeyframe,
const media::TimeUnit& aTimecode,
const IntRect& aPicture);
const IntRect& aPicture,
layers::KnowsCompositor* aAllocator = nullptr);
static already_AddRefed<VideoData> CreateAndCopyData(
const VideoInfo& aInfo,

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

@ -5,34 +5,35 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "MediaDecoder.h"
#include "AudioChannelService.h"
#include "ImageContainer.h"
#include "Layers.h"
#include "MediaDecoderStateMachine.h"
#include "MediaResource.h"
#include "MediaShutdownManager.h"
#include "VideoFrameContainer.h"
#include "VideoUtils.h"
#include "mozilla/AbstractThread.h"
#include "mozilla/FloatingPoint.h"
#include "mozilla/MathAlgorithms.h"
#include <limits>
#include "nsIObserver.h"
#include "nsTArray.h"
#include "VideoUtils.h"
#include "MediaDecoderStateMachine.h"
#include "ImageContainer.h"
#include "MediaResource.h"
#include "VideoFrameContainer.h"
#include "nsError.h"
#include "mozilla/Preferences.h"
#include "mozilla/StaticPtr.h"
#include "nsIMemoryReporter.h"
#include "nsComponentManagerUtils.h"
#include <algorithm>
#include "MediaShutdownManager.h"
#include "AudioChannelService.h"
#include "mozilla/AbstractThread.h"
#include "mozilla/Telemetry.h"
#include "mozilla/dom/AudioTrack.h"
#include "mozilla/dom/AudioTrackList.h"
#include "mozilla/dom/HTMLMediaElement.h"
#include "mozilla/dom/VideoTrack.h"
#include "mozilla/dom/VideoTrackList.h"
#include "nsPrintfCString.h"
#include "mozilla/Telemetry.h"
#include "Layers.h"
#include "mozilla/layers/ShadowLayers.h"
#include "nsComponentManagerUtils.h"
#include "nsError.h"
#include "nsIMemoryReporter.h"
#include "nsIObserver.h"
#include "nsPrintfCString.h"
#include "nsTArray.h"
#include <algorithm>
#include <limits>
#ifdef MOZ_ANDROID_OMX
#include "AndroidBridge.h"
@ -44,6 +45,12 @@ using namespace mozilla::media;
namespace mozilla {
// GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
// GetTickCount() and conflicts with MediaDecoder::GetCurrentTime implementation.
#ifdef GetCurrentTime
#undef GetCurrentTime
#endif
// avoid redefined macro in unified build
#undef LOG
#undef DUMP

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

@ -7,22 +7,6 @@
#if !defined(MediaDecoder_h_)
#define MediaDecoder_h_
#include "mozilla/Atomics.h"
#include "mozilla/CDMProxy.h"
#include "mozilla/MozPromise.h"
#include "mozilla/ReentrantMonitor.h"
#include "mozilla/StateMirroring.h"
#include "mozilla/StateWatching.h"
#include "mozilla/dom/AudioChannelBinding.h"
#include "necko-config.h"
#include "nsAutoPtr.h"
#include "nsCOMPtr.h"
#include "nsIObserver.h"
#include "nsISupports.h"
#include "nsITimer.h"
#include "AbstractMediaDecoder.h"
#include "DecoderDoctorDiagnostics.h"
#include "MediaDecoderOwner.h"
@ -32,8 +16,21 @@
#include "MediaResourceCallback.h"
#include "MediaStatistics.h"
#include "MediaStreamGraph.h"
#include "TimeUnits.h"
#include "SeekTarget.h"
#include "TimeUnits.h"
#include "mozilla/Atomics.h"
#include "mozilla/CDMProxy.h"
#include "mozilla/MozPromise.h"
#include "mozilla/ReentrantMonitor.h"
#include "mozilla/StateMirroring.h"
#include "mozilla/StateWatching.h"
#include "mozilla/dom/AudioChannelBinding.h"
#include "necko-config.h"
#include "nsAutoPtr.h"
#include "nsCOMPtr.h"
#include "nsIObserver.h"
#include "nsISupports.h"
#include "nsITimer.h"
class nsIStreamListener;
class nsIPrincipal;

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

@ -5,17 +5,19 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "MediaDecoderReader.h"
#include "AbstractMediaDecoder.h"
#include "MediaResource.h"
#include "VideoUtils.h"
#include "ImageContainer.h"
#include "MediaPrefs.h"
#include "nsPrintfCString.h"
#include "mozilla/mozalloc.h"
#include "MediaResource.h"
#include "VideoUtils.h"
#include "mozilla/Mutex.h"
#include <stdint.h>
#include "mozilla/SharedThreadPool.h"
#include "mozilla/TaskQueue.h"
#include "mozilla/mozalloc.h"
#include "nsPrintfCString.h"
#include <algorithm>
#include <stdint.h>
using namespace mozilla::media;

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

@ -6,26 +6,26 @@
#if !defined(MediaDecoderReader_h_)
#define MediaDecoderReader_h_
#include "AbstractMediaDecoder.h"
#include "AudioCompactor.h"
#include "Intervals.h"
#include "MediaData.h"
#include "MediaInfo.h"
#include "MediaMetadataManager.h"
#include "MediaQueue.h"
#include "MediaResult.h"
#include "MediaTimer.h"
#include "SeekTarget.h"
#include "TimeUnits.h"
#include "mozilla/EnumSet.h"
#include "mozilla/MozPromise.h"
#include "nsAutoPtr.h"
#include "AbstractMediaDecoder.h"
#include "MediaInfo.h"
#include "MediaData.h"
#include "MediaResult.h"
#include "MediaMetadataManager.h"
#include "MediaQueue.h"
#include "MediaTimer.h"
#include "AudioCompactor.h"
#include "Intervals.h"
#include "TimeUnits.h"
#include "SeekTarget.h"
namespace mozilla {
class CDMProxy;
class MediaDecoderReader;
class TaskQueue;
struct WaitForDataRejectValue
{

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

@ -4,25 +4,26 @@
* 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 "MediaFormatReader.h"
#include "AutoTaskQueue.h"
#include "mozilla/SizePrintfMacros.h"
#include "Layers.h"
#include "MediaData.h"
#include "MediaInfo.h"
#include "MediaFormatReader.h"
#include "MediaResource.h"
#include "VideoUtils.h"
#include "VideoFrameContainer.h"
#include "mozilla/dom/HTMLMediaElement.h"
#include "mozilla/layers/ShadowLayers.h"
#include "VideoUtils.h"
#include "mozilla/AbstractThread.h"
#include "mozilla/CDMProxy.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/Preferences.h"
#include "mozilla/Telemetry.h"
#include "mozilla/SharedThreadPool.h"
#include "mozilla/SizePrintfMacros.h"
#include "mozilla/SyncRunnable.h"
#include "mozilla/Telemetry.h"
#include "mozilla/Unused.h"
#include "mozilla/dom/HTMLMediaElement.h"
#include "mozilla/layers/ShadowLayers.h"
#include "nsContentUtils.h"
#include "nsPrintfCString.h"
#include "nsSize.h"
@ -2281,6 +2282,15 @@ MediaFormatReader::Update(TrackType aTrack)
nsCString error;
mVideo.mIsHardwareAccelerated =
mVideo.mDecoder && mVideo.mDecoder->IsHardwareAccelerated(error);
#ifdef XP_WIN
// D3D11_YCBCR_IMAGE images are GPU based, we try to limit the amount
// of GPU RAM used.
VideoData* videoData = static_cast<VideoData*>(output.get());
mVideo.mIsHardwareAccelerated =
mVideo.mIsHardwareAccelerated ||
(videoData->mImage &&
videoData->mImage->GetFormat() == ImageFormat::D3D11_YCBCR_IMAGE);
#endif
}
} else if (decoder.HasFatalError()) {
LOG("Rejecting %s promise: DECODE_ERROR", TrackTypeToStr(aTrack));

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

@ -6,21 +6,19 @@
#ifndef MOZILLA_MEDIASTREAMGRAPH_H_
#define MOZILLA_MEDIASTREAMGRAPH_H_
#include "AudioStream.h"
#include "MainThreadUtils.h"
#include "MediaStreamTypes.h"
#include "StreamTracks.h"
#include "VideoSegment.h"
#include "mozilla/LinkedList.h"
#include "mozilla/Mutex.h"
#include "mozilla/TaskQueue.h"
#include "mozilla/dom/AudioChannelBinding.h"
#include "AudioStream.h"
#include "nsTArray.h"
#include "nsIRunnable.h"
#include "VideoSegment.h"
#include "StreamTracks.h"
#include "MainThreadUtils.h"
#include "StreamTracks.h"
#include "nsAutoPtr.h"
#include "nsAutoRef.h"
#include "nsIRunnable.h"
#include "nsTArray.h"
#include <speex/speex_resampler.h>
class nsIRunnable;
@ -170,9 +168,6 @@ class ProcessedMediaStream;
class SourceMediaStream;
class TrackUnionStream;
enum MediaStreamGraphEvent : uint32_t;
enum TrackEventCommand : uint32_t;
/**
* Helper struct for binding a track listener to a specific TrackID.
*/
@ -183,24 +178,6 @@ struct TrackBound
TrackID mTrackID;
};
/**
* Describes how a track should be disabled.
*
* ENABLED Not disabled.
* SILENCE_BLACK Audio data is turned into silence, video frames are made black.
* SILENCE_FREEZE Audio data is turned into silence, video freezes at last frame.
*/
enum class DisabledTrackMode
{
ENABLED, SILENCE_BLACK, SILENCE_FREEZE
};
struct DisabledTrack {
DisabledTrack(TrackID aTrackID, DisabledTrackMode aMode)
: mTrackID(aTrackID), mMode(aMode) {}
TrackID mTrackID;
DisabledTrackMode mMode;
};
/**
* A stream of synchronized audio and video data. All (not blocked) streams
* progress at the same rate --- "real time". Streams cannot seek. The only

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

@ -19,21 +19,6 @@ class MediaStreamGraph;
class MediaStreamVideoSink;
class VideoSegment;
enum MediaStreamGraphEvent : uint32_t {
EVENT_FINISHED,
EVENT_REMOVED,
EVENT_HAS_DIRECT_LISTENERS, // transition from no direct listeners
EVENT_HAS_NO_DIRECT_LISTENERS, // transition to no direct listeners
};
// maskable flags, not a simple enumerated value
enum TrackEventCommand : uint32_t {
TRACK_EVENT_NONE = 0x00,
TRACK_EVENT_CREATED = 0x01,
TRACK_EVENT_ENDED = 0x02,
TRACK_EVENT_UNUSED = ~(TRACK_EVENT_ENDED | TRACK_EVENT_CREATED),
};
/**
* This is a base class for media graph thread listener callbacks.
* Override methods to be notified of audio or video data or changes in stream

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

@ -6,14 +6,15 @@
#include "MediaStreamTrack.h"
#include "DOMMediaStream.h"
#include "MediaStreamError.h"
#include "MediaStreamGraph.h"
#include "MediaStreamListener.h"
#include "mozilla/dom/Promise.h"
#include "nsContentUtils.h"
#include "nsIUUIDGenerator.h"
#include "nsServiceManagerUtils.h"
#include "MediaStreamListener.h"
#include "systemservices/MediaUtils.h"
#include "mozilla/dom/Promise.h"
#ifdef LOG
#undef LOG
#endif
@ -21,6 +22,8 @@
static mozilla::LazyLogModule gMediaStreamTrackLog("MediaStreamTrack");
#define LOG(type, msg) MOZ_LOG(gMediaStreamTrackLog, type, msg)
using namespace mozilla::media;
namespace mozilla {
namespace dom {

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

@ -6,17 +6,17 @@
#ifndef MEDIASTREAMTRACK_H_
#define MEDIASTREAMTRACK_H_
#include "mozilla/DOMEventTargetHelper.h"
#include "nsError.h"
#include "nsID.h"
#include "nsIPrincipal.h"
#include "StreamTracks.h"
#include "MediaTrackConstraints.h"
#include "mozilla/CORSMode.h"
#include "PrincipalChangeObserver.h"
#include "StreamTracks.h"
#include "mozilla/CORSMode.h"
#include "mozilla/DOMEventTargetHelper.h"
#include "mozilla/dom/MediaStreamTrackBinding.h"
#include "mozilla/dom/MediaTrackSettingsBinding.h"
#include "mozilla/media/MediaUtils.h"
#include "nsError.h"
#include "nsID.h"
#include "nsIPrincipal.h"
namespace mozilla {

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

@ -0,0 +1,49 @@
/* -*- 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_MEDIASTREAMTYPES_h_
#define MOZILLA_MEDIASTREAMTYPES_h_
#include "StreamTracks.h" // for TrackID
namespace mozilla {
enum MediaStreamGraphEvent : uint32_t {
EVENT_FINISHED,
EVENT_REMOVED,
EVENT_HAS_DIRECT_LISTENERS, // transition from no direct listeners
EVENT_HAS_NO_DIRECT_LISTENERS, // transition to no direct listeners
};
// maskable flags, not a simple enumerated value
enum TrackEventCommand : uint32_t {
TRACK_EVENT_NONE = 0x00,
TRACK_EVENT_CREATED = 0x01,
TRACK_EVENT_ENDED = 0x02,
TRACK_EVENT_UNUSED = ~(TRACK_EVENT_ENDED | TRACK_EVENT_CREATED),
};
/**
* Describes how a track should be disabled.
*
* ENABLED Not disabled.
* SILENCE_BLACK Audio data is turned into silence, video frames are made black.
* SILENCE_FREEZE Audio data is turned into silence, video freezes at last frame.
*/
enum class DisabledTrackMode
{
ENABLED, SILENCE_BLACK, SILENCE_FREEZE
};
struct DisabledTrack {
DisabledTrack(TrackID aTrackID, DisabledTrackMode aMode)
: mTrackID(aTrackID), mMode(aMode) {}
TrackID mTrackID;
DisabledTrackMode mMode;
};
} // namespace mozilla
#endif // MOZILLA_MEDIASTREAMTYPES_h_

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

@ -6,13 +6,12 @@
#include "MediaTimer.h"
#include <math.h>
#include "nsComponentManagerUtils.h"
#include "nsThreadUtils.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/RefPtr.h"
#include "mozilla/SharedThreadPool.h"
#include "nsComponentManagerUtils.h"
#include "nsThreadUtils.h"
#include <math.h>
namespace mozilla {

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

@ -7,15 +7,14 @@
#if !defined(MediaTimer_h_)
#define MediaTimer_h_
#include "mozilla/AbstractThread.h"
#include "mozilla/IntegerPrintfMacros.h"
#include "mozilla/Monitor.h"
#include "mozilla/MozPromise.h"
#include "mozilla/TimeStamp.h"
#include <queue>
#include "nsITimer.h"
#include "mozilla/RefPtr.h"
#include "mozilla/TimeStamp.h"
#include "nsITimer.h"
#include <queue>
namespace mozilla {

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

@ -9,6 +9,7 @@
#include "MediaPrefs.h"
#include "mozilla/Atomics.h"
#include "mozilla/Logging.h"
#include "mozilla/Telemetry.h"
#include "prsystem.h"
namespace mozilla {

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

@ -4,26 +4,25 @@
#include "VideoUtils.h"
#include "mozilla/Base64.h"
#include "mozilla/TaskQueue.h"
#include "mozilla/Telemetry.h"
#include "ImageContainer.h"
#include "MediaContainerType.h"
#include "MediaPrefs.h"
#include "MediaResource.h"
#include "TimeUnits.h"
#include "nsMathUtils.h"
#include "nsSize.h"
#include "VorbisUtils.h"
#include "ImageContainer.h"
#include "mozilla/Base64.h"
#include "mozilla/SharedThreadPool.h"
#include "nsIRandomGenerator.h"
#include "nsIServiceManager.h"
#include "nsServiceManagerUtils.h"
#include "nsIConsoleService.h"
#include "nsThreadUtils.h"
#include "mozilla/TaskQueue.h"
#include "mozilla/Telemetry.h"
#include "nsCharSeparatedTokenizer.h"
#include "nsContentTypeParser.h"
#include "nsIConsoleService.h"
#include "nsIRandomGenerator.h"
#include "nsIServiceManager.h"
#include "nsMathUtils.h"
#include "nsServiceManagerUtils.h"
#include "nsSize.h"
#include "nsThreadUtils.h"
#include <functional>
#include <stdint.h>

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

@ -7,7 +7,10 @@
#ifndef VideoUtils_h
#define VideoUtils_h
#include "AudioSampleFormat.h"
#include "MediaInfo.h"
#include "TimeUnits.h"
#include "VideoLimits.h"
#include "mozilla/AbstractThread.h"
#include "mozilla/Attributes.h"
#include "mozilla/CheckedInt.h"
@ -15,19 +18,14 @@
#include "mozilla/ReentrantMonitor.h"
#include "mozilla/RefPtr.h"
#include "mozilla/UniquePtr.h"
#include "nsAutoPtr.h"
#include "nsCOMPtr.h"
#include "nsIThread.h"
#include "nsSize.h"
#include "nsITimer.h"
#include "nsRect.h"
#include "nsSize.h"
#include "nsThreadUtils.h"
#include "prtime.h"
#include "AudioSampleFormat.h"
#include "TimeUnits.h"
#include "nsITimer.h"
#include "nsCOMPtr.h"
#include "VideoLimits.h"
using mozilla::CheckedInt64;
using mozilla::CheckedUint64;

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