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

--HG--
rename : devtools/client/responsive.html/components/NetworkThrottlingSelector.js => devtools/client/shared/components/throttling/NetworkThrottlingSelector.js
rename : devtools/client/responsive.html/actions/network-throttling.js => devtools/client/shared/components/throttling/actions.js
rename : devtools/client/shared/network-throttling-profiles.js => devtools/client/shared/components/throttling/profiles.js
rename : devtools/client/responsive.html/reducers/network-throttling.js => devtools/client/shared/components/throttling/reducer.js
This commit is contained in:
Cosmin Sabou 2018-05-02 12:27:59 +03:00
Родитель c3e7abdb2c 01bba2c16e
Коммит 435ba6ef00
87 изменённых файлов: 1022 добавлений и 459 удалений

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

@ -6,6 +6,7 @@
#include "RootAccessibleWrap.h"
#include "Compatibility.h"
#include "mozilla/WindowsVersion.h"
#include "nsCoreUtils.h"
#include "nsWinUtils.h"
@ -155,8 +156,11 @@ RootAccessibleWrap::get_accFocus(
/* [retval][out] */ VARIANT __RPC_FAR *pvarChild)
{
HRESULT hr = DocAccessibleWrap::get_accFocus(pvarChild);
if (FAILED(hr) || pvarChild->vt != VT_EMPTY) {
// We got a definite result (either failure or an accessible).
if (FAILED(hr) || pvarChild->vt != VT_EMPTY || !IsWin8OrLater()) {
// 1. We got a definite result (either failure or an accessible); or
// 2. This is Windows 7, where we don't want to retrieve the focus from a
// remote document because this causes mysterious intermittent crashes
// when we're called by UIA clients; see bug 1424505.
return hr;
}

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

@ -213,9 +213,9 @@ gTests.push({
// since we didn't set _cleanShutdown.
let richlistbox = tagsField.popup.richlistbox;
// Focus and select first result.
Assert.ok(richlistbox.itemCount, 1, "We have 1 autocomplete result");
Assert.equal(richlistbox.itemCount, 1, "We have 1 autocomplete result");
tagsField.popup.selectedIndex = 0;
Assert.ok(richlistbox.selectedItems.length, 1,
Assert.equal(richlistbox.selectedItems.length, 1,
"We have selected a tag from the autocomplete popup");
info("About to focus the autocomplete results");
richlistbox.focus();

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

@ -20,6 +20,7 @@ da
de
dsb
el
en-CA
en-GB
en-ZA
eo

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

@ -27,6 +27,7 @@ locales = [
"de",
"dsb",
"el",
"en-CA",
"en-GB",
"en-ZA",
"eo",

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

@ -222,6 +222,13 @@
]
}
},
"en-CA": {
"default": {
"visibleDefaultEngines": [
"google", "amazon-ca", "bing", "ddg", "ebay-ca", "twitter", "wikipedia"
]
}
},
"en-GB": {
"default": {
"visibleDefaultEngines": [

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

@ -1,67 +0,0 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
include $(MOZILLA_DIR)/build/binary-location.mk
browser_path := '"$(browser_path)"'
_PROFILE_DIR = $(TARGET_DEPTH)/_profile/pgo
ABSOLUTE_TOPSRCDIR = $(abspath $(MOZILLA_DIR))
_CERTS_SRC_DIR = $(ABSOLUTE_TOPSRCDIR)/build/pgo/certs
AUTOMATION_PPARGS = \
-DBROWSER_PATH=$(browser_path) \
-DXPC_BIN_PATH='"$(DIST)/bin"' \
-DBIN_SUFFIX='"$(BIN_SUFFIX)"' \
-DPROFILE_DIR='"$(_PROFILE_DIR)"' \
-DCERTS_SRC_DIR='"$(_CERTS_SRC_DIR)"' \
-DPERL='"$(PERL)"' \
$(NULL)
ifeq ($(OS_ARCH),Darwin)
AUTOMATION_PPARGS += -DIS_MAC=1
else
AUTOMATION_PPARGS += -DIS_MAC=0
endif
ifeq ($(OS_ARCH),Linux)
AUTOMATION_PPARGS += -DIS_LINUX=1
else
AUTOMATION_PPARGS += -DIS_LINUX=0
endif
ifeq ($(host_os), cygwin)
AUTOMATION_PPARGS += -DIS_CYGWIN=1
endif
ifeq ($(ENABLE_TESTS), 1)
AUTOMATION_PPARGS += -DIS_TEST_BUILD=1
else
AUTOMATION_PPARGS += -DIS_TEST_BUILD=0
endif
ifeq ($(MOZ_DEBUG), 1)
AUTOMATION_PPARGS += -DIS_DEBUG_BUILD=1
else
AUTOMATION_PPARGS += -DIS_DEBUG_BUILD=0
endif
ifdef MOZ_CRASHREPORTER
AUTOMATION_PPARGS += -DCRASHREPORTER=1
else
AUTOMATION_PPARGS += -DCRASHREPORTER=0
endif
ifdef MOZ_ASAN
AUTOMATION_PPARGS += -DIS_ASAN=1
else
AUTOMATION_PPARGS += -DIS_ASAN=0
endif
automation.py: $(MOZILLA_DIR)/build/automation.py.in $(MOZILLA_DIR)/build/automation-build.mk
$(call py_action,preprocessor, \
$(AUTOMATION_PPARGS) $(DEFINES) $(ACDEFINES) $< -o $@)
GARBAGE += automation.py automation.pyc

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

@ -53,7 +53,6 @@ _IS_CYGWIN = False
#endif
#expand _BIN_SUFFIX = __BIN_SUFFIX__
#expand _DEFAULT_APP = "./" + __BROWSER_PATH__
#expand _CERTS_SRC_DIR = __CERTS_SRC_DIR__
#expand _IS_TEST_BUILD = __IS_TEST_BUILD__
#expand _IS_DEBUG_BUILD = __IS_DEBUG_BUILD__
@ -99,7 +98,6 @@ class Automation(object):
UNIXISH = not IS_WIN32 and not IS_MAC
DEFAULT_APP = _DEFAULT_APP
CERTS_SRC_DIR = _CERTS_SRC_DIR
IS_TEST_BUILD = _IS_TEST_BUILD
IS_DEBUG_BUILD = _IS_DEBUG_BUILD
@ -138,7 +136,6 @@ class Automation(object):
"runApp",
"Process",
"DIST_BIN",
"DEFAULT_APP",
"CERTS_SRC_DIR",
"environment",
"IS_TEST_BUILD",

48
build/gen_automation.py Normal file
Просмотреть файл

@ -0,0 +1,48 @@
# -*- 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 distibuted with this
# file, You can obtain one at http://mozilla.og/MPL/2.0/.
import sys
import buildconfig
from mozbuild.preprocessor import Preprocessor
def main(output, input_file):
pp = Preprocessor()
pp.context.update(buildconfig.defines['ALLDEFINES'])
substs = buildconfig.substs
# Substs taken verbatim.
substs_vars = (
'BIN_SUFFIX',
)
for var in substs_vars:
pp.context[var] = '"%s"' % substs[var]
# Derived values.
for key, condition in (
('IS_MAC', substs['OS_ARCH'] == 'Darwin'),
('IS_LINUX', substs['OS_ARCH'] == 'Linux'),
('IS_TEST_BUILD', substs.get('ENABLE_TESTS') == '1'),
('IS_DEBUG_BUILD', substs.get('MOZ_DEBUG') == '1'),
('CRASHREPORTER', substs.get('MOZ_CRASHREPORTER')),
('IS_ASAN', substs.get('MOZ_ASAN'))):
if condition:
pp.context[key] = '1'
else:
pp.context[key] = '0'
pp.context.update({
'XPC_BIN_PATH': '"%s/dist/bin"' % buildconfig.topobjdir,
'CERTS_SRC_DIR': '"%s/build/pgo/certs"' % buildconfig.topsrcdir,
})
pp.out = output
pp.do_include(input_file)
if __name__ == '__main__':
main(*sys.agv[1:])

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

@ -96,6 +96,20 @@ if CONFIG['MOZ_APP_BASENAME']:
appini.script = 'appini_header.py'
appini.inputs = ['!application.ini']
if CONFIG['ENABLE_TESTS']:
GENERATED_FILES += ['automation.py']
auto = GENERATED_FILES['automation.py']
auto.script = 'gen_automation.py'
auto.inputs = ['automation.py.in']
TEST_HARNESS_FILES.reftest += [
'!automation.py',
]
TEST_HARNESS_FILES.testing.mochitest += [
'!automation.py',
]
# NOTE: Keep .gdbinit in the topsrcdir for people who run gdb from the topsrcdir.
OBJDIR_FILES += ['/.gdbinit']

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

@ -0,0 +1,18 @@
# 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/.
# LOCALIZATION NOTE These strings are used inside the NetworkThrottlingSelector
# component used to throttle network bandwidth.
#
# The correct localization of this file might be to keep it in
# English, or another language commonly spoken among web developers.
# You want to make that choice consistent across the developer tools.
# A good criteria is the language in which you'd find the best
# documentation on web development on the web.
# LOCALIZATION NOTE (responsive.noThrottling): UI option in a menu to configure
# network throttling. This option is the default and disables throttling so you
# just have normal network conditions. There is not very much room in the UI
# so a short string would be best if possible.
responsive.noThrottling=No throttling

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

@ -67,12 +67,6 @@ responsive.remoteOnly=Responsive Design Mode is only available for remote browse
# container tab.
responsive.noContainerTabs=Responsive Design Mode is currently unavailable in container tabs.
# LOCALIZATION NOTE (responsive.noThrottling): UI option in a menu to configure
# network throttling. This option is the default and disables throttling so you
# just have normal network conditions. There is not very much room in the UI
# so a short string would be best if possible.
responsive.noThrottling=No throttling
# LOCALIZATION NOTE (responsive.changeDevicePixelRatio): tooltip for the
# device pixel ratio dropdown when is enabled.
responsive.changeDevicePixelRatio=Change device pixel ratio of the viewport

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

@ -94,6 +94,31 @@
margin-top: 1px;
}
/* Throttling Button */
#global-network-throttling-selector:not(:hover) {
background-color: transparent;
}
#global-network-throttling-selector:hover {
background-color: var(--toolbarbutton-background);
}
#global-network-throttling-selector {
width: 92px;
padding-right: 12px;
background-image: var(--drop-down-icon-url);
background-position: right 6px;
background-repeat: no-repeat;
fill: var(--theme-toolbar-photon-icon-color);
}
/* Make sure the Throttle button icon is vertically centered on Mac */
:root[platform="mac"] #global-network-throttling-selector {
height: 17px;
background-position-y: 5px;
}
/* Search box */
.devtools-searchbox {

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

@ -49,6 +49,11 @@ const DISABLE_CACHE_LABEL = L10N.getStr("netmonitor.toolbar.disableCache.label")
loader.lazyRequireGetter(this, "showMenu", "devtools/client/netmonitor/src/utils/menu", true);
loader.lazyRequireGetter(this, "HarMenuUtils", "devtools/client/netmonitor/src/har/har-menu-utils", true);
// Throttling
const Types = require("devtools/client/shared/components/throttling/types");
const NetworkThrottlingSelector = createFactory(require("devtools/client/shared/components/throttling/NetworkThrottlingSelector"));
const { changeNetworkThrottling } = require("devtools/client/shared/components/throttling/actions");
/**
* Network monitor toolbar component.
*
@ -80,11 +85,15 @@ class Toolbar extends Component {
singleRow: PropTypes.bool.isRequired,
// Callback for opening split console.
openSplitConsole: PropTypes.func,
networkThrottling: PropTypes.shape(Types.networkThrottling).isRequired,
// Executed when throttling changes (through toolbar button).
onChangeNetworkThrottling: PropTypes.func.isRequired,
};
}
constructor(props) {
super(props);
this.autocompleteProvider = this.autocompleteProvider.bind(this);
this.onSearchBoxFocus = this.onSearchBoxFocus.bind(this);
this.toggleRequestFilterType = this.toggleRequestFilterType.bind(this);
@ -105,6 +114,7 @@ class Toolbar extends Component {
|| this.props.recording !== nextProps.recording
|| this.props.singleRow !== nextProps.singleRow
|| !Object.is(this.props.requestFilterTypes, nextProps.requestFilterTypes)
|| this.props.networkThrottling !== nextProps.networkThrottling
// Filtered requests are useful only when searchbox is focused
|| !!(this.refs.searchbox && this.refs.searchbox.focused);
@ -261,6 +271,22 @@ class Toolbar extends Component {
);
}
/**
* Render network throttling selector button.
*/
renderThrottlingSelector() {
let {
networkThrottling,
onChangeNetworkThrottling,
} = this.props;
return NetworkThrottlingSelector({
className: "devtools-button",
networkThrottling,
onChangeNetworkThrottling,
});
}
/**
* Render drop down button with HAR related actions.
*/
@ -362,6 +388,7 @@ class Toolbar extends Component {
this.renderPersistlogCheckbox(persistentLogsEnabled, togglePersistentLogs),
this.renderCacheCheckbox(browserCacheDisabled, toggleBrowserCache),
this.renderSeparator(),
this.renderThrottlingSelector(),
this.renderHarButton(),
)
)
@ -377,6 +404,7 @@ class Toolbar extends Component {
this.renderPersistlogCheckbox(persistentLogsEnabled, togglePersistentLogs),
this.renderCacheCheckbox(browserCacheDisabled, toggleBrowserCache),
this.renderSeparator(),
this.renderThrottlingSelector(),
this.renderHarButton(),
),
span({ className: "devtools-toolbar-group devtools-toolbar-two-rows-2" },
@ -395,6 +423,7 @@ module.exports = connect(
persistentLogsEnabled: state.ui.persistentLogsEnabled,
recording: getRecordingState(state),
requestFilterTypes: state.filters.requestFilterTypes,
networkThrottling: state.networkThrottling,
}),
(dispatch) => ({
clearRequests: () => dispatch(Actions.clearRequests()),
@ -405,5 +434,7 @@ module.exports = connect(
toggleRecording: () => dispatch(Actions.toggleRecording()),
togglePersistentLogs: () => dispatch(Actions.togglePersistentLogs()),
toggleRequestFilterType: (type) => dispatch(Actions.toggleRequestFilterType(type)),
onChangeNetworkThrottling: (enabled, profile) =>
dispatch(changeNetworkThrottling(enabled, profile)),
}),
)(Toolbar);

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

@ -12,6 +12,13 @@ const { getDisplayedTimingMarker } = require("../selectors/index");
// To be removed once FF60 is deprecated
loader.lazyRequireGetter(this, "TimelineFront", "devtools/shared/fronts/timeline", true);
// Network throttling
loader.lazyRequireGetter(this, "throttlingProfiles", "devtools/client/shared/components/throttling/profiles");
loader.lazyRequireGetter(this, "EmulationFront", "devtools/shared/fronts/emulation", true);
/**
* Connector to Firefox backend.
*/
class FirefoxConnector {
constructor() {
// Public methods
@ -29,6 +36,7 @@ class FirefoxConnector {
this.viewSourceInDebugger = this.viewSourceInDebugger.bind(this);
this.requestData = this.requestData.bind(this);
this.getTimingMarker = this.getTimingMarker.bind(this);
this.updateNetworkThrottling = this.updateNetworkThrottling.bind(this);
// Internals
this.getLongString = this.getLongString.bind(this);
@ -59,6 +67,7 @@ class FirefoxConnector {
owner: this.owner,
});
// Register all listeners
await this.addListeners();
// Listener for `will-navigate` event is (un)registered outside
@ -69,6 +78,10 @@ class FirefoxConnector {
if (this.tabTarget) {
this.tabTarget.on("will-navigate", this.willNavigate);
this.tabTarget.on("navigate", this.navigate);
// Initialize Emulation front for network throttling.
const { tab } = await this.tabTarget.client.getTab();
this.emulationFront = EmulationFront(this.tabTarget.client, tab);
}
// Displaying cache events is only intended for the UI panel.
@ -84,6 +97,11 @@ class FirefoxConnector {
await this.removeListeners();
if (this.emulationFront) {
this.emulationFront.destroy();
this.emulationFront = null;
}
if (this.tabTarget) {
this.tabTarget.off("will-navigate", this.willNavigate);
this.tabTarget.off("navigate", this.navigate);
@ -412,6 +430,20 @@ class FirefoxConnector {
return getDisplayedTimingMarker(state, name);
}
async updateNetworkThrottling(enabled, profile) {
if (!enabled) {
await this.emulationFront.clearNetworkThrottling();
} else {
const data = throttlingProfiles.find(({ id }) => id == profile);
const { download, upload, latency } = data;
await this.emulationFront.setNetworkThrottling({
downloadThroughput: download,
uploadThroughput: upload,
latency,
});
}
}
/**
* Fire events for the owner object.
*/

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

@ -27,6 +27,7 @@ class Connector {
this.viewSourceInDebugger = this.viewSourceInDebugger.bind(this);
this.requestData = this.requestData.bind(this);
this.getTimingMarker = this.getTimingMarker.bind(this);
this.updateNetworkThrottling = this.updateNetworkThrottling.bind(this);
}
// Connect/Disconnect API
@ -114,6 +115,10 @@ class Connector {
getTimingMarker() {
return this.connector.getTimingMarker(...arguments);
}
updateNetworkThrottling() {
return this.connector.updateNetworkThrottling(...arguments);
}
}
module.exports.Connector = Connector;

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

@ -12,6 +12,7 @@ const batching = require("./middleware/batching");
const prefs = require("./middleware/prefs");
const thunk = require("./middleware/thunk");
const recording = require("./middleware/recording");
const throttling = require("./middleware/throttling");
// Reducers
const rootReducer = require("./reducers/index");
@ -43,7 +44,8 @@ function configureStore(connector) {
thunk,
prefs,
batching,
recording(connector)
recording(connector),
throttling(connector),
);
return createStore(rootReducer, initialState, middleware);

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

@ -6,5 +6,6 @@ DevToolsModules(
'batching.js',
'prefs.js',
'recording.js',
'throttling.js',
'thunk.js',
)

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

@ -0,0 +1,26 @@
/* 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 {
CHANGE_NETWORK_THROTTLING,
} = require("devtools/client/shared/components/throttling/actions");
/**
* Network throttling middleware is responsible for
* updating/syncing currently connected backend
* according to user actions.
*/
function throttlingMiddleware(connector) {
return store => next => action => {
const res = next(action);
if (action.type === CHANGE_NETWORK_THROTTLING) {
connector.updateNetworkThrottling(action.enabled, action.profile);
}
return res;
};
}
module.exports = throttlingMiddleware;

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

@ -11,6 +11,7 @@ const { sortReducer } = require("./sort");
const { filters } = require("./filters");
const { timingMarkers } = require("./timing-markers");
const { ui } = require("./ui");
const networkThrottling = require("devtools/client/shared/components/throttling/reducer");
module.exports = batchingReducer(
combineReducers({
@ -19,5 +20,6 @@ module.exports = batchingReducer(
filters,
timingMarkers,
ui,
networkThrottling,
})
);

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

@ -10,6 +10,10 @@
const { createEnum } = require("devtools/client/shared/enum");
const {
CHANGE_NETWORK_THROTTLING,
} = require("devtools/client/shared/components/throttling/actions");
createEnum([
// Add a new device.
@ -34,7 +38,7 @@ createEnum([
"CHANGE_DISPLAY_PIXEL_RATIO",
// Change the network throttling profile.
"CHANGE_NETWORK_THROTTLING",
CHANGE_NETWORK_THROTTLING,
// The pixel ratio of the viewport has changed. This may be triggered by the user
// when changing the device displayed in the viewport, or when a pixel ratio is

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

@ -9,7 +9,6 @@ DevToolsModules(
'display-pixel-ratio.js',
'index.js',
'location.js',
'network-throttling.js',
'reload-conditions.js',
'screenshot.js',
'touch-simulation.js',

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

@ -1,21 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const {
CHANGE_NETWORK_THROTTLING,
} = require("./index");
module.exports = {
changeNetworkThrottling(enabled, profile) {
return {
type: CHANGE_NETWORK_THROTTLING,
enabled,
profile,
};
},
};

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

@ -18,7 +18,7 @@ const {
updateDeviceModal,
updatePreferredDevices,
} = require("./actions/devices");
const { changeNetworkThrottling } = require("./actions/network-throttling");
const { changeNetworkThrottling } = require("devtools/client/shared/components/throttling/actions");
const { changeReloadCondition } = require("./actions/reload-conditions");
const { takeScreenshot } = require("./actions/screenshot");
const { changeTouchSimulation } = require("./actions/touch-simulation");
@ -92,7 +92,7 @@ class App extends Component {
onChangeNetworkThrottling(enabled, profile) {
window.postMessage({
type: "change-network-throtting",
type: "change-network-throttling",
enabled,
profile,
}, "*");

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

@ -11,7 +11,7 @@ const dom = require("devtools/client/shared/vendor/react-dom-factories");
const { getStr } = require("../utils/l10n");
const Types = require("../types");
const DevicePixelRatioSelector = createFactory(require("./DevicePixelRatioSelector"));
const NetworkThrottlingSelector = createFactory(require("./NetworkThrottlingSelector"));
const NetworkThrottlingSelector = createFactory(require("devtools/client/shared/components/throttling/NetworkThrottlingSelector"));
const ReloadConditions = createFactory(require("./ReloadConditions"));
class GlobalToolbar extends PureComponent {

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

@ -11,7 +11,6 @@ DevToolsModules(
'DevicePixelRatioSelector.js',
'DeviceSelector.js',
'GlobalToolbar.js',
'NetworkThrottlingSelector.js',
'ReloadConditions.js',
'ResizableViewport.js',
'ToggleMenu.js',

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

@ -13,7 +13,7 @@ const TOOL_URL = "chrome://devtools/content/responsive.html/index.xhtml";
loader.lazyRequireGetter(this, "DebuggerClient", "devtools/shared/client/debugger-client", true);
loader.lazyRequireGetter(this, "DebuggerServer", "devtools/server/main", true);
loader.lazyRequireGetter(this, "throttlingProfiles", "devtools/client/shared/network-throttling-profiles");
loader.lazyRequireGetter(this, "throttlingProfiles", "devtools/client/shared/components/throttling/profiles");
loader.lazyRequireGetter(this, "swapToInnerBrowser", "devtools/client/responsive.html/browser/swap", true);
loader.lazyRequireGetter(this, "startup", "devtools/client/responsive.html/utils/window", true);
loader.lazyRequireGetter(this, "message", "devtools/client/responsive.html/utils/message");
@ -516,7 +516,7 @@ ResponsiveUI.prototype = {
case "change-device":
this.onChangeDevice(event);
break;
case "change-network-throtting":
case "change-network-throttling":
this.onChangeNetworkThrottling(event);
break;
case "change-pixel-ratio":

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

@ -7,7 +7,7 @@
exports.devices = require("./reducers/devices");
exports.displayPixelRatio = require("./reducers/display-pixel-ratio");
exports.location = require("./reducers/location");
exports.networkThrottling = require("./reducers/network-throttling");
exports.networkThrottling = require("devtools/client/shared/components/throttling/reducer");
exports.reloadConditions = require("./reducers/reload-conditions");
exports.screenshot = require("./reducers/screenshot");
exports.touchSimulation = require("./reducers/touch-simulation");

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

@ -8,7 +8,6 @@ DevToolsModules(
'devices.js',
'display-pixel-ratio.js',
'location.js',
'network-throttling.js',
'reload-conditions.js',
'screenshot.js',
'touch-simulation.js',

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

@ -1,33 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const {
CHANGE_NETWORK_THROTTLING,
} = require("../actions/index");
const INITIAL_NETWORK_THROTTLING = {
enabled: false,
profile: "",
};
let reducers = {
[CHANGE_NETWORK_THROTTLING](throttling, { enabled, profile }) {
return {
enabled,
profile,
};
},
};
module.exports = function(throttling = INITIAL_NETWORK_THROTTLING, action) {
let reducer = reducers[action.type];
if (!reducer) {
return throttling;
}
return reducer(throttling, action);
};

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

@ -3,7 +3,7 @@ http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const throttlingProfiles = require("devtools/client/shared/network-throttling-profiles");
const throttlingProfiles = require("devtools/client/shared/components/throttling/profiles");
// Tests changing network throttling
const TEST_URL = "data:text/html;charset=utf-8,Network throttling test";

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

@ -7,7 +7,7 @@
const {
changeNetworkThrottling,
} = require("devtools/client/responsive.html/actions/network-throttling");
} = require("devtools/client/shared/components/throttling/actions");
add_task(async function() {
let store = Store();

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

@ -8,7 +8,8 @@ DIRS += [
'reps',
'splitter',
'tabs',
'tree'
'throttling',
'tree',
]
DevToolsModules(

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

@ -8,18 +8,33 @@ const { PureComponent } = require("devtools/client/shared/vendor/react");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const Types = require("../types");
const { getStr } = require("../utils/l10n");
const throttlingProfiles = require("devtools/client/shared/network-throttling-profiles");
const Types = require("./types");
const throttlingProfiles = require("./profiles");
// Localization
const { LocalizationHelper } = require("devtools/shared/l10n");
const L10N = new LocalizationHelper(
"devtools/client/locales/network-throttling.properties");
/**
* This component represents selector button that can be used
* to throttle network bandwidth.
*/
class NetworkThrottlingSelector extends PureComponent {
static get propTypes() {
return {
className: PropTypes.string,
networkThrottling: PropTypes.shape(Types.networkThrottling).isRequired,
onChangeNetworkThrottling: PropTypes.func.isRequired,
};
}
static get defaultProps() {
return {
className: "",
};
}
constructor(props) {
super(props);
this.onSelectChange = this.onSelectChange.bind(this);
@ -30,7 +45,7 @@ class NetworkThrottlingSelector extends PureComponent {
onChangeNetworkThrottling,
} = this.props;
if (target.value == getStr("responsive.noThrottling")) {
if (target.value == L10N.getStr("responsive.noThrottling")) {
onChangeNetworkThrottling(false, "");
return;
}
@ -45,16 +60,17 @@ class NetworkThrottlingSelector extends PureComponent {
render() {
let {
className,
networkThrottling,
} = this.props;
let selectClass = "toolbar-dropdown";
let selectClass = className + " toolbar-dropdown";
let selectedProfile;
if (networkThrottling.enabled) {
selectClass += " selected";
selectedProfile = networkThrottling.profile;
} else {
selectedProfile = getStr("responsive.noThrottling");
selectedProfile = L10N.getStr("responsive.noThrottling");
}
let listContent = [
@ -62,7 +78,7 @@ class NetworkThrottlingSelector extends PureComponent {
{
key: "disabled",
},
getStr("responsive.noThrottling")
L10N.getStr("responsive.noThrottling")
),
dom.option(
{

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

@ -0,0 +1,22 @@
/* 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 actionTypes = {
CHANGE_NETWORK_THROTTLING: "CHANGE_NETWORK_THROTTLING",
};
function changeNetworkThrottling(enabled, profile) {
return {
type: actionTypes.CHANGE_NETWORK_THROTTLING,
enabled,
profile,
};
}
module.exports = {
...actionTypes,
changeNetworkThrottling,
};

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

@ -0,0 +1,13 @@
# -*- 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(
'actions.js',
'NetworkThrottlingSelector.js',
'profiles.js',
'reducer.js',
'types.js',
)

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

@ -0,0 +1,29 @@
/* 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 {
CHANGE_NETWORK_THROTTLING,
} = require("./actions");
const INITIAL_STATE = {
enabled: false,
profile: "",
};
function throttlingReducer(state = INITIAL_STATE, action) {
switch (action.type) {
case CHANGE_NETWORK_THROTTLING: {
return {
enabled: action.enabled,
profile: action.profile
};
}
default:
return state;
}
}
module.exports = throttlingReducer;

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

@ -0,0 +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/. */
"use strict";
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
/**
* Network throttling state.
*/
exports.networkThrottling = {
// Whether or not network throttling is enabled
enabled: PropTypes.bool,
// Name of the selected throttling profile
profile: PropTypes.string,
};

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

@ -38,7 +38,6 @@ DevToolsModules(
'keycodes.js',
'link.js',
'natural-sort.js',
'network-throttling-profiles.js',
'node-attribute-parser.js',
'options-view.js',
'output-parser.js',

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

@ -2850,11 +2850,7 @@ HTMLMediaElement::Seek(double aTime,
// The media backend is responsible for dispatching the timeupdate
// event if it changes the playback position as a result of the seek.
LOG(LogLevel::Debug, ("%p SetCurrentTime(%f) starting seek", this, aTime));
nsresult rv = mDecoder->Seek(aTime, aSeekType);
if (NS_FAILED(rv)) {
aRv.Throw(rv);
return nullptr;
}
mDecoder->Seek(aTime, aSeekType);
// We changed whether we're seeking so we need to AddRemoveSelfReference.
AddRemoveSelfReference();

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

@ -510,7 +510,8 @@ MediaDecoder::Play()
}
if (IsEnded()) {
return Seek(0, SeekTarget::PrevSyncPoint);
Seek(0, SeekTarget::PrevSyncPoint);
return NS_OK;
} else if (mPlayState == PLAY_STATE_LOADING) {
mNextState = PLAY_STATE_PLAYING;
return NS_OK;
@ -520,7 +521,7 @@ MediaDecoder::Play()
return NS_OK;
}
nsresult
void
MediaDecoder::Seek(double aTime, SeekTarget::Type aSeekType)
{
MOZ_ASSERT(NS_IsMainThread());
@ -540,7 +541,6 @@ MediaDecoder::Seek(double aTime, SeekTarget::Type aSeekType)
if (mPlayState == PLAY_STATE_ENDED) {
ChangeState(GetOwner()->GetPaused() ? PLAY_STATE_PAUSED : PLAY_STATE_PLAYING);
}
return NS_OK;
}
void

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

@ -134,7 +134,7 @@ public:
// Seek to the time position in (seconds) from the start of the video.
// If aDoFastSeek is true, we'll seek to the sync point/keyframe preceeding
// the seek target.
virtual nsresult Seek(double aTime, SeekTarget::Type aSeekType);
void Seek(double aTime, SeekTarget::Type aSeekType);
// Initialize state machine and schedule it.
nsresult InitializeStateMachine();

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

@ -3522,18 +3522,25 @@ MediaFormatReader::GetMozDebugReaderData(nsACString& aString)
audioDecoderName = mAudio.mDecoder
? mAudio.mDecoder->GetDescriptionName()
: mAudio.mDescription;
audioType = mInfo.mAudio.mMimeType;
audioType = mAudio.mInfo ? mAudio.mInfo->mMimeType : mInfo.mAudio.mMimeType;
}
if (HasVideo()) {
MutexAutoLock mon(mVideo.mMutex);
videoDecoderName = mVideo.mDecoder
? mVideo.mDecoder->GetDescriptionName()
: mVideo.mDescription;
videoType = mInfo.mVideo.mMimeType;
videoType = mVideo.mInfo ? mVideo.mInfo->mMimeType : mInfo.mVideo.mMimeType;
}
result += nsPrintfCString(
"Audio Decoder(%s): %s\n", audioType.get(), audioDecoderName.get());
result +=
nsPrintfCString("Audio Decoder(%s, %u channels @ %0.1fkHz): %s\n",
audioType.get(),
mAudio.mInfo ? mAudio.mInfo->GetAsAudioInfo()->mChannels
: mInfo.mAudio.mChannels,
(mAudio.mInfo ? mAudio.mInfo->GetAsAudioInfo()->mRate
: mInfo.mAudio.mRate) /
1000.0f,
audioDecoderName.get());
result += nsPrintfCString("Audio Frames Decoded: %" PRIu64 "\n",
mAudio.mNumSamplesOutputTotal);
if (HasAudio()) {

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

@ -418,6 +418,12 @@ MediaSource::Enabled(JSContext* cx, JSObject* aGlobal)
return Preferences::GetBool("media.mediasource.enabled");
}
/* static */ bool
MediaSource::ExperimentalEnabled(JSContext* cx, JSObject* aGlobal)
{
return Preferences::GetBool("media.mediasource.experimental.enabled");
}
void
MediaSource::SetLiveSeekableRange(double aStart, double aEnd, ErrorResult& aRv)
{

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

@ -79,6 +79,7 @@ public:
static nsresult IsTypeSupported(const nsAString& aType, DecoderDoctorDiagnostics* aDiagnostics);
static bool Enabled(JSContext* cx, JSObject* aGlobal);
static bool ExperimentalEnabled(JSContext* cx, JSObject* aGlobal);
IMPL_EVENT_HANDLER(sourceopen);
IMPL_EVENT_HANDLER(sourceended);

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

@ -297,6 +297,53 @@ SourceBuffer::RangeRemoval(double aStart, double aEnd)
->Track(mPendingRemoval);
}
void
SourceBuffer::ChangeType(const nsAString& aType, ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread());
DecoderDoctorDiagnostics diagnostics;
nsresult rv = MediaSource::IsTypeSupported(aType, &diagnostics);
diagnostics.StoreFormatDiagnostics(mMediaSource->GetOwner()
? mMediaSource->GetOwner()->GetExtantDoc()
: nullptr,
aType, NS_SUCCEEDED(rv), __func__);
MSE_API("ChangeType(aType=%s)%s",
NS_ConvertUTF16toUTF8(aType).get(),
rv == NS_OK ? "" : " [not supported]");
if (NS_FAILED(rv)) {
DDLOG(DDLogCategory::API, "ChangeType", rv);
aRv.Throw(rv);
return;
}
if (!mMediaSource->GetDecoder() ||
mMediaSource->GetDecoder()->OwnerHasError()) {
MSE_DEBUG("HTMLMediaElement.error is not null");
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return;
}
if (!IsAttached() || mUpdating) {
DDLOG(DDLogCategory::API, "ChangeType", NS_ERROR_DOM_INVALID_STATE_ERR);
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return;
}
MOZ_ASSERT(mMediaSource->ReadyState() != MediaSourceReadyState::Closed);
if (mMediaSource->ReadyState() == MediaSourceReadyState::Ended) {
mMediaSource->SetReadyState(MediaSourceReadyState::Open);
}
if (mCurrentAttributes.GetAppendState() == AppendState::PARSING_MEDIA_SEGMENT){
DDLOG(DDLogCategory::API, "ChangeType", NS_ERROR_DOM_INVALID_STATE_ERR);
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return;
}
Maybe<MediaContainerType> containerType = MakeMediaContainerType(aType);
MOZ_ASSERT(containerType);
mType = *containerType;
ResetParserState();
mTrackBuffersManager->ChangeType(mType);
}
void
SourceBuffer::Detach()
{

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

@ -93,6 +93,8 @@ public:
void Remove(double aStart, double aEnd, ErrorResult& aRv);
void ChangeType(const nsAString& aType, ErrorResult& aRv);
IMPL_EVENT_HANDLER(updatestart);
IMPL_EVENT_HANDLER(update);
IMPL_EVENT_HANDLER(updateend);
@ -183,7 +185,7 @@ private:
MozPromiseRequestHolder<SourceBufferTask::AppendPromise> mPendingAppend;
MozPromiseRequestHolder<SourceBufferTask::RangeRemovalPromise> mPendingRemoval;
const MediaContainerType mType;
MediaContainerType mType;
RefPtr<TimeRanges> mBuffered;

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

@ -24,7 +24,8 @@ public:
Reset,
RangeRemoval,
EvictData,
Detach
Detach,
ChangeType
};
typedef Pair<bool, SourceBufferAttributes> AppendBufferResult;
@ -112,6 +113,20 @@ public:
const char* GetTypeName() const override { return "Detach"; }
};
class ChangeTypeTask : public SourceBufferTask {
public:
explicit ChangeTypeTask(const MediaContainerType& aType)
: mType(aType)
{
}
static const Type sType = Type::ChangeType;
Type GetType() const override { return Type::ChangeType; }
const char* GetTypeName() const override { return "ChangeType"; }
const MediaContainerType mType;
};
} // end mozilla namespace
#endif

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

@ -111,6 +111,7 @@ TrackBuffersManager::TrackBuffersManager(MediaSourceDecoder* aParentDecoder,
: mInputBuffer(new MediaByteBuffer)
, mBufferFull(false)
, mFirstInitializationSegmentReceived(false)
, mChangeTypeReceived(false)
, mNewMediaSegmentStarted(false)
, mActiveTrack(false)
, mType(aType)
@ -280,6 +281,14 @@ TrackBuffersManager::ProcessTasks()
ShutdownDemuxers();
ResetTaskQueue();
return;
case Type::ChangeType:
MOZ_RELEASE_ASSERT(!mCurrentTask);
mType = task->As<ChangeTypeTask>()->mType;
mChangeTypeReceived = true;
mInitData = nullptr;
CompleteResetParserState();
CreateDemuxerforMIMEType();
break;
default:
NS_WARNING("Invalid Task");
}
@ -385,6 +394,15 @@ TrackBuffersManager::EvictData(const TimeUnit& aPlaybackTime, int64_t aSize)
return result;
}
void
TrackBuffersManager::ChangeType(const MediaContainerType& aType)
{
MOZ_ASSERT(NS_IsMainThread());
QueueTask(new ChangeTypeTask(aType));
}
TimeIntervals
TrackBuffersManager::Buffered() const
{
@ -475,10 +493,13 @@ TrackBuffersManager::CompleteResetParserState()
}
// We could be left with a demuxer in an unusable state. It needs to be
// recreated. We store in the InputBuffer an init segment which will be parsed
// during the next Segment Parser Loop and a new demuxer will be created and
// initialized.
if (mFirstInitializationSegmentReceived) {
// recreated. Unless we have a pending changeType operation, we store in the
// InputBuffer an init segment which will be parsed during the next Segment
// Parser Loop and a new demuxer will be created and initialized.
// If we are in the middle of a changeType operation, then we do not have an
// init segment yet. The next appendBuffer operation will need to provide such
// init segment.
if (mFirstInitializationSegmentReceived && !mChangeTypeReceived) {
MOZ_ASSERT(mInitData && mInitData->Length(), "we must have an init segment");
// The aim here is really to destroy our current demuxer.
CreateDemuxerforMIMEType();
@ -486,8 +507,10 @@ TrackBuffersManager::CompleteResetParserState()
// to mInputBuffer as it will get modified in the Segment Parser Loop.
mInputBuffer = new MediaByteBuffer;
mInputBuffer->AppendElements(*mInitData);
RecreateParser(true);
} else {
RecreateParser(false);
}
RecreateParser(true);
}
int64_t
@ -721,7 +744,7 @@ TrackBuffersManager::SegmentParserLoop()
MediaResult haveInitSegment = mParser->IsInitSegmentPresent(mInputBuffer);
if (NS_SUCCEEDED(haveInitSegment)) {
SetAppendState(AppendState::PARSING_INIT_SEGMENT);
if (mFirstInitializationSegmentReceived) {
if (mFirstInitializationSegmentReceived && !mChangeTypeReceived) {
// This is a new initialization segment. Obsolete the old one.
RecreateParser(false);
}
@ -772,8 +795,12 @@ TrackBuffersManager::SegmentParserLoop()
return;
}
if (mSourceBufferAttributes->GetAppendState() == AppendState::PARSING_MEDIA_SEGMENT) {
// 1. If the first initialization segment received flag is false, then run the append error algorithm with the decode error parameter set to true and abort this algorithm.
if (!mFirstInitializationSegmentReceived) {
// 1. If the first initialization segment received flag is false, then run
// the append error algorithm with the decode error parameter set to
// true and abort this algorithm.
// Or we are in the process of changeType, in which case we must first
// get an init segment before getting a media segment.
if (!mFirstInitializationSegmentReceived || mChangeTypeReceived) {
RejectAppend(NS_ERROR_FAILURE, __func__);
return;
}
@ -1108,13 +1135,17 @@ TrackBuffersManager::OnDemuxerInitDone(const MediaResult& aResult)
if (mFirstInitializationSegmentReceived) {
if (numVideos != mVideoTracks.mNumTracks ||
numAudios != mAudioTracks.mNumTracks ||
(numVideos && info.mVideo.mMimeType != mVideoTracks.mInfo->mMimeType) ||
(numAudios && info.mAudio.mMimeType != mAudioTracks.mInfo->mMimeType)) {
(!mChangeTypeReceived &&
((numVideos &&
info.mVideo.mMimeType != mVideoTracks.mInfo->mMimeType) ||
(numAudios &&
info.mAudio.mMimeType != mAudioTracks.mInfo->mMimeType)))) {
RejectAppend(NS_ERROR_FAILURE, __func__);
return;
}
// 1. If more than one track for a single type are present (ie 2 audio tracks),
// then the Track IDs match the ones in the first initialization segment.
// 1. If more than one track for a single type are present (ie 2 audio
// tracks), then the Track IDs match the ones in the first initialization
// segment.
// TODO
// 2. Add the appropriate track descriptions from this initialization
// segment to each of the track buffers.
@ -1214,6 +1245,9 @@ TrackBuffersManager::OnDemuxerInitDone(const MediaResult& aResult)
mVideoTracks.mLastInfo = new TrackInfoSharedPtr(info.mVideo, streamID);
}
// We have now completed the changeType operation.
mChangeTypeReceived = false;
UniquePtr<EncryptionInfo> crypto = mInputDemuxer->GetCrypto();
if (crypto && crypto->IsEncrypted()) {
// Try and dispatch 'encrypted'. Won't go if ready state still HAVE_NOTHING.

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

@ -115,6 +115,9 @@ public:
// and if still more space is needed remove from the end.
EvictDataResult EvictData(const media::TimeUnit& aPlaybackTime, int64_t aSize);
// Queue a task to run ChangeType
void ChangeType(const MediaContainerType& aType);
// Returns the buffered range currently managed.
// This may be called on any thread.
// Buffered must conform to http://w3c.github.io/media-source/index.html#widl-SourceBuffer-buffered
@ -205,10 +208,11 @@ private:
// Accessed on both the main thread and the task queue.
Atomic<bool> mBufferFull;
bool mFirstInitializationSegmentReceived;
bool mChangeTypeReceived;
// Set to true once a new segment is started.
bool mNewMediaSegmentStarted;
bool mActiveTrack;
const MediaContainerType mType;
MediaContainerType mType;
// ContainerParser objects and methods.
// Those are used to parse the incoming input buffer.

Двоичные данные
dom/media/mediasource/test/bipbop/bipbop_300-3s.webm Normal file

Двоичный файл не отображается.

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

@ -0,0 +1 @@
Cache-Control: no-store

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

@ -4,6 +4,7 @@ support-files =
mediasource.js
seek.webm seek.webm^headers^
seek_lowres.webm seek_lowres.webm^headers^
bipbop/bipbop_300-3s.webm bipbop/bipbop_300-3s.webm^headers^
bipbop/bipbop2s.mp4 bipbop/bipbop2s.mp4^headers^
bipbop/bipbopinit.mp4 bipbop/bipbop_audioinit.mp4 bipbop/bipbop_videoinit.mp4
bipbop/bipbop1.m4s bipbop/bipbop_audio1.m4s bipbop/bipbop_video1.m4s
@ -63,6 +64,8 @@ skip-if = toolkit == 'android' # Not supported on android
skip-if = toolkit == 'android' #timeout android bug 1199531
[test_BufferingWait_mp4.html]
skip-if = toolkit == 'android' # Not supported on android
[test_ChangeType.html]
skip-if = toolkit == 'android' # Not supported on android
[test_ChangeWhileWaitingOnMissingData_mp4.html]
skip-if = toolkit == 'android' # Not supported on android
[test_DrainOnMissingData_mp4.html]

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

@ -0,0 +1,88 @@
<!DOCTYPE html>
<html><head>
<meta http-equiv="content-type" content="text/html; charset=windows-1252">
<title>MSE: changeType allow to change container and codec type</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="mediasource.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<pre id="test"><script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
async function setupTest() {
await SpecialPowers.pushPrefEnv({'set': [['media.mediasource.experimental.enabled', true]]});
}
setupTest();
runWithMSE(function(ms, el) {
el.controls = true;
once(ms, 'sourceopen').then(function() {
// Log events for debugging.
var events = ["suspend", "play", "canplay", "canplaythrough", "loadstart", "loadedmetadata",
"loadeddata", "playing", "ended", "error", "stalled", "emptied", "abort",
"waiting", "pause", "durationchange", "seeking", "seeked"];
function logEvent(e) {
info("got " + e.type + " event");
}
events.forEach(function(e) {
el.addEventListener(e, logEvent);
});
ok(true, "Receive a sourceopen event");
var videosb = ms.addSourceBuffer("video/mp4");
if (typeof videosb.changeType === 'undefined') {
info('changeType API is not available');
}
el.addEventListener("error", function(e) {
ok(false, "should not fire '" + e.type + "' event");
SimpleTest.finish();
});
is(el.readyState, el.HAVE_NOTHING, "readyState is HAVE_NOTHING");
var promises = [];
promises.push(fetchAndLoad(videosb, 'bipbop/bipbop', ['init'], '.mp4'));
promises.push(once(el, 'loadedmetadata'));
Promise.all(promises)
.then(function() {
ok(true, "got loadedmetadata event");
var promises = [];
promises.push(once(el, 'loadeddata'));
promises.push(once(el, 'canplay'));
promises.push(fetchAndLoad(videosb, 'bipbop/bipbop', range(1,3), '.m4s'));
return Promise.all(promises);
})
.then(function() {
ok(true, "got canplay event");
el.play();
videosb.timestampOffset = el.buffered.end(0);
return fetchAndLoad(videosb, 'bipbop/bipbop_480_624kbps-video', ['init'], '.mp4');
})
.then(fetchAndLoad.bind(null, videosb, 'bipbop/bipbop_480_624kbps-video', range(1,3), '.m4s'))
.then(function() {
videosb.timestampOffset = el.buffered.end(0);
try {
videosb.changeType("video/webm");
} catch (e) {
ok(false, "shouldn't throw an exception");
SimpleTest.finish();
throw e;
}
return fetchAndLoad(videosb, 'bipbop/bipbop_300-3s', [''], '.webm');
})
.then(function() {
ms.endOfStream();
return once(el, 'ended');
})
.then(function() {
ok(el.currentTime >= el.buffered.end(0), "played to the end");
SimpleTest.finish();
});
});
});
</script>
</pre>
</body>
</html>

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

@ -146,7 +146,7 @@ public:
ConstantSourceNode::ConstantSourceNode(AudioContext* aContext)
: AudioScheduledSourceNode(aContext,
1,
2,
ChannelCountMode::Max,
ChannelInterpretation::Speakers)
, mOffset(new AudioParam(this, ConstantSourceNodeEngine::OFFSET,

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

@ -46,4 +46,8 @@ interface SourceBuffer : EventTarget {
void abort();
[Throws]
void remove(double start, unrestricted double end);
// Experimental function as proposed in:
// https://github.com/w3c/media-source/issues/155
[Throws, Func="mozilla::dom::MediaSource::ExperimentalEnabled"]
void changeType(DOMString type);
};

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

@ -424,7 +424,7 @@ bool Pickle::ExtractBuffers(PickleIterator* iter, size_t length, BufferList* buf
DCHECK(alignment == 4 || alignment == 8);
DCHECK(intptr_t(header_) % alignment == 0);
if (AlignInt(length) < length) {
if (AlignInt(length) < length || iter->iter_.Done()) {
return false;
}

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

@ -354,6 +354,49 @@ SentinelReadError(const char* aClassName)
MOZ_CRASH_UNSAFE_PRINTF("incorrect sentinel when reading %s", aClassName);
}
void
StateTransition(bool aIsDelete, State* aNext)
{
switch (*aNext) {
case State::Null:
if (aIsDelete) {
*aNext = State::Dead;
}
break;
case State::Dead:
LogicError("__delete__()d actor");
break;
default:
LogicError("corrupted actor state");
break;
}
}
void
ReEntrantDeleteStateTransition(bool aIsDelete,
bool aIsDeleteReply,
ReEntrantDeleteState* aNext)
{
switch (*aNext) {
case ReEntrantDeleteState::Null:
if (aIsDelete) {
*aNext = ReEntrantDeleteState::Dying;
}
break;
case ReEntrantDeleteState::Dead:
LogicError("__delete__()d actor");
break;
case ReEntrantDeleteState::Dying:
if (aIsDeleteReply) {
*aNext = ReEntrantDeleteState::Dead;
}
break;
default:
LogicError("corrupted actor state");
break;
}
}
void
TableToArray(const nsTHashtable<nsPtrHashKey<void>>& aTable,
nsTArray<void*>& aArray)

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

@ -131,6 +131,7 @@ enum RacyInterruptPolicy {
RIPParentWins
};
class IToplevelProtocol;
class IProtocol : public HasResultCodes
@ -749,6 +750,29 @@ DuplicateHandle(HANDLE aSourceHandle,
*/
void AnnotateSystemError();
enum class State
{
Dead,
Null,
Start = Null
};
void
StateTransition(bool aIsDelete, State* aNext);
enum class ReEntrantDeleteState
{
Dead,
Null,
Dying,
Start = Null,
};
void
ReEntrantDeleteStateTransition(bool aIsDelete,
bool aIsDeleteReply,
ReEntrantDeleteState* aNext);
/**
* An endpoint represents one end of a partially initialized IPDL channel. To
* set up a new top-level protocol:

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

@ -138,28 +138,6 @@ def _backstagePass():
def _iterType(ptr):
return Type('PickleIterator', ptr=ptr)
def _nullState(proto=None):
pfx = ''
if proto is not None: pfx = proto.name() +'::'
return ExprVar(pfx +'__Null')
def _deadState(proto=None):
pfx = ''
if proto is not None: pfx = proto.name() +'::'
return ExprVar(pfx +'__Dead')
def _dyingState(proto=None):
pfx = ''
if proto is not None: pfx = proto.name() +'::'
return ExprVar(pfx +'__Dying')
def _startState(proto=None, fq=False):
pfx = ''
if proto:
if fq: pfx = proto.fullname() +'::'
else: pfx = proto.name() +'::'
return ExprVar(pfx +'__Start')
def _deleteId():
return ExprVar('Msg___delete____ID')
@ -1077,6 +1055,17 @@ def _subtreeUsesShmem(p):
return True
return False
def _stateType(hasReentrantDelete):
if hasReentrantDelete:
return Type('mozilla::ipc::ReEntrantDeleteState')
else:
return Type('mozilla::ipc::State')
def _startState(hasReentrantDelete):
pfx = _stateType(hasReentrantDelete).name + '::'
return ExprVar(pfx + 'Start')
class Protocol(ipdl.ast.Protocol):
def cxxTypedefs(self):
return self.decl.cxxtypedefs
@ -1197,16 +1186,23 @@ class Protocol(ipdl.ast.Protocol):
return ExprVar('mState')
def fqStateType(self):
return Type(self.decl.type.name() +'::State')
return _stateType(self.decl.type.hasReentrantDelete)
def startState(self):
return _startState(self.decl.type)
return _startState(self.decl.type.hasReentrantDelete)
def nullState(self):
return _nullState(self.decl.type)
pfx = self.fqStateType().name + '::'
return ExprVar(pfx + 'Null')
def deadState(self):
return _deadState(self.decl.type)
pfx = self.fqStateType().name + '::'
return ExprVar(pfx + 'Dead')
def dyingState(self):
assert self.decl.type.hasReentrantDelete
pfx = self.fqStateType().name + '::'
return ExprVar(pfx + 'Dying')
def managerVar(self, thisexpr=None):
assert thisexpr is not None or not self.decl.type.isToplevel()
@ -1570,26 +1566,10 @@ class _GenerateProtocolCode(ipdl.ast.Visitor):
ns.addstmts([ edecl, Whitespace.NL ])
self.funcDefns.append(edefn)
# state information
stateenum = TypeEnum('State')
# NB: __Dead is the first state on purpose, so that it has
# value '0'
stateenum.addId(_deadState().name)
stateenum.addId(_nullState().name)
if self.protocol.decl.type.hasReentrantDelete:
stateenum.addId(_dyingState().name)
stateenum.addId(_startState().name, _nullState().name)
ns.addstmts([ StmtDecl(Decl(stateenum,'')), Whitespace.NL ])
# spit out message type enum and classes
msgenum = msgenums(self.protocol)
ns.addstmts([ StmtDecl(Decl(msgenum, '')), Whitespace.NL ])
tfDecl, tfDefn = _splitFuncDeclDefn(self.genTransitionFunc())
ns.addstmts([ tfDecl, Whitespace.NL ])
self.funcDefns.append(tfDefn)
for md in p.messageDecls:
decls = []
@ -1645,62 +1625,6 @@ class _GenerateProtocolCode(ipdl.ast.Visitor):
return openfunc
def genTransitionFunc(self):
ptype = self.protocol.decl.type
# bool Transition(MessageType msg, State* next)
# The state we are transitioning from is stored in *next.
msgtypevar = ExprVar('msg')
nextvar = ExprVar('next')
transitionfunc = FunctionDefn(FunctionDecl(
'Transition',
params=[ Decl(Type('MessageType'), msgtypevar.name),
Decl(Type('State', ptr=1), nextvar.name) ],
ret=Type.VOID))
fromswitch = StmtSwitch(ExprDeref(nextvar))
# special case for Null
nullerrorblock = Block()
if ptype.hasDelete:
ifdelete = StmtIf(ExprBinary(_deleteId(), '==', msgtypevar))
if ptype.hasReentrantDelete:
nextState = _dyingState()
else:
nextState = _deadState()
ifdelete.addifstmt(
StmtExpr(ExprAssn(ExprDeref(nextvar), nextState)))
nullerrorblock.addstmt(ifdelete)
nullerrorblock.addstmt(StmtBreak())
fromswitch.addcase(CaseLabel(_nullState().name), nullerrorblock)
# special case for Dead
deadblock = Block()
deadblock.addstmts([
_logicError('__delete__()d actor'),
StmtBreak() ])
fromswitch.addcase(CaseLabel(_deadState().name), deadblock)
# special case for Dying
if ptype.hasReentrantDelete:
dyingblock = Block()
ifdelete = StmtIf(ExprBinary(_deleteReplyId(), '==', msgtypevar))
ifdelete.addifstmt(
StmtExpr(ExprAssn(ExprDeref(nextvar), _deadState())))
dyingblock.addstmt(ifdelete)
dyingblock.addstmt(StmtBreak())
fromswitch.addcase(CaseLabel(_dyingState().name), dyingblock)
unreachedblock = Block()
unreachedblock.addstmts([
_logicError('corrupted actor state'),
StmtBreak() ])
fromswitch.addcase(DefaultLabel(), unreachedblock)
transitionfunc.addstmt(fromswitch)
return transitionfunc
##--------------------------------------------------
@ -3061,6 +2985,9 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
self.hdrfile.addthings([
CppDirective('include', '"mozilla/ipc/MessageChannel.h"'),
Whitespace.NL ])
self.hdrfile.addthings([
CppDirective('include', '"mozilla/ipc/ProtocolUtils.h"'),
Whitespace.NL ])
hasAsyncReturns = False
for md in p.messageDecls:
@ -3127,8 +3054,6 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
self.cls.addstmt(Whitespace.NL)
self.cls.addstmts([ Typedef(p.fqStateType(), 'State'), Whitespace.NL ])
if hasAsyncReturns:
self.cls.addstmt(Label.PUBLIC)
for md in p.messageDecls:
@ -3400,7 +3325,7 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
if ptype.hasReentrantDelete:
msgVar = ExprVar(params[0].name)
ifdying = StmtIf(ExprBinary(
ExprBinary(ExprVar('mState'), '==', _dyingState(ptype)),
ExprBinary(ExprVar('mState'), '==', self.protocol.dyingState()),
'&&',
ExprBinary(
ExprBinary(ExprCall(ExprSelect(msgVar, '.', 'is_reply')), '!=', ExprLiteral.TRUE),
@ -3619,7 +3544,7 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
self.cls.addstmts([ deallocself, Whitespace.NL ])
## private members
self.cls.addstmt(StmtDecl(Decl(Type('State'), p.stateVar().name)))
self.cls.addstmt(StmtDecl(Decl(self.protocol.fqStateType(), p.stateVar().name)))
for managed in ptype.manages:
self.cls.addstmts([
@ -3902,7 +3827,7 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
self.side),
actorvar)),
StmtExpr(ExprAssn(_actorState(actorvar),
_startState(actorproto, fq=1)))
_startState(md.decl.type.cdtype.hasReentrantDelete)))
]
def failCtorIf(self, md, cond):
@ -4703,13 +4628,28 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
return idvar, saveIdStmts
def transition(self, md, actor=None, reply=False):
if actor is not None: stateexpr = _actorState(actor)
else: stateexpr = self.protocol.stateVar()
msgid = md.pqMsgId() if not reply else md.pqReplyId()
return [ StmtExpr(ExprCall(ExprVar(self.protocol.name +'::Transition'),
args=[ ExprVar(msgid),
ExprAddrOf(stateexpr) ])) ]
args = [
ExprVar('true' if _deleteId().name == msgid else 'false'),
]
if self.protocol.decl.type.hasReentrantDelete:
function = 'ReEntrantDeleteStateTransition'
args.append(
ExprVar('true' if _deleteReplyId().name == msgid else 'false'),
)
else:
function = 'StateTransition'
if actor is not None:
stateexpr = _actorState(actor)
else:
stateexpr = self.protocol.stateVar()
args.append(ExprAddrOf(stateexpr))
return [
StmtExpr(ExprCall(ExprVar(function), args=args))
]
def endRead(self, msgexpr, iterexpr):
msgtype = ExprCall(ExprSelect(msgexpr, '.', 'type'), [ ])

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

@ -263,9 +263,9 @@ var XPCOMUtils = {
* @param aServices
* An object with a property for each service to be
* imported, where the property name is the name of the
* symbol to define, and the value is a 2-element array
* containing the contract ID and the interface name of the
* service, as passed to defineLazyServiceGetter.
* symbol to define, and the value is a 1 or 2 element array
* containing the contract ID and, optionally, the interface
* name of the service, as passed to defineLazyServiceGetter.
*/
defineLazyServiceGetters: function XPCU_defineLazyServiceGetters(
aObject, aServices)
@ -274,7 +274,7 @@ var XPCOMUtils = {
// Note: This is hot code, and cross-compartment array wrappers
// are not JIT-friendly to destructuring or spread operators, so
// we need to use indexed access instead.
this.defineLazyServiceGetter(aObject, name, service[0], service[1]);
this.defineLazyServiceGetter(aObject, name, service[0], service[1] || null);
}
},

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

@ -7,10 +7,6 @@ _DEST_DIR = $(DEPTH)/_tests/reftest
include $(topsrcdir)/config/rules.mk
# We're installing to _tests/reftest
TARGET_DEPTH = ../..
include $(topsrcdir)/build/automation-build.mk
# copy harness and the reftest extension bits to $(_DEST_DIR)
# This needs to happen after jar.mn handling from rules.mk included above.
# The order of the :: rules ensures that.

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

@ -14,9 +14,7 @@ JAR_MANIFESTS += ['jar.mn']
FINAL_TARGET_PP_FILES += ['install.rdf']
FINAL_TARGET_FILES += ['bootstrap.js']
GENERATED_FILES += ['automation.py']
TEST_HARNESS_FILES.reftest += [
'!automation.py',
'/build/mobile/remoteautomation.py',
'/build/pgo/server-locations.txt',
'/testing/mochitest/server.js',

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

@ -551,6 +551,9 @@ pref("media.mediasource.webm.enabled", true);
#endif
pref("media.mediasource.webm.audio.enabled", true);
// Whether to enable MediaSource v2 support.
pref("media.mediasource.experimental.enabled", false);
pref("media.benchmark.vp9.threshold", 150);
pref("media.benchmark.frames", 300);
pref("media.benchmark.timeout", 1000);

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

@ -21,6 +21,7 @@ class FreeBSDBootstrapper(BaseBootstrapper):
'npm',
'pkgconf',
'py%s%s-sqlite3' % sys.version_info[0:2],
'python3',
'rust',
'watchman',
'zip',

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

@ -40,7 +40,10 @@ from ..frontend.data import (
ObjdirFiles,
PerSourceFlag,
Program,
SimpleProgram,
HostLibrary,
HostProgram,
HostSimpleProgram,
SharedLibrary,
Sources,
StaticLibrary,
@ -53,6 +56,7 @@ from ..util import (
from ..frontend.context import (
AbsolutePath,
ObjDirPath,
RenamedSourcePath,
)
@ -79,9 +83,19 @@ class BackendTupfile(object):
self.variables = {}
self.static_lib = None
self.shared_lib = None
self.program = None
self.programs = []
self.host_programs = []
self.host_library = None
self.exports = set()
# These files are special, ignore anything that generates them or
# depends on them.
self._skip_files = [
'signmar',
'libxul.so',
'libtestcrasher.so',
]
self.fh = FileAvoidWrite(self.name, capture_diff=True, dry_run=dry_run)
self.fh.write('# THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT.\n')
self.fh.write('\n')
@ -98,6 +112,11 @@ class BackendTupfile(object):
extra_inputs=None, extra_outputs=None, check_unchanged=False):
inputs = inputs or []
outputs = outputs or []
for f in inputs + outputs:
if any(f.endswith(skip_file) for skip_file in self._skip_files):
return
display = display or ""
self.include_rules()
flags = ""
@ -206,11 +225,17 @@ class TupBackend(CommonBackend):
self._backend_files = {}
self._cmd = MozbuildObject.from_environment()
self._manifest_entries = OrderedDefaultDict(set)
self._compile_env_gen_files = (
# These are a hack to approximate things that are needed for the
# compile phase.
self._compile_env_files = (
'*.api',
'*.c',
'*.cfg',
'*.cpp',
'*.h',
'*.inc',
'*.msg',
'*.py',
'*.rs',
)
@ -283,9 +308,6 @@ class TupBackend(CommonBackend):
def _gen_shared_library(self, backend_file):
shlib = backend_file.shared_lib
if shlib.name == 'libxul.so':
# This will fail to link currently due to missing rust symbols.
return
if shlib.cxx_link:
mkshlib = (
@ -313,9 +335,6 @@ class TupBackend(CommonBackend):
list_file = self._make_list_file(backend_file.objdir, objs, list_file_name)
inputs = objs + static_libs + shared_libs
if any(i.endswith('libxul.so') for i in inputs):
# Don't attempt to link anything that depends on libxul.
return
symbols_file = []
if shlib.symbols_file:
@ -345,23 +364,27 @@ class TupBackend(CommonBackend):
shlib.install_target,
shlib.lib_name))
def _gen_programs(self, backend_file):
for p in backend_file.programs:
self._gen_program(backend_file, p)
def _gen_program(self, backend_file):
cc_or_cxx = 'CXX' if backend_file.program.cxx_link else 'CC'
objs, _, shared_libs, os_libs, static_libs = self._expand_libs(backend_file.program)
def _gen_program(self, backend_file, prog):
cc_or_cxx = 'CXX' if prog.cxx_link else 'CC'
objs, _, shared_libs, os_libs, static_libs = self._expand_libs(prog)
static_libs = self._lib_paths(backend_file.objdir, static_libs)
shared_libs = self._lib_paths(backend_file.objdir, shared_libs)
inputs = objs + static_libs + shared_libs
if any(i.endswith('libxul.so') for i in inputs):
# Don't attempt to link anything that depends on libxul.
return
list_file_name = '%s.list' % backend_file.program.name.replace('.', '_')
list_file_name = '%s.list' % prog.name.replace('.', '_')
list_file = self._make_list_file(backend_file.objdir, objs, list_file_name)
outputs = [mozpath.relpath(backend_file.program.output_path.full_path,
backend_file.objdir)]
if isinstance(prog, SimpleProgram):
outputs = [prog.name]
else:
outputs = [mozpath.relpath(prog.output_path.full_path,
backend_file.objdir)]
cmd = (
[backend_file.environment.substs[cc_or_cxx], '-o', '%o'] +
backend_file.local_flags['CXX_LDFLAGS'] +
@ -381,6 +404,57 @@ class TupBackend(CommonBackend):
)
def _gen_host_library(self, backend_file):
objs = backend_file.host_library.objs
inputs = objs
outputs = [backend_file.host_library.name]
cmd = (
[backend_file.environment.substs['HOST_AR']] +
[backend_file.environment.substs['HOST_AR_FLAGS'].replace('$@', '%o')] +
objs
)
backend_file.rule(
cmd=cmd,
inputs=inputs,
outputs=outputs,
display='AR %o'
)
def _gen_host_programs(self, backend_file):
for p in backend_file.host_programs:
self._gen_host_program(backend_file, p)
def _gen_host_program(self, backend_file, prog):
_, _, _, extra_libs, _ = self._expand_libs(prog)
objs = prog.objs
outputs = [prog.program]
host_libs = []
for lib in prog.linked_libraries:
if isinstance(lib, HostLibrary):
host_libs.append(lib)
host_libs = self._lib_paths(backend_file.objdir, host_libs)
inputs = objs + host_libs
use_cxx = any(f.endswith(('.cc', '.cpp')) for f in prog.source_files())
cc_or_cxx = 'HOST_CXX' if use_cxx else 'HOST_CC'
cmd = (
[backend_file.environment.substs[cc_or_cxx], '-o', '%o'] +
backend_file.local_flags['HOST_CXX_LDFLAGS'] +
backend_file.local_flags['HOST_LDFLAGS'] +
objs +
host_libs +
extra_libs
)
backend_file.rule(
cmd=cmd,
inputs=inputs,
outputs=outputs,
display='LINK %o'
)
def _gen_static_library(self, backend_file):
ar = [
backend_file.environment.substs['AR'],
@ -422,7 +496,7 @@ class TupBackend(CommonBackend):
skip_files = []
if self.environment.is_artifact_build:
skip_files = self._compile_env_gen_files
skip_files = self._compile_env_gen
for f in obj.outputs:
if any(mozpath.match(f, p) for p in skip_files):
@ -464,10 +538,12 @@ class TupBackend(CommonBackend):
backend_file.static_lib = obj
elif isinstance(obj, SharedLibrary):
backend_file.shared_lib = obj
elif isinstance(obj, HostProgram):
pass
elif isinstance(obj, Program):
backend_file.program = obj
elif isinstance(obj, (HostProgram, HostSimpleProgram)):
backend_file.host_programs.append(obj)
elif isinstance(obj, HostLibrary):
backend_file.host_library = obj
elif isinstance(obj, (Program, SimpleProgram)):
backend_file.programs.append(obj)
elif isinstance(obj, DirectoryTraversal):
pass
@ -490,11 +566,13 @@ class TupBackend(CommonBackend):
for objdir, backend_file in sorted(self._backend_files.items()):
backend_file.gen_sources_rules([self._installed_files])
for condition, gen_method in ((backend_file.shared_lib, self._gen_shared_library),
(backend_file.static_lib and backend_file.static_lib.no_expand_lib,
self._gen_static_library),
(backend_file.program, self._gen_program)):
if condition:
for var, gen_method in ((backend_file.shared_lib, self._gen_shared_library),
(backend_file.static_lib and backend_file.static_lib.no_expand_lib,
self._gen_static_library),
(backend_file.programs, self._gen_programs),
(backend_file.host_programs, self._gen_host_programs),
(backend_file.host_library, self._gen_host_library)):
if var:
backend_file.export_shell()
gen_method(backend_file)
for obj in backend_file.delayed_generated_files:
@ -539,7 +617,6 @@ class TupBackend(CommonBackend):
# TODO: These are directories that don't work in the tup backend
# yet, because things they depend on aren't built yet.
skip_directories = (
'layout/style/test', # HostSimplePrograms
'toolkit/library', # libxul.so
)
if obj.script and obj.method and obj.relobjdir not in skip_directories:
@ -569,7 +646,8 @@ class TupBackend(CommonBackend):
if exports:
backend_file.export(exports)
if any(f in obj.outputs for f in ('source-repo.h', 'buildid.h')):
if any(f.endswith(('automation.py', 'source-repo.h', 'buildid.h'))
for f in obj.outputs):
extra_outputs = [self._early_generated_files]
else:
extra_outputs = [self._installed_files] if obj.required_for_compile else []
@ -610,14 +688,14 @@ class TupBackend(CommonBackend):
if not path:
raise Exception("Cannot install to " + target)
if target.startswith('_tests'):
# TODO: TEST_HARNESS_FILES present a few challenges for the tup
# backend (bug 1372381).
return
for path, files in obj.files.walk():
self._add_features(target, path)
for f in files:
output_group = None
if any(mozpath.match(mozpath.basename(f), p)
for p in self._compile_env_files):
output_group = self._installed_files
if not isinstance(f, ObjDirPath):
backend_file = self._get_backend_file(mozpath.join(target, path))
if '*' in f:
@ -637,13 +715,27 @@ class TupBackend(CommonBackend):
yield p + '/'
prefix = ''.join(_prefix(f.full_path))
self.backend_input_files.add(prefix)
output_dir = ''
# If we have a RenamedSourcePath here, the common backend
# has generated this object from a jar manifest, and we
# can rely on 'path' to be our destination path relative
# to any wildcard match. Otherwise, the output file may
# contribute to our destination directory.
if not isinstance(f, RenamedSourcePath):
output_dir = ''.join(_prefix(mozpath.dirname(f)))
finder = FileFinder(prefix)
for p, _ in finder.find(f.full_path[len(prefix):]):
install_dir = prefix[len(obj.srcdir) + 1:]
output = p
if f.target_basename and '*' not in f.target_basename:
output = mozpath.join(f.target_basename, output)
backend_file.symlink_rule(mozpath.join(prefix, p),
output=mozpath.join(f.target_basename, p),
output_group=self._installed_files)
output=mozpath.join(output_dir, output),
output_group=output_group)
else:
backend_file.symlink_rule(f.full_path, output=f.target_basename, output_group=self._installed_files)
backend_file.symlink_rule(f.full_path, output=f.target_basename, output_group=output_group)
else:
if (self.environment.is_artifact_build and
any(mozpath.match(f.target_basename, p) for p in self._compile_env_gen_files)):
@ -653,18 +745,16 @@ class TupBackend(CommonBackend):
# We're not generating files in these directories yet, so
# don't attempt to install files generated from them.
if f.context.relobjdir not in ('layout/style/test',
'toolkit/library',
if f.context.relobjdir not in ('toolkit/library',
'js/src/shell'):
output = mozpath.join('$(MOZ_OBJ_ROOT)', target, path,
f.target_basename)
gen_backend_file = self._get_backend_file(f.context.relobjdir)
if gen_backend_file.requires_delay([f]):
output_group = self._installed_files if f.target_basename.endswith('.h') else None
gen_backend_file.delayed_installed_files.append((f.full_path, output, output_group))
else:
gen_backend_file.symlink_rule(f.full_path, output=output,
output_group=self._installed_files)
output_group=output_group)
def _process_final_target_pp_files(self, obj, backend_file):

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

@ -532,6 +532,14 @@ class HostSimpleProgram(HostMixin, BaseProgram):
SUFFIX_VAR = 'HOST_BIN_SUFFIX'
KIND = 'host'
def source_files(self):
for srcs in self.sources.values():
for f in srcs:
if ('host_%s' % mozpath.basename(mozpath.splitext(f)[0]) ==
mozpath.splitext(self.program)[0]):
return [f]
return []
def cargo_output_directory(context, target_var):
# cargo creates several directories and places its build artifacts

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

@ -14,6 +14,7 @@ import os
import re
import subprocess
import sys
import tempfile
from collections import OrderedDict
@ -823,6 +824,8 @@ class RunProgram(MachCommandBase):
help='Run the program with the crash reporter enabled.')
@CommandArgument('--setpref', action='append', default=[], group=prog_group,
help='Set the specified pref before starting the program. Can be set multiple times. Prefs can also be set in ~/.mozbuild/machrc in the [runprefs] section - see `./mach settings` for more information.')
@CommandArgument('--temp-profile', action='store_true', group=prog_group,
help='Run the program using a new temporary profile created inside the objdir.')
@CommandArgumentGroup('debugging')
@CommandArgument('--debug', action='store_true', group='debugging',
@ -846,7 +849,7 @@ class RunProgram(MachCommandBase):
@CommandArgument('--show-dump-stats', action='store_true', group='DMD',
help='Show stats when doing dumps.')
def run(self, params, remote, background, noprofile, disable_e10s,
enable_crash_reporter, setpref, debug, debugger,
enable_crash_reporter, setpref, temp_profile, debug, debugger,
debugger_args, dmd, mode, stacks, show_dump_stats):
if conditions.is_android(self):
@ -895,7 +898,11 @@ class RunProgram(MachCommandBase):
for pref in prefs:
prefs[pref] = Preferences.cast(prefs[pref])
path = os.path.join(self.topobjdir, 'tmp', 'scratch_user')
if (temp_profile):
path = tempfile.mkdtemp(dir=os.path.join(self.topobjdir, 'tmp'), prefix='profile-')
else:
path = os.path.join(self.topobjdir, 'tmp', 'profile-default')
profile = Profile(path, preferences=prefs)
args.append('-profile')
args.append(profile.profile)

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

@ -1,7 +1,6 @@
[DEFAULT]
head = head_psm.js
tags = psm
firefox-appdir = browser
support-files =
bad_certs/**
ocsp_certs/**

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

@ -287,14 +287,31 @@ LogManager.prototype = {
/**
* Finds all logs older than maxErrorAge and deletes them using async I/O.
*/
async cleanupLogs() {
cleanupLogs() {
let maxAge = this._prefs.get("log.appender.file.maxErrorAge", DEFAULT_MAX_ERROR_AGE);
let threshold = Date.now() - 1000 * maxAge;
this._log.debug("Log cleanup threshold time: " + threshold);
let shouldDelete = fileInfo => {
return fileInfo.lastModificationDate.getTime() < threshold;
};
return this._deleteLogFiles(shouldDelete);
},
/**
* Finds all logs and removes them.
*/
removeAllLogs() {
return this._deleteLogFiles(() => true);
},
// Delete some log files. A callback is invoked for each found log file to
// determine if that file should be removed.
async _deleteLogFiles(cbShouldDelete) {
this._cleaningUpFileLogs = true;
let logDir = FileUtils.getDir("ProfD", this._logFileSubDirectoryEntries);
let iterator = new OS.File.DirectoryIterator(logDir.path);
let maxAge = this._prefs.get("log.appender.file.maxErrorAge", DEFAULT_MAX_ERROR_AGE);
let threshold = Date.now() - 1000 * maxAge;
this._log.debug("Log cleanup threshold time: " + threshold);
await iterator.forEach(async (entry) => {
// Note that we don't check this.logFilePrefix is in the name - we cleanup
// all files in this directory regardless of that prefix so old logfiles
@ -306,7 +323,7 @@ LogManager.prototype = {
try {
// need to call .stat() as the enumerator doesn't give that to us on *nix.
let info = await OS.File.stat(entry.path);
if (info.lastModificationDate.getTime() >= threshold) {
if (!cbShouldDelete(info)) {
return;
}
this._log.trace(" > Cleanup removing " + entry.name +

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

@ -223,3 +223,37 @@ add_task(async function test_logFileError() {
lm.finalize();
});
function countLogFiles() {
let logsdir = FileUtils.getDir("ProfD", ["weave", "logs"], true);
let count = 0;
let entries = logsdir.directoryEntries;
while (entries.hasMoreElements()) {
count += 1;
entries.getNext();
}
return count;
}
// Test that removeAllLogs removes all log files.
add_task(async function test_logFileError() {
Services.prefs.setBoolPref("log-manager.test.log.appender.file.logOnError", true);
Services.prefs.setBoolPref("log-manager.test.log.appender.file.logOnSuccess", true);
let lm = new LogManager("log-manager.test.", ["TestLog2"], "test");
let log = Log.repository.getLogger("TestLog2");
log.info("an info message");
let reason = await lm.resetFileLog();
Assert.equal(reason, lm.SUCCESS_LOG_WRITTEN, "success log was written.");
log.error("an error message");
reason = await lm.resetFileLog();
Assert.equal(reason, lm.ERROR_LOG_WRITTEN);
Assert.equal(countLogFiles(), 2, "expect 2 log files");
await lm.removeAllLogs();
Assert.equal(countLogFiles(), 0, "should be no log files after removing them");
lm.finalize();
});

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

@ -775,7 +775,20 @@ ErrorHandler.prototype = {
break;
case "weave:service:start-over:finish":
// ensure we capture any logs between the last sync and the reset completing.
this.resetFileLog();
this.resetFileLog().then(() => {
// although for privacy reasons we also delete all logs (but we allow
// a preference to avoid this to help with debugging.)
if (!Svc.Prefs.get("log.keepLogsOnReset", false)) {
return this._logManager.removeAllLogs().then(() => {
Svc.Obs.notify("weave:service:remove-file-log");
});
}
return null;
}).catch(err => {
// So we failed to delete the logs - take the ironic option of
// writing this error to the logs we failed to delete!
this._log.error("Failed to delete logs on reset", err);
});
break;
}
},

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

@ -401,3 +401,28 @@ add_test(function test_logErrorCleanup_age() {
Svc.Obs.notify("weave:service:sync:error");
}, delay, this, "cleanup-timer");
});
add_task(async function test_remove_log_on_startOver() {
Svc.Prefs.set("log.appender.file.logOnError", true);
let log = Log.repository.getLogger("Sync.Test.FileLog");
const MESSAGE = "this WILL show up";
log.info(MESSAGE);
let promiseLogWritten = promiseOneObserver("weave:service:reset-file-log");
// Fake an unsuccessful sync.
Svc.Obs.notify("weave:service:sync:error");
await promiseLogWritten;
// Should have at least 1 log file.
let entries = logsdir.directoryEntries;
Assert.ok(entries.hasMoreElements());
// Fake a reset.
let promiseRemoved = promiseOneObserver("weave:service:remove-file-log");
Svc.Obs.notify("weave:service:start-over:finish");
await promiseRemoved;
// should be no files left.
Assert.ok(!logsdir.directoryEntries.hasMoreElements());
});

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

@ -71,7 +71,6 @@ const SYNC_WIPE_REMOTE = "wipeRemote";
const ACTION_ADD = "add";
const ACTION_DELETE = "delete";
const ACTION_MODIFY = "modify";
const ACTION_PRIVATE_BROWSING = "private-browsing";
const ACTION_SET_ENABLED = "set-enabled";
const ACTION_SYNC = "sync";
const ACTION_SYNC_RESET_CLIENT = SYNC_RESET_CLIENT;
@ -84,7 +83,6 @@ const ACTIONS = [
ACTION_ADD,
ACTION_DELETE,
ACTION_MODIFY,
ACTION_PRIVATE_BROWSING,
ACTION_SET_ENABLED,
ACTION_SYNC,
ACTION_SYNC_RESET_CLIENT,
@ -96,7 +94,6 @@ const ACTIONS = [
const OBSERVER_TOPICS = ["fxaccounts:onlogin",
"fxaccounts:onlogout",
"private-browsing",
"profile-before-change",
"sessionstore-windows-restored",
"weave:service:tracking-started",
@ -171,10 +168,6 @@ var TPS = {
Logger.logInfo("----------event observed: " + topic);
switch (topic) {
case "private-browsing":
Logger.logInfo("private browsing " + data);
break;
case "profile-before-change":
OBSERVER_TOPICS.forEach(function(topic) {
Services.obs.removeObserver(this, topic);

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

@ -7,10 +7,6 @@
_DEST_DIR = $(DEPTH)/_tests/$(relativesrcdir)
include $(topsrcdir)/config/rules.mk
# We're installing to _tests/testing/mochitest, so this is the depth
# necessary for relative objdir paths.
TARGET_DEPTH = ../../..
include $(topsrcdir)/build/automation-build.mk
libs::
(cd $(DIST)/xpi-stage && tar $(TAR_CREATE_FLAGS) - mochijar) | (cd $(_DEST_DIR) && tar -xf -)

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

@ -26,12 +26,7 @@ MOCHITEST_MANIFESTS += [
]
MOCHITEST_CHROME_MANIFESTS += ['chrome/chrome.ini']
GENERATED_FILES += [
'automation.py',
]
TEST_HARNESS_FILES.testing.mochitest += [
'!automation.py',
'/build/mobile/remoteautomation.py',
'/build/pgo/server-locations.txt',
'/build/sanitizers/lsan_suppressions.txt',

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

@ -1,17 +1,11 @@
[constant-source-basic.html]
[X Factory method: node.channelCount is not equal to 2. Got 1.]
expected: FAIL
[X Factory method: node.offset.minValue is not equal to -3.4028234663852886e+38. Got -Infinity.]
expected: FAIL
[X Factory method: node.offset.maxValue is not equal to 3.4028234663852886e+38. Got Infinity.]
expected: FAIL
[< [createConstantSource()\] 3 out of 11 assertions were failed.]
expected: FAIL
[X Constructor: node.channelCount is not equal to 2. Got 1.]
[< [createConstantSource()\] 2 out of 11 assertions were failed.]
expected: FAIL
[X Constructor: node.offset.minValue is not equal to -3.4028234663852886e+38. Got -Infinity.]
@ -20,7 +14,7 @@
[X Constructor: node.offset.maxValue is not equal to 3.4028234663852886e+38. Got Infinity.]
expected: FAIL
[< [new ConstantSourceNode()\] 3 out of 11 assertions were failed.]
[< [new ConstantSourceNode()\] 2 out of 11 assertions were failed.]
expected: FAIL
[X start(-1) threw "NotSupportedError" instead of RangeError.]

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

@ -137,7 +137,7 @@ var test = {
var toolbar =
PlacesUtils.getFolderContents(PlacesUtils.toolbarFolderId,
false, true).root;
Assert.ok(toolbar.childCount, 1);
Assert.equal(toolbar.childCount, 1);
var folderNode = toolbar.getChild(0);
Assert.equal(folderNode.type, folderNode.RESULT_TYPE_FOLDER);

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

@ -43,7 +43,7 @@ var quotesTest = {
toolbar.containerOpen = true;
// test for our quoted folder
Assert.ok(toolbar.childCount, 1);
Assert.equal(toolbar.childCount, 1);
var folderNode = toolbar.getChild(0);
Assert.equal(folderNode.type, folderNode.RESULT_TYPE_FOLDER);
Assert.equal(folderNode.title, this._folderTitle);

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

@ -604,12 +604,8 @@ function waitForConnectionClosed(aCallback) {
* @param [optional] aStack
* The stack frame used to report the error.
*/
function do_check_valid_places_guid(aGuid,
aStack) {
if (!aStack) {
aStack = Components.stack.caller;
}
Assert.ok(/^[a-zA-Z0-9\-_]{12}$/.test(aGuid), aStack);
function do_check_valid_places_guid(aGuid) {
Assert.ok(/^[a-zA-Z0-9\-_]{12}$/.test(aGuid), "Should be a valid GUID");
}
/**
@ -621,21 +617,17 @@ function do_check_valid_places_guid(aGuid,
* The stack frame used to report the error.
* @return the associated the guid.
*/
function do_get_guid_for_uri(aURI,
aStack) {
if (!aStack) {
aStack = Components.stack.caller;
}
function do_get_guid_for_uri(aURI) {
let stmt = DBConn().createStatement(
`SELECT guid
FROM moz_places
WHERE url_hash = hash(:url) AND url = :url`
);
stmt.params.url = aURI.spec;
Assert.ok(stmt.executeStep(), aStack);
Assert.ok(stmt.executeStep(), "GUID for URI statement should succeed");
let guid = stmt.row.guid;
stmt.finalize();
do_check_valid_places_guid(guid, aStack);
do_check_valid_places_guid(guid);
return guid;
}
@ -649,11 +641,10 @@ function do_get_guid_for_uri(aURI,
*/
function do_check_guid_for_uri(aURI,
aGUID) {
let caller = Components.stack.caller;
let guid = do_get_guid_for_uri(aURI, caller);
let guid = do_get_guid_for_uri(aURI);
if (aGUID) {
do_check_valid_places_guid(aGUID, caller);
Assert.equal(guid, aGUID, caller);
do_check_valid_places_guid(aGUID);
Assert.equal(guid, aGUID, "Should have a guid in moz_places for the URI");
}
}
@ -666,21 +657,17 @@ function do_check_guid_for_uri(aURI,
* The stack frame used to report the error.
* @return the associated the guid.
*/
function do_get_guid_for_bookmark(aId,
aStack) {
if (!aStack) {
aStack = Components.stack.caller;
}
function do_get_guid_for_bookmark(aId) {
let stmt = DBConn().createStatement(
`SELECT guid
FROM moz_bookmarks
WHERE id = :item_id`
);
stmt.params.item_id = aId;
Assert.ok(stmt.executeStep(), aStack);
Assert.ok(stmt.executeStep(), "Should succeed executing the SQL statement");
let guid = stmt.row.guid;
stmt.finalize();
do_check_valid_places_guid(guid, aStack);
do_check_valid_places_guid(guid);
return guid;
}
@ -694,11 +681,10 @@ function do_get_guid_for_bookmark(aId,
*/
function do_check_guid_for_bookmark(aId,
aGUID) {
let caller = Components.stack.caller;
let guid = do_get_guid_for_bookmark(aId, caller);
let guid = do_get_guid_for_bookmark(aId);
if (aGUID) {
do_check_valid_places_guid(aGUID, caller);
Assert.equal(guid, aGUID, caller);
do_check_valid_places_guid(aGUID);
Assert.equal(guid, aGUID, "Should have the correct GUID for the bookmark");
}
}

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

@ -129,15 +129,14 @@ VisitObserver.prototype = {
*/
function do_check_title_for_uri(aURI,
aTitle) {
let stack = Components.stack.caller;
let stmt = DBConn().createStatement(
`SELECT title
FROM moz_places
WHERE url_hash = hash(:url) AND url = :url`
);
stmt.params.url = aURI.spec;
Assert.ok(stmt.executeStep(), stack);
Assert.equal(stmt.row.title, aTitle, stack);
Assert.ok(stmt.executeStep());
Assert.equal(stmt.row.title, aTitle);
stmt.finalize();
}

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

@ -244,7 +244,7 @@ function ensureAnnotationsSet(aGuid, aAnnos) {
}
function ensureItemsMoved(...items) {
Assert.ok(observer.itemsMoved.size, items.length);
Assert.equal(observer.itemsMoved.size, items.length);
for (let item of items) {
Assert.ok(observer.itemsMoved.has(item.guid));
let info = observer.itemsMoved.get(item.guid);

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

@ -450,14 +450,16 @@ security:
pkcs11_modules_loaded:
bug_numbers:
- 1369911
- 1445961
description: >
A keyed boolean indicating the library names of the PKCS#11 modules that
have been loaded by the browser.
expires: "62"
expires: "69"
kind: boolean
keyed: true
notification_emails:
- seceng-telemetry@mozilla.com
- dkeeler@mozilla.com
release_channel_collection: opt-out
record_in_processes:
- main

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

@ -9,6 +9,10 @@
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:xbl="http://www.mozilla.org/xbl">
<!-- This binding is needed on <scrollbar> to prevent content process
startup performance regression; to be removed in bug 1458375 -->
<binding id="empty"/>
<binding id="basecontrol">
<implementation implements="nsIDOMXULControlElement">
<!-- public implementation -->

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

@ -5,68 +5,68 @@ ChromeUtils.import("resource://gre/modules/BinarySearch.jsm");
function run_test() {
// empty array
ok([], 1, false, 0);
check([], 1, false, 0);
// one-element array
ok([2], 2, true, 0);
ok([2], 1, false, 0);
ok([2], 3, false, 1);
check([2], 2, true, 0);
check([2], 1, false, 0);
check([2], 3, false, 1);
// two-element array
ok([2, 4], 2, true, 0);
ok([2, 4], 4, true, 1);
ok([2, 4], 1, false, 0);
ok([2, 4], 3, false, 1);
ok([2, 4], 5, false, 2);
check([2, 4], 2, true, 0);
check([2, 4], 4, true, 1);
check([2, 4], 1, false, 0);
check([2, 4], 3, false, 1);
check([2, 4], 5, false, 2);
// three-element array
ok([2, 4, 6], 2, true, 0);
ok([2, 4, 6], 4, true, 1);
ok([2, 4, 6], 6, true, 2);
ok([2, 4, 6], 1, false, 0);
ok([2, 4, 6], 3, false, 1);
ok([2, 4, 6], 5, false, 2);
ok([2, 4, 6], 7, false, 3);
check([2, 4, 6], 2, true, 0);
check([2, 4, 6], 4, true, 1);
check([2, 4, 6], 6, true, 2);
check([2, 4, 6], 1, false, 0);
check([2, 4, 6], 3, false, 1);
check([2, 4, 6], 5, false, 2);
check([2, 4, 6], 7, false, 3);
// duplicates
ok([2, 2], 2, true, 0);
ok([2, 2], 1, false, 0);
ok([2, 2], 3, false, 2);
check([2, 2], 2, true, 0);
check([2, 2], 1, false, 0);
check([2, 2], 3, false, 2);
// duplicates on the left
ok([2, 2, 4], 2, true, 1);
ok([2, 2, 4], 4, true, 2);
ok([2, 2, 4], 1, false, 0);
ok([2, 2, 4], 3, false, 2);
ok([2, 2, 4], 5, false, 3);
check([2, 2, 4], 2, true, 1);
check([2, 2, 4], 4, true, 2);
check([2, 2, 4], 1, false, 0);
check([2, 2, 4], 3, false, 2);
check([2, 2, 4], 5, false, 3);
// duplicates on the right
ok([2, 4, 4], 2, true, 0);
ok([2, 4, 4], 4, true, 1);
ok([2, 4, 4], 1, false, 0);
ok([2, 4, 4], 3, false, 1);
ok([2, 4, 4], 5, false, 3);
check([2, 4, 4], 2, true, 0);
check([2, 4, 4], 4, true, 1);
check([2, 4, 4], 1, false, 0);
check([2, 4, 4], 3, false, 1);
check([2, 4, 4], 5, false, 3);
// duplicates in the middle
ok([2, 4, 4, 6], 2, true, 0);
ok([2, 4, 4, 6], 4, true, 1);
ok([2, 4, 4, 6], 6, true, 3);
ok([2, 4, 4, 6], 1, false, 0);
ok([2, 4, 4, 6], 3, false, 1);
ok([2, 4, 4, 6], 5, false, 3);
ok([2, 4, 4, 6], 7, false, 4);
check([2, 4, 4, 6], 2, true, 0);
check([2, 4, 4, 6], 4, true, 1);
check([2, 4, 4, 6], 6, true, 3);
check([2, 4, 4, 6], 1, false, 0);
check([2, 4, 4, 6], 3, false, 1);
check([2, 4, 4, 6], 5, false, 3);
check([2, 4, 4, 6], 7, false, 4);
// duplicates all around
ok([2, 2, 4, 4, 6, 6], 2, true, 0);
ok([2, 2, 4, 4, 6, 6], 4, true, 2);
ok([2, 2, 4, 4, 6, 6], 6, true, 4);
ok([2, 2, 4, 4, 6, 6], 1, false, 0);
ok([2, 2, 4, 4, 6, 6], 3, false, 2);
ok([2, 2, 4, 4, 6, 6], 5, false, 4);
ok([2, 2, 4, 4, 6, 6], 7, false, 6);
check([2, 2, 4, 4, 6, 6], 2, true, 0);
check([2, 2, 4, 4, 6, 6], 4, true, 2);
check([2, 2, 4, 4, 6, 6], 6, true, 4);
check([2, 2, 4, 4, 6, 6], 1, false, 0);
check([2, 2, 4, 4, 6, 6], 3, false, 2);
check([2, 2, 4, 4, 6, 6], 5, false, 4);
check([2, 2, 4, 4, 6, 6], 7, false, 6);
}
function ok(array, target, expectedFound, expectedIdx) {
function check(array, target, expectedFound, expectedIdx) {
let [found, idx] = BinarySearch.search(cmp, array, target);
Assert.equal(found, expectedFound);
Assert.equal(idx, expectedIdx);

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

@ -7,6 +7,7 @@
scrollbar {
-moz-appearance: scrollbar;
-moz-binding: url("chrome://global/content/bindings/general.xml#empty");
cursor: default;
background-color: white;
}
@ -81,6 +82,7 @@ scrollcorner {
@media print {
html|div scrollbar {
-moz-appearance: scrollbar;
-moz-binding: url("chrome://global/content/bindings/general.xml#empty");
cursor: default;
}
}

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

@ -13,6 +13,7 @@
scrollbar {
-moz-appearance: scrollbar-horizontal;
-moz-binding: url("chrome://global/content/bindings/general.xml#empty");
cursor: default;
}
@ -62,7 +63,7 @@ scrollbarbutton {
/* ::::: square at the corner of two scrollbars ::::: */
scrollcorner {
scrollcorner {
/* XXX -moz-appearance: scrollcorner; */
width: 16px;
cursor: default;