Merge m-c to b2ginbound, a=merge

--HG--
extra : commitid : HBa9vqJvY25
This commit is contained in:
Wes Kocher 2015-12-03 16:11:31 -08:00
Родитель e7a07471ca c40454e094
Коммит ceeecd110c
220 изменённых файлов: 2514 добавлений и 1423 удалений

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

@ -1087,6 +1087,9 @@ pref("identity.fxaccounts.enabled", true);
// Mobile Identity API.
pref("services.mobileid.server.uri", "https://msisdn.services.mozilla.com");
pref("identity.fxaccounts.remote.oauth.uri", "https://oauth.accounts.firefox.com/v1");
pref("identity.fxaccounts.remote.profile.uri", "https://profile.accounts.firefox.com/v1");
// Enable mapped array buffer.
#ifndef XP_WIN
pref("dom.mapped_arraybuffer.enabled", true);

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

@ -19,14 +19,6 @@ const STATE_CLOSED = 4;
// We're initially stopped.
var state = STATE_STOPPED;
function observer(subj, topic) {
Services.obs.removeObserver(observer, topic);
state = STATE_QUITTING;
}
// Listen for when the application is quitting.
Services.obs.addObserver(observer, "quit-application-granted", false);
/**
* This module keeps track of SessionStore's current run state. We will
* always start out at STATE_STOPPED. After the sessionw as read from disk and
@ -95,5 +87,14 @@ this.RunState = Object.freeze({
if (this.isClosing) {
state = STATE_CLOSED;
}
}
},
// Switch the run state to STATE_QUITTING. This should be called once we're
// certain that the browser is going away and before we start collecting the
// final window states to save in the session file.
setQuitting() {
if (this.isRunning) {
state = STATE_QUITTING;
}
},
});

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

@ -31,7 +31,7 @@ const MAX_CONCURRENT_TAB_RESTORES = 3;
// global notifications observed
const OBSERVING = [
"browser-window-before-show", "domwindowclosed",
"quit-application-requested", "browser-lastwindow-close-granted",
"quit-application-granted", "browser-lastwindow-close-granted",
"quit-application", "browser:purge-session-history",
"browser:purge-domain-data",
"idle-daily",
@ -180,6 +180,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "Utils",
"resource:///modules/sessionstore/Utils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ViewSourceBrowser",
"resource://gre/modules/ViewSourceBrowser.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "AsyncShutdown",
"resource://gre/modules/AsyncShutdown.jsm");
/**
* |true| if we are in debug mode, |false| otherwise.
@ -627,8 +629,8 @@ var SessionStoreInternal = {
case "domwindowclosed": // catch closed windows
this.onClose(aSubject);
break;
case "quit-application-requested":
this.onQuitApplicationRequested();
case "quit-application-granted":
this.onQuitApplicationGranted();
break;
case "browser-lastwindow-close-granted":
this.onLastWindowCloseGranted();
@ -837,6 +839,7 @@ var SessionStoreInternal = {
break;
case "SessionStore:error":
this.reportInternalError(data);
TabStateFlusher.resolveAll(browser, false, "Received error from the content process");
break;
default:
throw new Error(`received unknown message '${aMessage.name}'`);
@ -1210,6 +1213,10 @@ var SessionStoreInternal = {
var tabbrowser = aWindow.gBrowser;
// The tabbrowser binding will go away once the window is closed,
// so we'll hold a reference to the browsers in the closure here.
let browsers = tabbrowser.browsers;
TAB_EVENTS.forEach(function(aEvent) {
tabbrowser.tabContainer.removeEventListener(aEvent, this, true);
}, this);
@ -1281,10 +1288,6 @@ var SessionStoreInternal = {
this.maybeSaveClosedWindow(winData, isLastWindow);
}
// The tabbrowser binding will go away once the window is closed,
// so we'll hold a reference to the browsers in the closure here.
let browsers = tabbrowser.browsers;
TabStateFlusher.flushWindow(aWindow).then(() => {
// At this point, aWindow is closed! You should probably not try to
// access any DOM elements from aWindow within this callback unless
@ -1310,13 +1313,13 @@ var SessionStoreInternal = {
// Update the tabs data now that we've got the most
// recent information.
this.cleanUpWindow(aWindow, winData);
this.cleanUpWindow(aWindow, winData, browsers);
// save the state without this window to disk
this.saveStateDelayed();
});
} else {
this.cleanUpWindow(aWindow, winData);
this.cleanUpWindow(aWindow, winData, browsers);
}
for (let i = 0; i < tabbrowser.tabs.length; i++) {
@ -1336,7 +1339,13 @@ var SessionStoreInternal = {
* DyingWindowCache in case anybody is still holding a
* reference to it.
*/
cleanUpWindow(aWindow, winData) {
cleanUpWindow(aWindow, winData, browsers) {
// Any leftover TabStateFlusher Promises need to be resolved now,
// since we're about to remove the message listeners.
for (let browser of browsers) {
TabStateFlusher.resolveAll(browser);
}
// Cache the window state until it is completely gone.
DyingWindowCache.set(aWindow, winData);
@ -1395,23 +1404,76 @@ var SessionStoreInternal = {
},
/**
* On quit application requested
* On quit application granted
*/
onQuitApplicationRequested: function ssi_onQuitApplicationRequested() {
// get a current snapshot of all windows
this._forEachBrowserWindow(function(aWindow) {
// Flush all data queued in the content script to not lose it when
// shutting down.
TabState.flushWindow(aWindow);
this._collectWindowData(aWindow);
onQuitApplicationGranted: function ssi_onQuitApplicationGranted() {
// Collect an initial snapshot of window data before we do the flush
this._forEachBrowserWindow((win) => {
this._collectWindowData(win);
});
// we must cache this because _getMostRecentBrowserWindow will always
// return null by the time quit-application occurs
// Now add an AsyncShutdown blocker that'll spin the event loop
// until the windows have all been flushed.
// This progress object will track the state of async window flushing
// and will help us debug things that go wrong with our AsyncShutdown
// blocker.
let progress = { total: -1, current: -1 };
// We're going down! Switch state so that we treat closing windows and
// tabs correctly.
RunState.setQuitting();
AsyncShutdown.quitApplicationGranted.addBlocker(
"SessionStore: flushing all windows",
this.flushAllWindowsAsync(progress),
() => progress);
},
/**
* An async Task that iterates all open browser windows and flushes
* any outstanding messages from their tabs. This will also close
* all of the currently open windows while we wait for the flushes
* to complete.
*
* @param progress (Object)
* Optional progress object that will be updated as async
* window flushing progresses. flushAllWindowsSync will
* write to the following properties:
*
* total (int):
* The total number of windows to be flushed.
* current (int):
* The current window that we're waiting for a flush on.
*
* @return Promise
*/
flushAllWindowsAsync: Task.async(function*(progress={}) {
let windowPromises = [];
// We collect flush promises and close each window immediately so that
// the user can't start changing any window state while we're waiting
// for the flushes to finish.
this._forEachBrowserWindow((win) => {
windowPromises.push(TabStateFlusher.flushWindow(win));
win.close();
});
progress.total = windowPromises.length;
// We'll iterate through the Promise array, yielding each one, so as to
// provide useful progress information to AsyncShutdown.
for (let i = 0; i < windowPromises.length; ++i) {
progress.current = i;
yield windowPromises[i];
};
// We must cache this because _getMostRecentBrowserWindow will always
// return null by the time quit-application occurs.
var activeWindow = this._getMostRecentBrowserWindow();
if (activeWindow)
this.activeWindowSSiCache = activeWindow.__SSi || "";
DirtyWindows.clear();
},
}),
/**
* On last browser window close

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

@ -37,9 +37,19 @@ this.TabStateFlusher = Object.freeze({
/**
* Resolves the flush request with the given flush ID.
*
* @param browser (<xul:browser>)
* The browser for which the flush is being resolved.
* @param flushID (int)
* The ID of the flush that was sent to the browser.
* @param success (bool, optional)
* Whether or not the flush succeeded.
* @param message (string, optional)
* An error message that will be sent to the Console in the
* event that a flush failed.
*/
resolve(browser, flushID) {
TabStateFlusherInternal.resolve(browser, flushID);
resolve(browser, flushID, success=true, message="") {
TabStateFlusherInternal.resolve(browser, flushID, success, message);
},
/**
@ -47,9 +57,17 @@ this.TabStateFlusher = Object.freeze({
* used when the content process crashed or the final update message was
* seen. In those cases we can't guarantee to ever hear back from the frame
* script so we just resolve all requests instead of discarding them.
*
* @param browser (<xul:browser>)
* The browser for which all flushes are being resolved.
* @param success (bool, optional)
* Whether or not the flushes succeeded.
* @param message (string, optional)
* An error message that will be sent to the Console in the
* event that the flushes failed.
*/
resolveAll(browser) {
TabStateFlusherInternal.resolveAll(browser);
resolveAll(browser, success=true, message="") {
TabStateFlusherInternal.resolveAll(browser, success, message);
}
});
@ -95,8 +113,18 @@ var TabStateFlusherInternal = {
/**
* Resolves the flush request with the given flush ID.
*
* @param browser (<xul:browser>)
* The browser for which the flush is being resolved.
* @param flushID (int)
* The ID of the flush that was sent to the browser.
* @param success (bool, optional)
* Whether or not the flush succeeded.
* @param message (string, optional)
* An error message that will be sent to the Console in the
* event that a flush failed.
*/
resolve(browser, flushID) {
resolve(browser, flushID, success=true, message="") {
// Nothing to do if there are no pending flushes for the given browser.
if (!this._requests.has(browser.permanentKey)) {
return;
@ -108,10 +136,14 @@ var TabStateFlusherInternal = {
return;
}
if (!success) {
Cu.reportError("Failed to flush browser: " + message);
}
// Resolve the request with the given id.
let resolve = perBrowserRequests.get(flushID);
perBrowserRequests.delete(flushID);
resolve();
resolve(success);
},
/**
@ -119,8 +151,16 @@ var TabStateFlusherInternal = {
* used when the content process crashed or the final update message was
* seen. In those cases we can't guarantee to ever hear back from the frame
* script so we just resolve all requests instead of discarding them.
*
* @param browser (<xul:browser>)
* The browser for which all flushes are being resolved.
* @param success (bool, optional)
* Whether or not the flushes succeeded.
* @param message (string, optional)
* An error message that will be sent to the Console in the
* event that the flushes failed.
*/
resolveAll(browser) {
resolveAll(browser, success=true, message="") {
// Nothing to do if there are no pending flushes for the given browser.
if (!this._requests.has(browser.permanentKey)) {
return;
@ -129,9 +169,13 @@ var TabStateFlusherInternal = {
// Retrieve active requests for given browser.
let perBrowserRequests = this._requests.get(browser.permanentKey);
if (!success) {
Cu.reportError("Failed to flush browser: " + message);
}
// Resolve all requests.
for (let resolve of perBrowserRequests.values()) {
resolve();
resolve(success);
}
// Clear active requests.

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

@ -21,29 +21,6 @@ add_task(function flush_on_tabclose() {
"sessionStorage data has been flushed on TabClose");
});
/**
* This test ensures we won't lose tab data queued in the content script when
* the application tries to quit.
*/
add_task(function flush_on_quit_requested() {
let tab = yield createTabWithStorageData(["http://example.com"]);
let browser = tab.linkedBrowser;
yield modifySessionStorage(browser, {test: "on-quit-requested"});
// Note that sending quit-application-requested should not interfere with
// other tests and code. We're just notifying about a shutdown request but
// we will not send quit-application-granted. Observers will thus assume
// that some other observer has canceled the request.
sendQuitApplicationRequested();
let {storage} = JSON.parse(ss.getTabState(tab));
is(storage["http://example.com"].test, "on-quit-requested",
"sessionStorage data has been flushed when a quit is requested");
gBrowser.removeTab(tab);
});
/**
* This test ensures we won't lose tab data queued in the content script when
* duplicating a tab.
@ -152,9 +129,3 @@ function createTabWithStorageData(urls, win = window) {
throw new Task.Result(tab);
});
}
function sendQuitApplicationRequested() {
let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"]
.createInstance(Ci.nsISupportsPRBool);
Services.obs.notifyObservers(cancelQuit, "quit-application-requested", null);
}

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

@ -51,7 +51,11 @@ add_task(function*() {
// Attempt to flush. This should fail.
let promiseFlushed = TabStateFlusher.flush(browser);
promiseFlushed.then(() => {throw new Error("Flush should have failed")});
promiseFlushed.then((success) => {
if (success) {
throw new Error("Flush should have failed")
}
});
// The frame script should report an error.
yield promiseReported;

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

@ -59,6 +59,7 @@
"dot-location": [2, "property"],
"eol-last": 2,
"eqeqeq": [2, "smart"],
"generator-star-spacing": [2, {"before": false, "after": true}],
"jsx-quotes": [2, "prefer-double"],
"key-spacing": [2, {"beforeColon": false, "afterColon": true }],
"linebreak-style": [2, "unix"],
@ -71,6 +72,8 @@
"no-class-assign": 2,
"no-const-assign": 2,
"no-console": 0, // Leave as 0. We use console logging in content code.
"no-duplicate-case": 2,
"no-else-return": 2,
"no-empty": 2,
"no-empty-label": 2,
"no-eval": 2,
@ -99,6 +102,7 @@
"no-proto": 2,
"no-return-assign": 2,
"no-script-url": 2,
"no-self-compare": 2,
"no-sequences": 2,
"no-shadow": 2,
"no-shadow-restricted-names": 2,
@ -131,18 +135,19 @@
"yoda": [2, "never"],
// eslint-plugin-react rules. These are documented at
// <https://github.com/yannickcr/eslint-plugin-react#list-of-supported-rules>
"react/jsx-curly-spacing": [2, "never"],
"react/jsx-no-bind": 2,
"react/jsx-no-duplicate-props": 2,
"react/jsx-no-undef": 2,
"react/jsx-sort-props": 2,
"react/jsx-sort-prop-types": 2,
"react/jsx-uses-vars": 2,
"react/jsx-no-duplicate-props": 2,
"react/no-did-mount-set-state": 2,
"react/no-did-update-set-state": 2,
"react/no-unknown-property": 2,
"react/prop-types": 2,
"react/self-closing-comp": 2,
"react/wrap-multilines": 2,
"react/jsx-curly-spacing": [2, "never"],
// Not worth it: React is defined globally
"react/jsx-uses-react": 0,
"react/react-in-jsx-scope": 0,

10
browser/extensions/loop/bootstrap.js поставляемый
Просмотреть файл

@ -799,12 +799,8 @@ function startup() {
for (let sheet of sheets) {
let styleSheetURI = Services.io.newURI(sheet, null, null);
// XXX We would love to specify AUTHOR_SHEET here and in shutdown, however
// bug 1228542 prevents us from doing that as we'd cause a lot of assertions
// in debug mode for tests. Once that is fixed, we should be able to change
// this, and remove the !important attributes from our syle sheets.
styleSheetService.loadAndRegisterSheet(styleSheetURI,
styleSheetService.USER_SHEET);
styleSheetService.AUTHOR_SHEET);
}
}
@ -846,9 +842,9 @@ function shutdown() {
for (let sheet of sheets) {
let styleSheetURI = Services.io.newURI(sheet, null, null);
if (styleSheetService.sheetRegistered(styleSheetURI,
styleSheetService.USER_SHEET)) {
styleSheetService.AUTHOR_SHEET)) {
styleSheetService.unregisterSheet(styleSheetURI,
styleSheetService.USER_SHEET);
styleSheetService.AUTHOR_SHEET);
}
}

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

@ -3,7 +3,7 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
window.OTProperties = {
cdnURL: "loop/"
cdnURL: ""
};
window.OTProperties.assetURL = window.OTProperties.cdnURL + "sdk-content/";
window.OTProperties.configURL = window.OTProperties.assetURL + "js/dynamic_config.min.js";

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

@ -380,9 +380,9 @@ loop.panel = (function(_, mozL10n) {
var roomUrl = this.props.roomUrls && this.props.roomUrls[0];
if (roomUrl && roomUrl.location) {
return this._renderIcon(roomUrl);
} else {
return this._renderDefaultIcon();
}
return this._renderDefaultIcon();
}
});

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

@ -380,9 +380,9 @@ loop.panel = (function(_, mozL10n) {
var roomUrl = this.props.roomUrls && this.props.roomUrls[0];
if (roomUrl && roomUrl.location) {
return this._renderIcon(roomUrl);
} else {
return this._renderDefaultIcon();
}
return this._renderDefaultIcon();
}
});

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

@ -7,7 +7,6 @@ loop.roomViews = (function(mozL10n) {
"use strict";
var ROOM_STATES = loop.store.ROOM_STATES;
var SCREEN_SHARE_STATES = loop.shared.utils.SCREEN_SHARE_STATES;
var FAILURE_DETAILS = loop.shared.utils.FAILURE_DETAILS;
var sharedActions = loop.shared.actions;
var sharedMixins = loop.shared.mixins;
@ -622,6 +621,12 @@ loop.roomViews = (function(mozL10n) {
})
}));
}
// Automatically start sharing a tab now we're ready to share.
if (this.state.roomState !== ROOM_STATES.SESSION_CONNECTED &&
nextState.roomState === ROOM_STATES.SESSION_CONNECTED) {
this.props.dispatcher.dispatch(new sharedActions.StartBrowserShare());
}
},
/**
@ -767,11 +772,6 @@ loop.roomViews = (function(mozL10n) {
this.setTitle(roomTitle);
}
var screenShareData = {
state: this.state.screenSharingState || SCREEN_SHARE_STATES.INACTIVE,
visible: true
};
var shouldRenderInvitationOverlay = this._shouldRenderInvitationOverlay();
var shouldRenderEditContextView = this.state.showEditContext;
var roomData = this.props.roomStore.getStoreState("activeRoom");
@ -827,7 +827,6 @@ loop.roomViews = (function(mozL10n) {
dispatcher: this.props.dispatcher,
hangup: this.leaveRoom,
publishStream: this.publishStream,
screenShare: screenShareData,
settingsMenuItems: settingsMenuItems,
show: !shouldRenderEditContextView,
showHangup: this.props.chatWindowDetached,

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

@ -7,7 +7,6 @@ loop.roomViews = (function(mozL10n) {
"use strict";
var ROOM_STATES = loop.store.ROOM_STATES;
var SCREEN_SHARE_STATES = loop.shared.utils.SCREEN_SHARE_STATES;
var FAILURE_DETAILS = loop.shared.utils.FAILURE_DETAILS;
var sharedActions = loop.shared.actions;
var sharedMixins = loop.shared.mixins;
@ -622,6 +621,12 @@ loop.roomViews = (function(mozL10n) {
})
}));
}
// Automatically start sharing a tab now we're ready to share.
if (this.state.roomState !== ROOM_STATES.SESSION_CONNECTED &&
nextState.roomState === ROOM_STATES.SESSION_CONNECTED) {
this.props.dispatcher.dispatch(new sharedActions.StartBrowserShare());
}
},
/**
@ -767,11 +772,6 @@ loop.roomViews = (function(mozL10n) {
this.setTitle(roomTitle);
}
var screenShareData = {
state: this.state.screenSharingState || SCREEN_SHARE_STATES.INACTIVE,
visible: true
};
var shouldRenderInvitationOverlay = this._shouldRenderInvitationOverlay();
var shouldRenderEditContextView = this.state.showEditContext;
var roomData = this.props.roomStore.getStoreState("activeRoom");
@ -827,7 +827,6 @@ loop.roomViews = (function(mozL10n) {
dispatcher={this.props.dispatcher}
hangup={this.leaveRoom}
publishStream={this.publishStream}
screenShare={screenShareData}
settingsMenuItems={settingsMenuItems}
show={!shouldRenderEditContextView}
showHangup={this.props.chatWindowDetached}

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

@ -160,24 +160,6 @@ html[dir="rtl"] .conversation-toolbar-btn-box.btn-edit-entry {
background-image: url("../img/settings-hover.svg");
}
.btn-screen-share {
background-image: url("../img/sharing.svg");
}
.btn-screen-share:hover,
.btn-screen-share:active {
background-image: url("../img/sharing-hover.svg");
}
.btn-screen-share.active {
background-image: url("../img/sharing-active.svg");
}
.btn-screen-share.disabled {
/* The screen share button is in its pending state when its disabled. */
background-image: url("../img/sharing-pending.svg");
}
/* General Call (incoming or outgoing). */
.call-action-group {
@ -319,7 +301,6 @@ html[dir="rtl"] .room-failure > .settings-control {
color: #f00;
}
.screen-share-menu.dropdown-menu,
.settings-menu.dropdown-menu {
bottom: 3.1rem;
}
@ -330,16 +311,10 @@ html[dir="rtl"] .room-failure > .settings-control {
right: 14px;
}
html[dir="rtl"] .screen-share-menu.dropdown-menu,
html[dir="rtl"] .settings-menu.dropdown-menu {
right: auto;
}
html[dir="rtl"] .screen-share-menu.dropdown-menu {
/*offset dropdown menu to be above menu button*/
left: 40px;
}
html[dir="rtl"] .settings-menu.dropdown-menu {
/*offset dropdown menu to be above menu button*/
left: 14px;

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

@ -1 +0,0 @@
<svg width="28" height="28" viewBox="0 0 28 28" xmlns="http://www.w3.org/2000/svg"><g fill="none"><rect opacity=".95" fill="#fff" x="2" y="2" width="24" height="24" rx="40"/><path d="M2 14c0 6.629 5.373 12 12 12 6.629 0 12-5.373 12-12 0-6.629-5.373-12-12-12-6.629 0-12 5.373-12 12zm-2 0c0-7.732 6.267-14 14-14 7.732 0 14 6.267 14 14 0 7.732-6.267 14-14 14-7.732 0-14-6.267-14-14z" fill-opacity=".2" fill="#000"/><rect fill="#00A9DC" x="11" y="12" width="9" height="7" rx="1"/><path d="M17 11v-.997c0-.565-.447-1.003-.998-1.003h-7.005c-.551 0-.998.449-.998 1.003v4.994c0 .565.447 1.003.998 1.003h1.002v-3.997c0-.554.446-1.003.998-1.003h6.002z" fill="#00A9DC"/></g></svg>

До

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

После

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

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

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="28px" height="28px" viewBox="0 0 28 28" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<rect id="Rectangle-1264-Copy" opacity="0.95" fill="#5CCCEE" x="2" y="2" width="24" height="24" rx="40"></rect>
<path d="M2,14 L2,14 C2,20.6288742 7.372583,26 14,26 L14,26 C20.6288742,26 26,20.627417 26,14 L26,14 C26,7.37112582 20.627417,2 14,2 L14,2 C7.37112582,2 2,7.372583 2,14 L2,14 Z M0,14 L0,14 C0,6.26754774 6.26702203,0 14,0 C21.7324523,0 28,6.26702203 28,14 C28,21.7324523 21.732978,28 14,28 C6.26754774,28 0,21.732978 0,14 L0,14 Z" id="Shape" fill-opacity="0.2" fill="#000000"></path>
<rect id="Rectangle-170-Copy-4" fill="#FFFFFF" x="11" y="12" width="9" height="7" rx="1"></rect>
<path d="M17,11 L17,10.0029293 C17,9.43788135 16.553384,9 16.0024554,9 L8.99754465,9 C8.4463114,9 8,9.44902676 8,10.0029293 L8,14.9970707 C8,15.5621186 8.44661595,16 8.99754465,16 L10,16 L10,12.0029293 C10,11.4490268 10.4463114,11 10.9975446,11 L17,11 Z" id="Rectangle-170-Copy" fill="#FFFFFF"></path>
</g>
</svg>

До

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

После

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

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

@ -1 +0,0 @@
<svg width="28" height="28" viewBox="0 0 28 28" xmlns="http://www.w3.org/2000/svg"><g fill="none"><rect opacity=".95" fill="#999999" x="2" y="2" width="24" height="24" rx="40"/><path d="M2 14c0 6.629 5.373 12 12 12 6.629 0 12-5.373 12-12 0-6.629-5.373-12-12-12-6.629 0-12 5.373-12 12zm-2 0c0-7.732 6.267-14 14-14 7.732 0 14 6.267 14 14 0 7.732-6.267 14-14 14-7.732 0-14-6.267-14-14z" fill-opacity=".2" fill="#000"/><rect fill="#4A4A4A" x="11" y="12" width="9" height="7" rx="1"/><path d="M17 11v-.997c0-.565-.447-1.003-.998-1.003h-7.005c-.551 0-.998.449-.998 1.003v4.994c0 .565.447 1.003.998 1.003h1.002v-3.997c0-.554.446-1.003.998-1.003h6.002z" fill="#4A4A4A"/></g></svg>

До

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

После

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

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

@ -1 +0,0 @@
<svg width="28" height="28" viewBox="0 0 28 28" xmlns="http://www.w3.org/2000/svg"><g fill="none"><rect opacity=".95" fill="#fff" x="2" y="2" width="24" height="24" rx="40"/><path d="M2 14c0 6.629 5.373 12 12 12 6.629 0 12-5.373 12-12 0-6.629-5.373-12-12-12-6.629 0-12 5.373-12 12zm-2 0c0-7.732 6.267-14 14-14 7.732 0 14 6.267 14 14 0 7.732-6.267 14-14 14-7.732 0-14-6.267-14-14z" fill-opacity=".2" fill="#000"/><rect fill="#4A4A4A" x="11" y="12" width="9" height="7" rx="1"/><path d="M17 11v-.997c0-.565-.447-1.003-.998-1.003h-7.005c-.551 0-.998.449-.998 1.003v4.994c0 .565.447 1.003.998 1.003h1.002v-3.997c0-.554.446-1.003.998-1.003h6.002z" fill="#4A4A4A"/></g></svg>

До

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

После

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

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

@ -17,8 +17,9 @@ loop.shared.actions = (function() {
function Action(name, schema, values) {
var validatedData = new loop.validate.Validator(schema || {})
.validate(values || {});
for (var prop in validatedData)
for (var prop in validatedData) {
this[prop] = validatedData[prop];
}
this.name = name;
}
@ -205,11 +206,9 @@ loop.shared.actions = (function() {
}),
/**
* Used to start a screen share.
* Used to start a browser tab share.
*/
StartScreenShare: Action.define("startScreenShare", {
// The part of the screen to share, e.g. "window" or "browser".
type: String
StartBrowserShare: Action.define("startBrowserShare", {
}),
/**

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

@ -257,7 +257,7 @@ loop.store.ActiveRoomStore = (function() {
"mediaStreamDestroyed",
"remoteVideoStatus",
"videoDimensionsChanged",
"startScreenShare",
"startBrowserShare",
"endScreenShare",
"updateSocialShareInfo",
"connectionStatus",
@ -920,11 +920,11 @@ loop.store.ActiveRoomStore = (function() {
},
/**
* Initiates a screen sharing publisher.
* Initiates a browser tab sharing publisher.
*
* @param {sharedActions.StartScreenShare} actionData
* @param {sharedActions.StartBrowserShare} actionData
*/
startScreenShare: function(actionData) {
startBrowserShare: function(actionData) {
// For the unit test we already set the state here, instead of indirectly
// via an action, because actions are queued thus depending on the
// asynchronous nature of `loop.request`.
@ -934,19 +934,16 @@ loop.store.ActiveRoomStore = (function() {
}));
var options = {
videoSource: actionData.type
videoSource: "browser"
};
if (options.videoSource === "browser") {
this._browserSharingListener = this._handleSwitchBrowserShare.bind(this);
this._browserSharingListener = this._handleSwitchBrowserShare.bind(this);
// Set up a listener for watching screen shares. This will get notified
// with the first windowId when it is added, so we start off the sharing
// from within the listener.
loop.request("AddBrowserSharingListener").then(this._browserSharingListener);
loop.subscribe("BrowserSwitch", this._browserSharingListener);
} else {
this._sdkDriver.startScreenShare(options);
}
// Set up a listener for watching screen shares. This will get notified
// with the first windowId when it is added, so we start off the sharing
// from within the listener.
loop.request("AddBrowserSharingListener", this.getStoreState().windowId)
.then(this._browserSharingListener);
loop.subscribe("BrowserSwitch", this._browserSharingListener);
},
/**

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

@ -10,7 +10,6 @@ loop.shared.views = (function(_, mozL10n) {
var sharedActions = loop.shared.actions;
var sharedModels = loop.shared.models;
var sharedMixins = loop.shared.mixins;
var SCREEN_SHARE_STATES = loop.shared.utils.SCREEN_SHARE_STATES;
/**
* Hang-up control button.
@ -104,114 +103,6 @@ loop.shared.views = (function(_, mozL10n) {
}
});
/**
* Screen sharing control button.
*
* Required props:
* - {loop.Dispatcher} dispatcher The dispatcher instance
* - {Boolean} visible Set to true to display the button
* - {String} state One of the screen sharing states, see
* loop.shared.utils.SCREEN_SHARE_STATES
*/
var ScreenShareControlButton = React.createClass({displayName: "ScreenShareControlButton",
mixins: [sharedMixins.DropdownMenuMixin()],
propTypes: {
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
state: React.PropTypes.string.isRequired,
visible: React.PropTypes.bool.isRequired
},
getInitialState: function() {
var os = loop.shared.utils.getOS();
var osVersion = loop.shared.utils.getOSVersion();
// Disable screensharing on older OSX and Windows versions.
if ((os.indexOf("mac") > -1 && osVersion.major <= 10 && osVersion.minor <= 6) ||
(os.indexOf("win") > -1 && osVersion.major <= 5 && osVersion.minor <= 2)) {
return { windowSharingDisabled: true };
}
return { windowSharingDisabled: false };
},
handleClick: function() {
if (this.props.state === SCREEN_SHARE_STATES.ACTIVE) {
this.props.dispatcher.dispatch(
new sharedActions.EndScreenShare({}));
} else {
this.toggleDropdownMenu();
}
},
_startScreenShare: function(type) {
this.props.dispatcher.dispatch(new sharedActions.StartScreenShare({
type: type
}));
},
_handleShareTabs: function() {
this._startScreenShare("browser");
this.hideDropdownMenu();
},
_handleShareWindows: function() {
this._startScreenShare("window");
this.hideDropdownMenu();
},
_getTitle: function() {
var prefix = this.props.state === SCREEN_SHARE_STATES.ACTIVE ?
"active" : "inactive";
return mozL10n.get(prefix + "_screenshare_button_title");
},
render: function() {
if (!this.props.visible) {
return null;
}
var cx = classNames;
var isActive = this.props.state === SCREEN_SHARE_STATES.ACTIVE;
var screenShareClasses = cx({
"btn": true,
"btn-screen-share": true,
"transparent-button": true,
"menu-showing": this.state.showMenu,
"active": isActive,
"disabled": this.props.state === SCREEN_SHARE_STATES.PENDING
});
var dropdownMenuClasses = cx({
"screen-share-menu": true,
"dropdown-menu": true,
"hide": !this.state.showMenu
});
var windowSharingClasses = cx({
"dropdown-menu-item": true,
"disabled": this.state.windowSharingDisabled
});
return (
React.createElement("div", null,
React.createElement("button", {className: screenShareClasses,
onClick: this.handleClick,
ref: "anchor",
title: this._getTitle()},
isActive ? null : React.createElement("span", {className: "chevron"})
),
React.createElement("ul", {className: dropdownMenuClasses, ref: "menu"},
React.createElement("li", {className: "dropdown-menu-item", onClick: this._handleShareTabs},
mozL10n.get("share_tabs_button_title2")
),
React.createElement("li", {className: windowSharingClasses, onClick: this._handleShareWindows},
mozL10n.get("share_windows_button_title")
)
)
)
);
}
});
/**
* Settings control button.
*/
@ -391,7 +282,6 @@ loop.shared.views = (function(_, mozL10n) {
return {
video: { enabled: true, visible: true },
audio: { enabled: true, visible: true },
screenShare: { state: SCREEN_SHARE_STATES.INACTIVE, visible: false },
settingsMenuItems: null,
showHangup: true
};
@ -408,7 +298,6 @@ loop.shared.views = (function(_, mozL10n) {
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
hangup: React.PropTypes.func.isRequired,
publishStream: React.PropTypes.func.isRequired,
screenShare: React.PropTypes.object,
settingsMenuItems: React.PropTypes.array,
show: React.PropTypes.bool.isRequired,
showHangup: React.PropTypes.bool,
@ -525,11 +414,6 @@ loop.shared.views = (function(_, mozL10n) {
visible: this.props.audio.visible})
)
),
React.createElement("li", {className: "conversation-toolbar-btn-box"},
React.createElement(ScreenShareControlButton, {dispatcher: this.props.dispatcher,
state: this.props.screenShare.state,
visible: this.props.screenShare.visible})
),
React.createElement("li", {className: "conversation-toolbar-btn-box btn-edit-entry"},
React.createElement(SettingsControlButton, {menuItems: this.props.settingsMenuItems})
)
@ -1141,7 +1025,6 @@ loop.shared.views = (function(_, mozL10n) {
MediaView: MediaView,
LoadingView: LoadingView,
SettingsControlButton: SettingsControlButton,
ScreenShareControlButton: ScreenShareControlButton,
NotificationListView: NotificationListView
};
})(_, navigator.mozL10n || document.mozL10n);

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

@ -10,7 +10,6 @@ loop.shared.views = (function(_, mozL10n) {
var sharedActions = loop.shared.actions;
var sharedModels = loop.shared.models;
var sharedMixins = loop.shared.mixins;
var SCREEN_SHARE_STATES = loop.shared.utils.SCREEN_SHARE_STATES;
/**
* Hang-up control button.
@ -104,114 +103,6 @@ loop.shared.views = (function(_, mozL10n) {
}
});
/**
* Screen sharing control button.
*
* Required props:
* - {loop.Dispatcher} dispatcher The dispatcher instance
* - {Boolean} visible Set to true to display the button
* - {String} state One of the screen sharing states, see
* loop.shared.utils.SCREEN_SHARE_STATES
*/
var ScreenShareControlButton = React.createClass({
mixins: [sharedMixins.DropdownMenuMixin()],
propTypes: {
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
state: React.PropTypes.string.isRequired,
visible: React.PropTypes.bool.isRequired
},
getInitialState: function() {
var os = loop.shared.utils.getOS();
var osVersion = loop.shared.utils.getOSVersion();
// Disable screensharing on older OSX and Windows versions.
if ((os.indexOf("mac") > -1 && osVersion.major <= 10 && osVersion.minor <= 6) ||
(os.indexOf("win") > -1 && osVersion.major <= 5 && osVersion.minor <= 2)) {
return { windowSharingDisabled: true };
}
return { windowSharingDisabled: false };
},
handleClick: function() {
if (this.props.state === SCREEN_SHARE_STATES.ACTIVE) {
this.props.dispatcher.dispatch(
new sharedActions.EndScreenShare({}));
} else {
this.toggleDropdownMenu();
}
},
_startScreenShare: function(type) {
this.props.dispatcher.dispatch(new sharedActions.StartScreenShare({
type: type
}));
},
_handleShareTabs: function() {
this._startScreenShare("browser");
this.hideDropdownMenu();
},
_handleShareWindows: function() {
this._startScreenShare("window");
this.hideDropdownMenu();
},
_getTitle: function() {
var prefix = this.props.state === SCREEN_SHARE_STATES.ACTIVE ?
"active" : "inactive";
return mozL10n.get(prefix + "_screenshare_button_title");
},
render: function() {
if (!this.props.visible) {
return null;
}
var cx = classNames;
var isActive = this.props.state === SCREEN_SHARE_STATES.ACTIVE;
var screenShareClasses = cx({
"btn": true,
"btn-screen-share": true,
"transparent-button": true,
"menu-showing": this.state.showMenu,
"active": isActive,
"disabled": this.props.state === SCREEN_SHARE_STATES.PENDING
});
var dropdownMenuClasses = cx({
"screen-share-menu": true,
"dropdown-menu": true,
"hide": !this.state.showMenu
});
var windowSharingClasses = cx({
"dropdown-menu-item": true,
"disabled": this.state.windowSharingDisabled
});
return (
<div>
<button className={screenShareClasses}
onClick={this.handleClick}
ref="anchor"
title={this._getTitle()}>
{isActive ? null : <span className="chevron"/>}
</button>
<ul className={dropdownMenuClasses} ref="menu">
<li className="dropdown-menu-item" onClick={this._handleShareTabs}>
{mozL10n.get("share_tabs_button_title2")}
</li>
<li className={windowSharingClasses} onClick={this._handleShareWindows}>
{mozL10n.get("share_windows_button_title")}
</li>
</ul>
</div>
);
}
});
/**
* Settings control button.
*/
@ -391,7 +282,6 @@ loop.shared.views = (function(_, mozL10n) {
return {
video: { enabled: true, visible: true },
audio: { enabled: true, visible: true },
screenShare: { state: SCREEN_SHARE_STATES.INACTIVE, visible: false },
settingsMenuItems: null,
showHangup: true
};
@ -408,7 +298,6 @@ loop.shared.views = (function(_, mozL10n) {
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
hangup: React.PropTypes.func.isRequired,
publishStream: React.PropTypes.func.isRequired,
screenShare: React.PropTypes.object,
settingsMenuItems: React.PropTypes.array,
show: React.PropTypes.bool.isRequired,
showHangup: React.PropTypes.bool,
@ -525,11 +414,6 @@ loop.shared.views = (function(_, mozL10n) {
visible={this.props.audio.visible}/>
</div>
</li>
<li className="conversation-toolbar-btn-box">
<ScreenShareControlButton dispatcher={this.props.dispatcher}
state={this.props.screenShare.state}
visible={this.props.screenShare.visible} />
</li>
<li className="conversation-toolbar-btn-box btn-edit-entry">
<SettingsControlButton menuItems={this.props.settingsMenuItems} />
</li>
@ -1141,7 +1025,6 @@ loop.shared.views = (function(_, mozL10n) {
MediaView: MediaView,
LoadingView: LoadingView,
SettingsControlButton: SettingsControlButton,
ScreenShareControlButton: ScreenShareControlButton,
NotificationListView: NotificationListView
};
})(_, navigator.mozL10n || document.mozL10n);

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

@ -6,42 +6,36 @@
/* Only apply to browser.xul documents */
@-moz-document url("chrome://browser/content/browser.xul") {
/**
* XXX Due to bug 1228542, anything in this file that overrides a browser style
* must specify !important. Otherwise the style won't get applied correctly
* due to the limitations caused by the bug.
*/
notification[value="loop-sharing-notification"] {
background: #00a9dc !important;
padding: 0 !important;
border: 0 !important;
background: #00a9dc;
padding: 0;
border: 0;
}
notification[value="loop-sharing-notification"].paused {
background: #ebebeb !important;
background: #ebebeb;
}
notification[value="loop-sharing-notification"] .notification-button {
background: #fff !important;
border-radius: 0 !important;
background: #fff;
border-radius: 0;
}
notification[value="loop-sharing-notification"].paused .notification-button {
background: #57bd35 !important;
background: #57bd35;
}
notification[value="loop-sharing-notification"].paused .notification-button:hover {
background: #39a017 !important;
background: #39a017;
}
notification[value="loop-sharing-notification"] .notification-button:hover,
notification[value="loop-sharing-notification"].paused .notification-button-default:hover {
background: #ebebeb !important;
background: #ebebeb;
}
notification[value="loop-sharing-notification"] .notification-button-default,
notification[value="loop-sharing-notification"].paused .notification-button-default {
background: #fff !important;
background: #fff;
}
}

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

@ -6,20 +6,14 @@
/* Only apply to browser.xul documents */
@-moz-document url("chrome://browser/content/browser.xul") {
/**
* XXX Due to bug 1228542, anything in this file that overrides a browser style
* must specify !important. Otherwise the style won't get applied correctly
* due to the limitations caused by the bug.
*/
/*
XXX Copied from browser/themes/<platform>/browser.css. Should really be
changing the sizes of icons in files to 16px x 16px and no borders.
*/
:-moz-any(toolbar, .widget-overflow-list) #loop-button > .toolbarbutton-icon,
:-moz-any(toolbar, .widget-overflow-list) #loop-button > :-moz-any(.toolbarbutton-menubutton-button, .toolbarbutton-badge-stack) > .toolbarbutton-icon {
max-width: 18px !important;
margin: 0 !important;
max-width: 18px;
margin: 0;
}
#loop-button {
@ -99,7 +93,7 @@
/* Make sure that the state icons are not shown in the customization palette. */
toolbarpaletteitem[place="palette"] > #loop-button {
-moz-image-region: rect(0, 64px, 64px, 0) !important;
-moz-image-region: rect(0, 64px, 64px, 0);
}
#loop-button[cui-areatype="menu-panel"][state="disabled"],
@ -137,7 +131,7 @@
/* Make sure that the state icons are not shown in the customization palette. */
toolbarpaletteitem[place="palette"] > #loop-button {
-moz-image-region: rect(0, 32px, 32px, 0) !important;
-moz-image-region: rect(0, 32px, 32px, 0);
}
#loop-button[cui-areatype="menu-panel"][state="disabled"],
@ -167,120 +161,120 @@
}
notification[value="loop-sharing-notification"] {
-moz-appearance: none !important;
height: 40px !important;
background-color: #00a9dc !important;
box-shadow: 0 40px 1px rgba(0,0,0,.5) inset !important;
-moz-appearance: none;
height: 40px;
background-color: #00a9dc;
box-shadow: 0 40px 1px rgba(0,0,0,.5) inset;
}
notification[value="loop-sharing-notification"].paused {
background-color: #ebebeb !important;
background-color: #ebebeb;
}
notification[value="loop-sharing-notification"] .notification-inner {
color: #fff !important;
padding: 0 !important;
color: #fff;
padding: 0;
}
notification[value="loop-sharing-notification"].paused .notification-inner {
color: #00a9dc !important;
color: #00a9dc;
}
notification[value="loop-sharing-notification"] .notification-button {
-moz-appearance: none !important;
background-color: #fff !important;
border: 0 !important;
border-right: solid 1px #ebebeb !important;
width: 100px !important;
height: 40px !important;
margin: 0 !important;
list-style-image: url(chrome://loop/content/shared/img/pause-12x12.svg) !important;
box-shadow: 0 40px 1px rgba(0,0,0,.5) inset !important;
text-shadow: none !important;
-moz-appearance: none;
background-color: #fff;
border: 0;
border-right: solid 1px #ebebeb;
width: 100px;
height: 40px;
margin: 0;
list-style-image: url(chrome://loop/content/shared/img/pause-12x12.svg);
box-shadow: 0 40px 1px rgba(0,0,0,.5) inset;
text-shadow: none;
}
notification[value="loop-sharing-notification"] .notification-button:-moz-locale-dir(rtl) {
border-right: 0 !important;
border-left: solid 1px #ebebeb !important;
border-right: 0;
border-left: solid 1px #ebebeb;
}
notification[value="loop-sharing-notification"].paused .notification-button {
background-color: #57bd35 !important;
color: #fff !important;
list-style-image: url(chrome://loop/content/shared/img/play-12x12.svg) !important;
background-color: #57bd35;
color: #fff;
list-style-image: url(chrome://loop/content/shared/img/play-12x12.svg);
}
notification[value="loop-sharing-notification"].paused .notification-button:hover {
background-color: #39a017 !important;
background-color: #39a017;
}
notification[value="loop-sharing-notification"] .notification-button:hover,
notification[value="loop-sharing-notification"].paused .notification-button-default:hover {
background-color: #ebebeb !important;
background-color: #ebebeb;
}
notification[value="loop-sharing-notification"] .notification-button-default,
notification[value="loop-sharing-notification"].paused .notification-button-default {
color: #d92215 !important;
background-color: #fff !important;
border-right: 0 !important;
list-style-image: url(chrome://loop/content/shared/img/stop-12x12.svg) !important;
color: #d92215;
background-color: #fff;
border-right: 0;
list-style-image: url(chrome://loop/content/shared/img/stop-12x12.svg);
}
notification[value="loop-sharing-notification"] .notification-button .button-icon {
display: block !important;
-moz-margin-end: 6px !important;
display: block;
-moz-margin-end: 6px;
}
notification[value="loop-sharing-notification"] .button-menubutton-button {
min-width: 0 !important;
min-width: 0;
}
notification[value="loop-sharing-notification"] .messageImage {
list-style-image: url(chrome://loop/content/shared/img/icons-16x16.svg#loop-icon-white) !important;
margin-inline-start: 14px !important;
list-style-image: url(chrome://loop/content/shared/img/icons-16x16.svg#loop-icon-white);
margin-inline-start: 14px;
}
notification[value="loop-sharing-notification"].paused .messageImage {
list-style-image: url(chrome://loop/content/shared/img/icons-16x16.svg#loop-icon-still) !important;
list-style-image: url(chrome://loop/content/shared/img/icons-16x16.svg#loop-icon-still);
}
notification[value="loop-sharing-notification"] .close-icon {
display: none !important;
display: none;
}
chatbox[src^="about:loopconversation#"] > .chat-titlebar {
background-color: #00a9dc !important;
border-color: #00a9dc !important;
background-color: #00a9dc;
border-color: #00a9dc;
}
chatbox[src^="about:loopconversation#"] .chat-title {
color: white !important;
color: white;
}
chatbox[src^="about:loopconversation#"] .chat-minimize-button {
list-style-image: url("chrome://browser/skin/social/chat-icons.svg#minimize-white") !important;
list-style-image: url("chrome://browser/skin/social/chat-icons.svg#minimize-white");
}
chatbox[src^="about:loopconversation#"] .chat-swap-button {
list-style-image: url("chrome://browser/skin/social/chat-icons.svg#expand-white") !important;
list-style-image: url("chrome://browser/skin/social/chat-icons.svg#expand-white");
}
.chat-loop-hangup {
list-style-image: url("chrome://browser/skin/social/chat-icons.svg#exit-white") !important;
background-color: #d13f1a !important;
border: 1px solid #d13f1a !important;
border-top-right-radius: 4px !important;
width: 32px !important;
height: 26px !important;
margin-top: -6px !important;
margin-bottom: -5px !important;
-moz-margin-start: 6px !important;
-moz-margin-end: -5px !important;
list-style-image: url("chrome://browser/skin/social/chat-icons.svg#exit-white");
background-color: #d13f1a;
border: 1px solid #d13f1a;
border-top-right-radius: 4px;
width: 32px;
height: 26px;
margin-top: -6px;
margin-bottom: -5px;
-moz-margin-start: 6px;
-moz-margin-end: -5px;
}
.chat-toolbarbutton.chat-loop-hangup:-moz-any(:hover,:hover:active) {
background-color: #ef6745 !important;
border-color: #ef6745 !important;
background-color: #ef6745;
border-color: #ef6745;
}
}

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

@ -166,7 +166,7 @@
}
window.OTProperties = {
cdnURL: "shared/libs/"
cdnURL: "shared/vendor/"
};
window.OTProperties.assetURL = window.OTProperties.cdnURL + "sdk-content/";
window.OTProperties.configURL = window.OTProperties.assetURL + "js/dynamic_config.min.js";

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

@ -12,8 +12,6 @@ mute_local_audio_button_title=Mute your audio
unmute_local_audio_button_title=Unmute your audio
mute_local_video_button_title2=Disable video
unmute_local_video_button_title2=Enable video
active_screenshare_button_title=Stop sharing
inactive_screenshare_button_title=Share your screen
welcome=Welcome to the {{clientShortname}} web client.
incompatible_browser_heading=Oops!

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

@ -14,9 +14,9 @@
"devDependencies": {
"classnames": "2.2.x",
"compression": "1.5.x",
"eslint": "1.6.x",
"eslint": "1.10.x",
"eslint-plugin-mozilla": "../../../../testing/eslint-plugin-mozilla",
"eslint-plugin-react": "3.5.x",
"eslint-plugin-react": "3.10.x",
"exports-loader": "0.6.x",
"expose-loader": "0.7.x",
"express": "4.x",

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

@ -400,11 +400,9 @@ describe("loop.roomViews", function() {
expect(muteBtn.classList.contains("muted")).eql(true);
});
it("should dispatch a `StartScreenShare` action when sharing is not active and the screen share button is pressed", function() {
it("should dispatch a `SetMute` action when the mute button is pressed", function() {
view = mountTestComponent();
view.setState({ screenSharingState: SCREEN_SHARE_STATES.INACTIVE });
var muteBtn = view.getDOMNode().querySelector(".btn-mute-video");
React.addons.TestUtils.Simulate.click(muteBtn);
@ -437,6 +435,15 @@ describe("loop.roomViews", function() {
expectActionDispatched(component);
});
it("should dispatch a `StartBrowserShare` action when the SESSION_CONNECTED state is entered", function() {
activeRoomStore.setStoreState({ roomState: ROOM_STATES.READY });
var component = mountTestComponent();
activeRoomStore.setStoreState({ roomState: ROOM_STATES.SESSION_CONNECTED });
expectActionDispatched("startBrowserShare");
});
});
describe("#render", function() {

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

@ -186,12 +186,6 @@ class Test1BrowserCall(MarionetteTestCase):
self.switch_to_chatbox()
self.check_received_message("test2")
def local_enable_screenshare(self):
self.switch_to_chatbox()
button = self.marionette.find_element(By.CLASS_NAME, "btn-screen-share")
button.click()
def standalone_check_remote_screenshare(self):
self.switch_to_standalone()
self.check_video(".screen-share-video")
@ -269,43 +263,41 @@ class Test1BrowserCall(MarionetteTestCase):
def test_1_browser_call(self):
self.switch_to_panel()
self.local_start_a_conversation()
# self.local_start_a_conversation()
# Check the self video in the conversation window
self.local_check_room_self_video()
# # Check the self video in the conversation window
# self.local_check_room_self_video()
# make sure that the media start time is not initialized
self.local_check_media_start_time_uninitialized()
# # make sure that the media start time is not initialized
# self.local_check_media_start_time_uninitialized()
room_url = self.local_get_and_verify_room_url()
# room_url = self.local_get_and_verify_room_url()
# load the link clicker interface into the current content browser
self.standalone_load_and_join_room(room_url)
# # load the link clicker interface into the current content browser
# self.standalone_load_and_join_room(room_url)
# Check we get the video streams
self.standalone_check_remote_video()
self.local_check_remote_video()
# # Check we get the video streams
# self.standalone_check_remote_video()
# self.local_check_remote_video()
# Check text messaging
self.check_text_messaging()
# # Check text messaging
# self.check_text_messaging()
# since bi-directional media is connected, make sure we've set
# the start time
self.local_check_media_start_time_initialized()
# # since bi-directional media is connected, make sure we've set
# # the start time
# self.local_check_media_start_time_initialized()
# XXX To enable this, we either need to navigate the permissions prompt
# or have a route where we don't need the permissions prompt.
# self.local_enable_screenshare()
# # Check that screenshare was automatically started
# self.standalone_check_remote_screenshare()
# We hangup on the remote (standalone) side, because this also leaves
# the local chatbox with the local publishing media still connected,
# which means that the local_check_connection_length below
# verifies that the connection is noted at the time the remote media
# drops, rather than waiting until the window closes.
self.remote_leave_room()
# # We hangup on the remote (standalone) side, because this also leaves
# # the local chatbox with the local publishing media still connected,
# # which means that the local_check_connection_length below
# # verifies that the connection is noted at the time the remote media
# # drops, rather than waiting until the window closes.
# self.remote_leave_room()
self.local_check_connection_length_noted()
# self.local_check_connection_length_noted()
def tearDown(self):
self.loop_test_servers.shutdown()

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

@ -199,9 +199,7 @@ describe("loop.store.ActiveRoomStore", function() {
it("should remove the sharing listener", function() {
// Setup the listener.
store.startScreenShare(new sharedActions.StartScreenShare({
type: "browser"
}));
store.startBrowserShare(new sharedActions.StartBrowserShare());
// Now simulate room failure.
store.roomFailure(new sharedActions.RoomFailure({
@ -1257,9 +1255,7 @@ describe("loop.store.ActiveRoomStore", function() {
it("should remove the sharing listener", function() {
// Setup the listener.
store.startScreenShare(new sharedActions.StartScreenShare({
type: "browser"
}));
store.startBrowserShare(new sharedActions.StartBrowserShare());
// Now simulate connection failure.
store.connectionFailure(connectionFailureAction);
@ -1539,15 +1535,13 @@ describe("loop.store.ActiveRoomStore", function() {
});
});
describe("#startScreenShare", function() {
describe("#startBrowserShare", function() {
afterEach(function() {
store.endScreenShare();
});
it("should set the state to 'pending'", function() {
store.startScreenShare(new sharedActions.StartScreenShare({
type: "window"
}));
store.startBrowserShare(new sharedActions.StartBrowserShare());
sinon.assert.calledOnce(dispatcher.dispatch);
sinon.assert.calledWith(dispatcher.dispatch,
@ -1556,29 +1550,14 @@ describe("loop.store.ActiveRoomStore", function() {
}));
});
it("should invoke the SDK driver with the correct options for window sharing", function() {
store.startScreenShare(new sharedActions.StartScreenShare({
type: "window"
}));
sinon.assert.calledOnce(fakeSdkDriver.startScreenShare);
sinon.assert.calledWith(fakeSdkDriver.startScreenShare, {
videoSource: "window"
});
});
it("should add a browser sharing listener for tab sharing", function() {
store.startScreenShare(new sharedActions.StartScreenShare({
type: "browser"
}));
store.startBrowserShare(new sharedActions.StartBrowserShare());
sinon.assert.calledOnce(requestStubs.AddBrowserSharingListener);
});
it("should invoke the SDK driver with the correct options for tab sharing", function() {
store.startScreenShare(new sharedActions.StartScreenShare({
type: "browser"
}));
store.startBrowserShare(new sharedActions.StartBrowserShare());
sinon.assert.calledOnce(fakeSdkDriver.startScreenShare);
sinon.assert.calledWith(fakeSdkDriver.startScreenShare, {
@ -1593,9 +1572,7 @@ describe("loop.store.ActiveRoomStore", function() {
describe("Screen share Events", function() {
beforeEach(function() {
store.startScreenShare(new sharedActions.StartScreenShare({
type: "browser"
}));
store.startBrowserShare(new sharedActions.StartBrowserShare());
store.setStoreState({
screenSharingState: SCREEN_SHARE_STATES.ACTIVE
@ -1652,9 +1629,7 @@ describe("loop.store.ActiveRoomStore", function() {
it("should remove the sharing listener", function() {
// Setup the listener.
store.startScreenShare(new sharedActions.StartScreenShare({
type: "browser"
}));
store.startBrowserShare(new sharedActions.StartBrowserShare());
// Now stop the screen share.
store.endScreenShare();
@ -1807,9 +1782,7 @@ describe("loop.store.ActiveRoomStore", function() {
it("should remove the sharing listener", function() {
// Setup the listener.
store.startScreenShare(new sharedActions.StartScreenShare({
type: "browser"
}));
store.startBrowserShare(new sharedActions.StartBrowserShare());
// Now unload the window.
store.windowUnload();
@ -1864,9 +1837,7 @@ describe("loop.store.ActiveRoomStore", function() {
it("should remove the sharing listener", function() {
// Setup the listener.
store.startScreenShare(new sharedActions.StartScreenShare({
type: "browser"
}));
store.startBrowserShare(new sharedActions.StartBrowserShare());
// Now leave the room.
store.leaveRoom();

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

@ -11,7 +11,6 @@ describe("loop.shared.views", function() {
var sharedActions = loop.shared.actions;
var sharedModels = loop.shared.models;
var sharedViews = loop.shared.views;
var SCREEN_SHARE_STATES = loop.shared.utils.SCREEN_SHARE_STATES;
var getReactElementByClass = TestUtils.findRenderedDOMComponentWithClass;
var sandbox, fakeAudioXHR, dispatcher, OS, OSVersion;
@ -109,186 +108,6 @@ describe("loop.shared.views", function() {
});
});
describe("ScreenShareControlButton", function() {
it("should render a visible share button", function() {
var comp = TestUtils.renderIntoDocument(
React.createElement(sharedViews.ScreenShareControlButton, {
dispatcher: dispatcher,
visible: true,
state: SCREEN_SHARE_STATES.INACTIVE
}));
expect(comp.getDOMNode().classList.contains("active")).eql(false);
expect(comp.getDOMNode().classList.contains("disabled")).eql(false);
});
it("should render a disabled share button when share is pending", function() {
var comp = TestUtils.renderIntoDocument(
React.createElement(sharedViews.ScreenShareControlButton, {
dispatcher: dispatcher,
visible: true,
state: SCREEN_SHARE_STATES.PENDING
}));
var node = comp.getDOMNode().querySelector(".btn-screen-share");
expect(node.classList.contains("active")).eql(false);
expect(node.classList.contains("disabled")).eql(true);
});
it("should render an active share button", function() {
var comp = TestUtils.renderIntoDocument(
React.createElement(sharedViews.ScreenShareControlButton, {
dispatcher: dispatcher,
visible: true,
state: SCREEN_SHARE_STATES.ACTIVE
}));
var node = comp.getDOMNode().querySelector(".btn-screen-share");
expect(node.classList.contains("active")).eql(true);
expect(node.classList.contains("disabled")).eql(false);
});
it("should show the screenshare dropdown on click when the state is not active",
function() {
var comp = TestUtils.renderIntoDocument(
React.createElement(sharedViews.ScreenShareControlButton, {
dispatcher: dispatcher,
visible: true,
state: SCREEN_SHARE_STATES.INACTIVE
}));
expect(comp.state.showMenu).eql(false);
TestUtils.Simulate.click(comp.getDOMNode().querySelector(".btn-screen-share"));
expect(comp.state.showMenu).eql(true);
});
it("should dispatch a 'browser' StartScreenShare action on option click",
function() {
var comp = TestUtils.renderIntoDocument(
React.createElement(sharedViews.ScreenShareControlButton, {
dispatcher: dispatcher,
visible: true,
state: SCREEN_SHARE_STATES.INACTIVE
}));
TestUtils.Simulate.click(comp.getDOMNode().querySelector(
".screen-share-menu > li"));
sinon.assert.calledOnce(dispatcher.dispatch);
sinon.assert.calledWithExactly(dispatcher.dispatch,
new sharedActions.StartScreenShare({ type: "browser" }));
});
it("should close the dropdown on 'browser' option click", function() {
var comp = TestUtils.renderIntoDocument(
React.createElement(sharedViews.ScreenShareControlButton, {
dispatcher: dispatcher,
visible: true,
state: SCREEN_SHARE_STATES.INACTIVE
}));
sandbox.stub(comp, "hideDropdownMenu");
TestUtils.Simulate.click(comp.getDOMNode().querySelector(
".screen-share-menu > li"));
sinon.assert.calledOnce(comp.hideDropdownMenu);
});
it("should dispatch a 'window' StartScreenShare action on option click",
function() {
var comp = TestUtils.renderIntoDocument(
React.createElement(sharedViews.ScreenShareControlButton, {
dispatcher: dispatcher,
visible: true,
state: SCREEN_SHARE_STATES.INACTIVE
}));
TestUtils.Simulate.click(comp.getDOMNode().querySelector(
".screen-share-menu > li:last-child"));
sinon.assert.calledOnce(dispatcher.dispatch);
sinon.assert.calledWithExactly(dispatcher.dispatch,
new sharedActions.StartScreenShare({ type: "window" }));
});
it("should close the dropdown on 'window' option click", function() {
var comp = TestUtils.renderIntoDocument(
React.createElement(sharedViews.ScreenShareControlButton, {
dispatcher: dispatcher,
visible: true,
state: SCREEN_SHARE_STATES.INACTIVE
}));
sandbox.stub(comp, "hideDropdownMenu");
TestUtils.Simulate.click(comp.getDOMNode().querySelector(
".screen-share-menu > li:last-child"));
sinon.assert.calledOnce(comp.hideDropdownMenu);
});
it("should have the 'window' option enabled", function() {
var comp = TestUtils.renderIntoDocument(
React.createElement(sharedViews.ScreenShareControlButton, {
dispatcher: dispatcher,
visible: true,
state: SCREEN_SHARE_STATES.INACTIVE
}));
var node = comp.getDOMNode().querySelector(".screen-share-menu > li:last-child");
expect(node.classList.contains("disabled")).eql(false);
});
it("should disable the 'window' option on Windows XP", function() {
OS = "win";
OSVersion = { major: 5, minor: 1 };
var comp = TestUtils.renderIntoDocument(
React.createElement(sharedViews.ScreenShareControlButton, {
dispatcher: dispatcher,
visible: true,
state: SCREEN_SHARE_STATES.INACTIVE
}));
var node = comp.getDOMNode().querySelector(".screen-share-menu > li:last-child");
expect(node.classList.contains("disabled")).eql(true);
});
it("should disable the 'window' option on OSX 10.6", function() {
OS = "mac";
OSVersion = { major: 10, minor: 6 };
var comp = TestUtils.renderIntoDocument(
React.createElement(sharedViews.ScreenShareControlButton, {
dispatcher: dispatcher,
visible: true,
state: SCREEN_SHARE_STATES.INACTIVE
}));
var node = comp.getDOMNode().querySelector(".screen-share-menu > li:last-child");
expect(node.classList.contains("disabled")).eql(true);
});
it("should dispatch a EndScreenShare action on click when the state is active",
function() {
var comp = TestUtils.renderIntoDocument(
React.createElement(sharedViews.ScreenShareControlButton, {
dispatcher: dispatcher,
visible: true,
state: SCREEN_SHARE_STATES.ACTIVE
}));
TestUtils.Simulate.click(comp.getDOMNode().querySelector(".btn-screen-share"));
sinon.assert.calledOnce(dispatcher.dispatch);
sinon.assert.calledWithExactly(dispatcher.dispatch,
new sharedActions.EndScreenShare({}));
});
});
describe("SettingsControlButton", function() {
var requestStubs;
var support_url = "https://support.com";

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

@ -38,7 +38,6 @@
var ROOM_STATES = loop.store.ROOM_STATES;
var CALL_TYPES = loop.shared.utils.CALL_TYPES;
var FAILURE_DETAILS = loop.shared.utils.FAILURE_DETAILS;
var SCREEN_SHARE_STATES = loop.shared.utils.SCREEN_SHARE_STATES;
// Local helpers
function returnTrue() {
@ -743,7 +742,6 @@
dispatcher: dispatcher,
hangup: noop,
publishStream: noop,
screenShare: { state: SCREEN_SHARE_STATES.INACTIVE, visible: true},
settingsMenuItems: [{ id: "feedback" }],
show: true,
video: { enabled: true, visible: true}})
@ -751,14 +749,13 @@
),
React.createElement(FramedExample, {dashed: true,
height: 56,
summary: "Video muted, Screen share pending",
summary: "Video muted",
width: 300},
React.createElement("div", {className: "fx-embedded"},
React.createElement(ConversationToolbar, {audio: { enabled: true, visible: true},
dispatcher: dispatcher,
hangup: noop,
publishStream: noop,
screenShare: { state: SCREEN_SHARE_STATES.PENDING, visible: true},
settingsMenuItems: [{ id: "feedback" }],
show: true,
video: { enabled: false, visible: true}})
@ -766,14 +763,13 @@
),
React.createElement(FramedExample, {dashed: true,
height: 56,
summary: "Audio muted, Screen share active",
summary: "Audio muted",
width: 300},
React.createElement("div", {className: "fx-embedded"},
React.createElement(ConversationToolbar, {audio: { enabled: false, visible: true},
dispatcher: dispatcher,
hangup: noop,
publishStream: noop,
screenShare: { state: SCREEN_SHARE_STATES.ACTIVE, visible: true},
settingsMenuItems: [{ id: "feedback" }],
show: true,
video: { enabled: true, visible: true}})

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

@ -38,7 +38,6 @@
var ROOM_STATES = loop.store.ROOM_STATES;
var CALL_TYPES = loop.shared.utils.CALL_TYPES;
var FAILURE_DETAILS = loop.shared.utils.FAILURE_DETAILS;
var SCREEN_SHARE_STATES = loop.shared.utils.SCREEN_SHARE_STATES;
// Local helpers
function returnTrue() {
@ -743,7 +742,6 @@
dispatcher={dispatcher}
hangup={noop}
publishStream={noop}
screenShare={{ state: SCREEN_SHARE_STATES.INACTIVE, visible: true }}
settingsMenuItems={[{ id: "feedback" }]}
show={true}
video={{ enabled: true, visible: true }} />
@ -751,14 +749,13 @@
</FramedExample>
<FramedExample dashed={true}
height={56}
summary="Video muted, Screen share pending"
summary="Video muted"
width={300}>
<div className="fx-embedded">
<ConversationToolbar audio={{ enabled: true, visible: true }}
dispatcher={dispatcher}
hangup={noop}
publishStream={noop}
screenShare={{ state: SCREEN_SHARE_STATES.PENDING, visible: true }}
settingsMenuItems={[{ id: "feedback" }]}
show={true}
video={{ enabled: false, visible: true }} />
@ -766,14 +763,13 @@
</FramedExample>
<FramedExample dashed={true}
height={56}
summary="Audio muted, Screen share active"
summary="Audio muted"
width={300}>
<div className="fx-embedded">
<ConversationToolbar audio={{ enabled: false, visible: true }}
dispatcher={dispatcher}
hangup={noop}
publishStream={noop}
screenShare={{ state: SCREEN_SHARE_STATES.ACTIVE, visible: true }}
settingsMenuItems={[{ id: "feedback" }]}
show={true}
video={{ enabled: true, visible: true }} />

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

@ -104,10 +104,6 @@ mute_local_audio_button_title=Mute your audio
unmute_local_audio_button_title=Unmute your audio
mute_local_video_button_title2=Disable video
unmute_local_video_button_title2=Enable video
active_screenshare_button_title=Stop sharing
inactive_screenshare_button_title=Share your screen
share_tabs_button_title2=Share your Tabs
share_windows_button_title=Share other Windows
self_view_hidden_message=Self-view hidden but still being sent; resize window to show

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

@ -20,10 +20,10 @@ if test -n "$MOZ_NATIVE_ICU"; then
PKG_CHECK_MODULES(MOZ_ICU, icu-i18n >= 50.1)
MOZ_SHARED_ICU=1
else
MOZ_ICU_CFLAGS="-I$_topsrcdir/intl/icu/source/common -I$_topsrcdir/intl/icu/source/i18n"
AC_SUBST_LIST(MOZ_ICU_CFLAGS)
MOZ_ICU_INCLUDES="/intl/icu/source/common /intl/icu/source/i18n"
fi
AC_SUBST_LIST(MOZ_ICU_INCLUDES)
AC_SUBST(MOZ_NATIVE_ICU)
MOZ_ARG_WITH_STRING(intl-api,

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

@ -183,6 +183,7 @@ app/Message.h
app/MessageRunner.h
arpa/inet.h
arpa/nameser.h
array
asm/page.h
asm/sigcontext.h
asm/signal.h

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

@ -254,9 +254,8 @@
// Disallow trailing whitespace at the end of lines.
"no-trailing-spaces": 2,
// Disallow use of undeclared variables unless mentioned in a /*global */
// block.
// This should really be a 2, but until we define all globals in comments
// and .eslintrc, keeping this as a 1.
// block. Note that globals from head.js are automatically imported in tests
// by the import-headjs-globals rule form the mozilla eslint plugin.
"no-undef": 2,
// Allow dangling underscores in identifiers (for privates).
"no-underscore-dangle": 0,

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

@ -64,16 +64,20 @@ var AboutDebugging = {
document.querySelector(".category[value=" + category + "]")
.setAttribute("selected", "true");
location.hash = "#" + category;
if (category == "addons") {
React.render(React.createElement(AddonsComponent, { client: this.client }),
document.querySelector("#addons"));
} else if (category == "workers") {
React.render(React.createElement(WorkersComponent, { client: this.client }),
document.querySelector("#workers"));
}
},
init() {
let telemetry = this._telemetry = new Telemetry();
telemetry.toolOpened("aboutdebugging");
// Show the first available tab.
this.showTab();
window.addEventListener("hashchange", () => this.showTab());
// Link checkboxes to prefs.
let elements = document.querySelectorAll("input[type=checkbox][data-pref]");
Array.map(elements, element => {
@ -99,13 +103,12 @@ var AboutDebugging = {
DebuggerServer.addBrowserActors();
}
DebuggerServer.allowChromeProcess = true;
let client = new DebuggerClient(DebuggerServer.connectPipe());
this.client = new DebuggerClient(DebuggerServer.connectPipe());
client.connect(() => {
React.render(React.createElement(AddonsComponent, { client }),
document.querySelector("#addons"));
React.render(React.createElement(WorkersComponent, { client }),
document.querySelector("#workers"));
this.client.connect(() => {
// Show the first available tab.
this.showTab();
window.addEventListener("hashchange", () => this.showTab());
});
},
@ -144,6 +147,9 @@ var AboutDebugging = {
React.unmountComponentAtNode(document.querySelector("#addons"));
React.unmountComponentAtNode(document.querySelector("#workers"));
this.client.close();
this.client = null;
},
};

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

@ -27,7 +27,7 @@ exports.TargetListComponent = React.createClass({
return React.createElement(TargetComponent, { client, target });
});
return (
React.createElement("div", { className: "targets" },
React.createElement("div", { id: this.props.id, className: "targets" },
React.createElement("h4", null, this.props.name),
targets.length > 0 ? targets :
React.createElement("p", null, Strings.GetStringFromName("nothing"))

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

@ -14,6 +14,8 @@ loader.lazyRequireGetter(this, "TargetListComponent",
"devtools/client/aboutdebugging/components/target-list", true);
loader.lazyRequireGetter(this, "Services");
loader.lazyImporter(this, "Task", "resource://gre/modules/Task.jsm");
const Strings = Services.strings.createBundle(
"chrome://devtools/locale/aboutdebugging.properties");
const WorkerIcon = "chrome://devtools/skin/images/debugging-workers.svg";
@ -32,12 +34,16 @@ exports.WorkersComponent = React.createClass({
},
componentDidMount() {
this.props.client.addListener("workerListChanged", this.update);
let client = this.props.client;
client.addListener("workerListChanged", this.update);
client.addListener("processListChanged", this.update);
this.update();
},
componentWillUnmount() {
this.props.client.removeListener("workerListChanged", this.update);
let client = this.props.client;
client.removeListener("processListChanged", this.update);
client.removeListener("workerListChanged", this.update);
},
render() {
@ -45,22 +51,23 @@ exports.WorkersComponent = React.createClass({
let workers = this.state.workers;
return React.createElement("div", { className: "inverted-icons" },
React.createElement(TargetListComponent, {
id: "service-workers",
name: Strings.GetStringFromName("serviceWorkers"),
targets: workers.service, client }),
React.createElement(TargetListComponent, {
id: "shared-workers",
name: Strings.GetStringFromName("sharedWorkers"),
targets: workers.shared, client }),
React.createElement(TargetListComponent, {
id: "other-workers",
name: Strings.GetStringFromName("otherWorkers"),
targets: workers.other, client })
);
},
update() {
let client = this.props.client;
let workers = this.getInitialState().workers;
client.mainRoot.listWorkers(response => {
let forms = response.workers;
this.getWorkerForms().then(forms => {
forms.forEach(form => {
let worker = {
name: form.url,
@ -83,5 +90,29 @@ exports.WorkersComponent = React.createClass({
});
this.setState({ workers });
});
}
},
getWorkerForms: Task.async(function*() {
let client = this.props.client;
// List workers from the Parent process
let result = yield client.mainRoot.listWorkers();
let forms = result.workers;
// And then from the Child processes
let { processes } = yield client.mainRoot.listProcesses();
for (let process of processes) {
// Ignore parent process
if (process.parent) {
continue;
}
let { form } = yield client.getProcess(process.id);
let processActor = form.actor;
let { workers } = yield client.request({to: processActor,
type: "listWorkers"});
forms = forms.concat(workers);
}
return forms;
}),
});

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

@ -5,5 +5,8 @@ support-files =
head.js
addons/unpacked/bootstrap.js
addons/unpacked/install.rdf
service-workers/empty-sw.html
service-workers/empty-sw.js
[browser_addons_install.js]
[browser_service_workers.js]

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

@ -0,0 +1,66 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Service workers can't be loaded from chrome://,
// but http:// is ok with dom.serviceWorkers.testing.enabled turned on.
const HTTP_ROOT = CHROME_ROOT.replace("chrome://mochitests/content/",
"http://mochi.test:8888/");
const SERVICE_WORKER = HTTP_ROOT + "service-workers/empty-sw.js";
const TAB_URL = HTTP_ROOT + "service-workers/empty-sw.html";
function waitForWorkersUpdate(document) {
return new Promise(done => {
var observer = new MutationObserver(function(mutations) {
observer.disconnect();
done();
});
var target = document.getElementById("service-workers");
observer.observe(target, { childList: true });
});
}
add_task(function *() {
yield new Promise(done => {
let options = {"set": [
["dom.serviceWorkers.testing.enabled", true],
]};
SpecialPowers.pushPrefEnv(options, done);
});
let { tab, document } = yield openAboutDebugging("workers");
let swTab = yield addTab(TAB_URL);
yield waitForWorkersUpdate(document);
// Check that the service worker appears in the UI
let names = [...document.querySelectorAll("#service-workers .target-name")];
names = names.map(element => element.textContent);
ok(names.includes(SERVICE_WORKER), "The service worker url appears in the list: " + names);
// Use message manager to work with e10s
let frameScript = function () {
// Retrieve the `sw` promise created in the html page
let { sw } = content.wrappedJSObject;
sw.then(function (registration) {
registration.unregister().then(function (success) {
dump("SW unregistered: " + success + "\n");
},
function (e) {
dump("SW not unregistered; " + e + "\n");
});
});
};
swTab.linkedBrowser.messageManager.loadFrameScript("data:,(" + encodeURIComponent(frameScript) + ")()", true);
yield waitForWorkersUpdate(document);
// Check that the service worker disappeared from the UI
names = [...document.querySelectorAll("#service-workers .target-name")];
names = names.map(element => element.textContent);
ok(!names.includes(SERVICE_WORKER), "The service worker url is no longer in the list: " + names);
yield removeTab(swTab);
yield closeAboutDebugging(tab);
});

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

@ -16,9 +16,13 @@ registerCleanupFunction(() => {
DevToolsUtils.testing = false;
});
function openAboutDebugging() {
function openAboutDebugging(page) {
info("opening about:debugging");
return addTab("about:debugging").then(tab => {
let url = "about:debugging";
if (page) {
url += "#" + page;
}
return addTab(url).then(tab => {
let browser = tab.linkedBrowser;
return {
tab,

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

@ -0,0 +1,20 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>Service worker test</title>
</head>
<body>
<script type="text/javascript">
var sw = navigator.serviceWorker.register("empty-sw.js");
sw.then(
function (registration) {
dump("SW registered\n");
},
function (e) {
dump("SW not registered: " + e + "\n");
}
);
</script>
</body>
</html>

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

@ -0,0 +1 @@
// Empty, just test registering.

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

@ -32,17 +32,13 @@ function* spawnTest() {
ok(msg, "output for pprint(window)");
let oncePromise = hud.jsterm.once("messages-cleared");
helpers.audit(options, [
yield helpers.audit(options, [
{
setup: "console clear",
exec: { output: "" }
}
]);
yield oncePromise;
let labels = hud.outputNode.querySelectorAll(".message");
is(labels.length, 0, "no output in console");

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

@ -10,6 +10,8 @@ const promise = require("promise");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://devtools/client/shared/DOMHelpers.jsm");
loader.lazyRequireGetter(this, "system", "devtools/shared/system");
/* A host should always allow this much space for the page to be displayed.
* There is also a min-height on the browser, but we still don't want to set
* frame.height to be larger than that, since it can cause problems with
@ -283,6 +285,15 @@ WindowHost.prototype = {
let frameLoad = () => {
win.removeEventListener("load", frameLoad, true);
win.focus();
let key;
if (system.constants.platform === "macosx") {
key = win.document.getElementById("toolbox-key-toggle-osx");
} else {
key = win.document.getElementById("toolbox-key-toggle");
}
key.removeAttribute("disabled");
this.frame = win.document.getElementById("toolbox-iframe");
this.emit("ready", this.frame);

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

@ -29,12 +29,13 @@
<key id="toolbox-key-toggle"
key="&toggleToolbox.key;"
command="toolbox-cmd-close"
#ifdef XP_MACOSX
modifiers="accel,alt"
#else
modifiers="accel,shift"
#endif
/>
disabled="true"/>
<key id="toolbox-key-toggle-osx"
key="&toggleToolbox.key;"
command="toolbox-cmd-close"
modifiers="accel,alt"
disabled="true"/>
<key id="toolbox-key-toggle-F12"
keycode="&toggleToolboxF12.keycode;"
keytext="&toggleToolboxF12.keytext;"

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

@ -390,19 +390,20 @@ SelectorAutocompleter.prototype = {
let items = [];
for (let [value, /*count*/, state] of list) {
// for cases like 'div ' or 'div >' or 'div+'
if (query.match(/[\s>+]$/)) {
// for cases like 'div ' or 'div >' or 'div+'
value = query + value;
}
// for cases like 'div #a' or 'div .a' or 'div > d' and likewise
else if (query.match(/[\s>+][\.#a-zA-Z][^\s>+\.#]*$/)) {
let lastPart = query.match(/[\s>+][\.#a-zA-Z][^>\s+\.#]*$/)[0];
} else if (query.match(/[\s>+][\.#a-zA-Z][^\s>+\.#\[]*$/)) {
// for cases like 'div #a' or 'div .a' or 'div > d' and likewise
let lastPart = query.match(/[\s>+][\.#a-zA-Z][^\s>+\.#\[]*$/)[0];
value = query.slice(0, -1 * lastPart.length + 1) + value;
}
// for cases like 'div.class' or '#foo.bar' and likewise
else if (query.match(/[a-zA-Z][#\.][^#\.\s+>]*$/)) {
let lastPart = query.match(/[a-zA-Z][#\.][^#\.\s>+]*$/)[0];
} else if (query.match(/[a-zA-Z][#\.][^#\.\s+>]*$/)) {
// for cases like 'div.class' or '#foo.bar' and likewise
let lastPart = query.match(/[a-zA-Z][#\.][^#\.\s+>]*$/)[0];
value = query.slice(0, -1 * lastPart.length + 1) + value;
} else if (query.match(/[a-zA-Z]\[[^\]]*\]?$/)) {
// for cases like 'div[foo=bar]' and likewise
value = query;
}
let item = {
@ -457,6 +458,13 @@ SelectorAutocompleter.prototype = {
let state = this.state;
let firstPart = "";
if (query.endsWith("*")) {
// Hide the popup if the query ends with * because we don't want to
// suggest all nodes.
this.hidePopup();
return;
}
if (state === this.States.TAG) {
// gets the tag that is being completed. For ex. 'div.foo > s' returns 's',
// 'di' returns 'di' and likewise.

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

@ -160,6 +160,39 @@ var TEST_DATA = [
{
key: "VK_BACK_SPACE",
suggestions: []
},
{
key: "p",
suggestions: [
{label: "p"},
{label: "#p1"},
{label: "#p2"},
{label: "#p3"}
]
},
{
key: "[", suggestions: []
},
{
key: "i", suggestions: []
},
{
key: "d", suggestions: []
},
{
key: "*", suggestions: []
},
{
key: "=", suggestions: []
},
{
key: "p", suggestions: []
},
{
key: "]",
suggestions: [
{label: "p[id*=p]"}
]
}
];

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

@ -117,7 +117,7 @@ devtools.jar:
content/commandline/commandline.css (commandline/commandline.css)
content/commandline/commandlineoutput.xhtml (commandline/commandlineoutput.xhtml)
content/commandline/commandlinetooltip.xhtml (commandline/commandlinetooltip.xhtml)
* content/framework/toolbox-window.xul (framework/toolbox-window.xul)
content/framework/toolbox-window.xul (framework/toolbox-window.xul)
content/framework/toolbox-options.xul (framework/toolbox-options.xul)
content/framework/toolbox-options.js (framework/toolbox-options.js)
content/framework/toolbox.xul (framework/toolbox.xul)

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

@ -569,11 +569,12 @@ Rule.prototype = {
getOriginalSourceStrings: function() {
return this.domRule.getOriginalLocation().then(({href, line, mediaText}) => {
let mediaString = mediaText ? " @" + mediaText : "";
let linePart = line > 0 ? (":" + line) : "";
let sourceStrings = {
full: (href || CssLogic.l10n("rule.sourceInline")) + ":" +
line + mediaString,
short: CssLogic.shortSource({href: href}) + ":" + line + mediaString
full: (href || CssLogic.l10n("rule.sourceInline")) + linePart +
mediaString,
short: CssLogic.shortSource({href: href}) + linePart + mediaString
};
return sourceStrings;

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

@ -11,6 +11,7 @@ support-files =
doc_content_stylesheet_xul.css
doc_copystyles.css
doc_copystyles.html
doc_cssom.html
doc_custom.html
doc_filter.html
doc_frame_script.js
@ -89,6 +90,7 @@ skip-if = e10s # Bug 1039528: "inspect element" contextual-menu doesn't work wit
[browser_ruleview_context-menu-show-mdn-docs-02.js]
[browser_ruleview_context-menu-show-mdn-docs-03.js]
[browser_ruleview_copy_styles.js]
[browser_ruleview_cssom.js]
[browser_ruleview_cubicbezier-appears-on-swatch-click.js]
[browser_ruleview_cubicbezier-commit-on-ENTER.js]
[browser_ruleview_cubicbezier-revert-on-ESC.js]

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

@ -0,0 +1,22 @@
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test to ensure that CSSOM doesn't make the rule view blow up.
// https://bugzilla.mozilla.org/show_bug.cgi?id=1224121
const TEST_URI = TEST_URL_ROOT + "doc_cssom.html";
add_task(function*() {
yield addTab(TEST_URI);
let {inspector, view} = yield openRuleView();
yield selectNode("#target", inspector);
let elementStyle = view._elementStyle;
let rule = elementStyle.rules[1];
is(rule.textProps.length, 1, "rule should have one property");
is(rule.textProps[0].name, "color", "the property should be 'color'");
});

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

@ -0,0 +1,21 @@
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<html>
<head>
<title>CSSOM test</title>
<script>
window.onload = function() {
let x = document.styleSheets[0];
x.insertRule("div { color: seagreen; }", 1);
};
</script>
<style>
span { }
</style>
</head>
<body>
<div id="target"> the ocean </div>
</body>
</html>

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

@ -72,7 +72,9 @@ exports.items = [
return;
}
let onceMessagesCleared = panel.hud.jsterm.once("messages-cleared");
panel.hud.jsterm.clearOutput();
return onceMessagesCleared;
}
},
{

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

@ -14,6 +14,8 @@ const Services = require("Services");
const { assert } = require("devtools/shared/DevToolsUtils");
const { TabSources } = require("./utils/TabSources");
loader.lazyRequireGetter(this, "WorkerActorList", "devtools/server/actors/worker", true);
function ChildProcessActor(aConnection) {
this.conn = aConnection;
this._contextPool = new ActorPool(this.conn);
@ -32,6 +34,10 @@ function ChildProcessActor(aConnection) {
.createInstance(Ci.nsIPrincipal);
let sandbox = Cu.Sandbox(systemPrincipal);
this._consoleScope = sandbox;
this._workerList = null;
this._workerActorPool = null;
this._onWorkerListChanged = this._onWorkerListChanged.bind(this);
}
exports.ChildProcessActor = ChildProcessActor;
@ -87,9 +93,42 @@ ChildProcessActor.prototype = {
};
},
onListWorkers: function () {
if (!this._workerList) {
this._workerList = new WorkerActorList({});
}
return this._workerList.getList().then(actors => {
let pool = new ActorPool(this.conn);
for (let actor of actors) {
pool.addActor(actor);
}
this.conn.removeActorPool(this._workerActorPool);
this._workerActorPool = pool;
this.conn.addActorPool(this._workerActorPool);
this._workerList.onListChanged = this._onWorkerListChanged;
return {
"from": this.actorID,
"workers": actors.map(actor => actor.form())
};
});
},
_onWorkerListChanged: function () {
this.conn.send({ from: this.actorID, type: "workerListChanged" });
this._workerList.onListChanged = null;
},
disconnect: function() {
this.conn.removeActorPool(this._contextPool);
this._contextPool = null;
// Tell the live lists we aren't watching any more.
if (this._workerList) {
this._workerList.onListChanged = null;
}
},
preNest: function() {
@ -103,4 +142,5 @@ ChildProcessActor.prototype = {
};
ChildProcessActor.prototype.requestTypes = {
"listWorkers": ChildProcessActor.prototype.onListWorkers,
};

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

@ -40,6 +40,7 @@ DevToolsModules(
'performance.js',
'preference.js',
'pretty-print-worker.js',
'process.js',
'profiler.js',
'promises.js',
'root.js',

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

@ -0,0 +1,83 @@
/* 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";
var { Cc, Ci } = require("chrome");
loader.lazyGetter(this, "ppmm", () => {
return Cc["@mozilla.org/parentprocessmessagemanager;1"].getService(Ci.nsIMessageBroadcaster);
});
function ProcessActorList() {
this._actors = new Map();
this._onListChanged = null;
this._mustNotify = false;
this._onMessage = this._onMessage.bind(this);
this._processScript = "data:text/javascript,sendAsyncMessage('debug:new-process');";
}
ProcessActorList.prototype = {
getList: function () {
let processes = [];
for (let i = 0; i < ppmm.childCount; i++) {
processes.push({
id: i, // XXX: may not be a perfect id, but process message manager doesn't expose anything...
parent: i == 0, // XXX Weak, but appear to be stable
tabCount: undefined, // TODO: exposes process message manager on frameloaders in order to compute this
});
}
this._mustNotify = true;
this._checkListening();
return processes;
},
get onListChanged() {
return this._onListChanged;
},
set onListChanged(onListChanged) {
if (typeof onListChanged !== "function" && onListChanged !== null) {
throw new Error("onListChanged must be either a function or null.");
}
if (onListChanged === this._onListChanged) {
return;
}
this._onListChanged = onListChanged;
this._checkListening();
},
_checkListening: function () {
if (this._onListChanged !== null && this._mustNotify) {
this._knownProcesses = [];
for (let i = 0; i < ppmm.childCount; i++) {
this._knownProcesses.push(ppmm.getChildAt(i));
}
ppmm.addMessageListener('debug:new-process', this._onMessage);
ppmm.loadProcessScript(this._processScript, true);
} else {
ppmm.removeMessageListener('debug:new-process', this._onMessage);
ppmm.removeDelayedProcessScript(this._processScript);
}
},
_notifyListChanged: function () {
if (this._mustNotify) {
this._onListChanged();
this._mustNotify = false;
}
},
_onMessage: function ({ target }) {
if (this._knownProcesses.includes(target)) {
return;
}
this._notifyListChanged();
},
};
exports.ProcessActorList = ProcessActorList;

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

@ -96,6 +96,7 @@ function RootActor(aConnection, aParameters) {
this._onAddonListChanged = this.onAddonListChanged.bind(this);
this._onWorkerListChanged = this.onWorkerListChanged.bind(this);
this._onServiceWorkerRegistrationListChanged = this.onServiceWorkerRegistrationListChanged.bind(this);
this._onProcessListChanged = this.onProcessListChanged.bind(this);
this._extraActors = {};
this._globalActorPool = new ActorPool(this.conn);
@ -206,6 +207,9 @@ RootActor.prototype = {
if (this._parameters.addonList) {
this._parameters.addonList.onListChanged = null;
}
if (this._parameters.workerList) {
this._parameters.workerList.onListChanged = null;
}
if (typeof this._parameters.onShutdown === 'function') {
this._parameters.onShutdown();
}
@ -419,15 +423,20 @@ RootActor.prototype = {
},
onListProcesses: function () {
let processes = [];
for (let i = 0; i < ppmm.childCount; i++) {
processes.push({
id: i, // XXX: may not be a perfect id, but process message manager doesn't expose anything...
parent: i == 0, // XXX Weak, but appear to be stable
tabCount: undefined, // TODO: exposes process message manager on frameloaders in order to compute this
});
let { processList } = this._parameters;
if (!processList) {
return { from: this.actorID, error: "noProcesses",
message: "This root actor has no processes." };
}
return { processes: processes };
processList.onListChanged = this._onProcessListChanged;
return {
processes: processList.getList()
};
},
onProcessListChanged: function () {
this.conn.send({ from: this.actorID, type: "processListChanged" });
this._parameters.processList.onListChanged = null;
},
onGetProcess: function (aRequest) {

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

@ -1154,6 +1154,11 @@ var StyleRuleActor = protocol.ActorClass({
// about: handler.
// https://bugzilla.mozilla.org/show_bug.cgi?id=935803#c37
return !!(this._parentSheet &&
// If a rule does not have source, then it has been
// modified via CSSOM; and we should fall back to
// non-authored editing.
// https://bugzilla.mozilla.org/show_bug.cgi?id=1224121
this.sheetActor.allRulesHaveSource() &&
this._parentSheet.href !== "about:PreferenceStyleSheet");
},

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

@ -482,6 +482,30 @@ var StyleSheetActor = protocol.ActorClass({
this._transitionRefCount = 0;
},
/**
* Test whether all the rules in this sheet have associated source.
* @return {Boolean} true if all the rules have source; false if
* some rule was created via CSSOM.
*/
allRulesHaveSource: function() {
let rules;
try {
rules = this.rawSheet.cssRules;
} catch (e) {
// sheet isn't loaded yet
return true;
}
for (let i = 0; i < rules.length; i++) {
let rule = rules[i];
if (DOMUtils.getRelativeRuleLine(rule) === 0) {
return false;
}
}
return true;
},
/**
* Get the raw stylesheet's cssRules once the sheet has been loaded.
*

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

@ -24,6 +24,7 @@ loader.lazyRequireGetter(this, "unwrapDebuggerObjectGlobal", "devtools/server/ac
loader.lazyRequireGetter(this, "BrowserAddonActor", "devtools/server/actors/addon", true);
loader.lazyRequireGetter(this, "WorkerActorList", "devtools/server/actors/worker", true);
loader.lazyRequireGetter(this, "ServiceWorkerRegistrationActorList", "devtools/server/actors/worker", true);
loader.lazyRequireGetter(this, "ProcessActorList", "devtools/server/actors/process", true);
loader.lazyImporter(this, "AddonManager", "resource://gre/modules/AddonManager.jsm");
// Assumptions on events module:
@ -132,6 +133,7 @@ function createRootActor(aConnection)
addonList: new BrowserAddonList(aConnection),
workerList: new WorkerActorList({}),
serviceWorkerRegistrationList: new ServiceWorkerRegistrationActorList(),
processList: new ProcessActorList(),
globalActorFactories: DebuggerServer.globalActorFactories,
onShutdown: sendShutdownEvent
});

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

@ -193,6 +193,9 @@ WorkerActorList.prototype = {
if (typeof onListChanged !== "function" && onListChanged !== null) {
throw new Error("onListChanged must be either a function or null.");
}
if (onListChanged === this._onListChanged) {
return;
}
if (this._mustNotify) {
if (this._onListChanged === null && onListChanged !== null) {

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

@ -13,14 +13,7 @@ const { DevToolsLoader } = Cu.import("resource://devtools/shared/Loader.jsm", {}
this.EXPORTED_SYMBOLS = ["init"];
var started = false;
function init(msg) {
if (started) {
return;
}
started = true;
// Init a custom, invisible DebuggerServer, in order to not pollute
// the debugger with all devtools modules, nor break the debugger itself with using it
// in the same process.
@ -61,6 +54,5 @@ function init(msg) {
mm.removeMessageListener("debug:content-process-destroy", onDestroy);
DebuggerServer.destroy();
started = false;
});
}

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

@ -28,21 +28,15 @@ window.onload = function() {
"set": [
// Always log packets when running tests.
["devtools.debugger.log", true],
["dom.mozBrowserFramesEnabled", true]
// Enabled mozbrowser frame to support remote=true
["dom.mozBrowserFramesEnabled", true],
// Allows creating a branch new process when creation the iframe
["dom.ipc.processCount", 10],
]
}, runTests);
}
function runTests() {
// Create a remote iframe with a message manager
let iframe = document.createElement("iframe");
iframe.mozbrowser = true;
iframe.setAttribute("remote", "true");
iframe.setAttribute("src", "data:text/html,foo");
document.body.appendChild(iframe);
let mm = iframe.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader.messageManager;
// Instantiate a minimal server
if (!DebuggerServer.initialized) {
DebuggerServer.init();
@ -52,13 +46,41 @@ function runTests() {
DebuggerServer.addBrowserActors();
}
function firstClient() {
let client, iframe, processCount;
function connect() {
// Fake a first connection to the content process
let transport = DebuggerServer.connectPipe();
let client = new DebuggerClient(transport);
client.connect(() => {
client = new DebuggerClient(transport);
client.connect(listProcess);
}
function listProcess() {
// Call listProcesses in order to start receiving new process notifications
client.addListener("processListChanged", function listener() {
client.removeListener("processListChanged", listener);
ok(true, "Received processListChanged event");
getProcess();
});
client.mainRoot.listProcesses(response => {
processCount = response.processes.length;
// Create a remote iframe to spawn a new process
createRemoteIframe();
});
}
function createRemoteIframe() {
iframe = document.createElement("iframe");
iframe.mozbrowser = true;
iframe.setAttribute("remote", "true");
iframe.setAttribute("src", "data:text/html,foo");
document.body.appendChild(iframe);
}
function getProcess() {
client.mainRoot.listProcesses(response => {
ok(response.processes.length >= 2, "Got at least the parent process and one child");
is(response.processes.length, processCount+1 , "Got one additional process on the second call to listProcesses");
// Connect to the first content processe available
let content = response.processes.filter(p => (!p.parent))[0];
@ -75,21 +97,21 @@ function runTests() {
text: "var a = 42; a"
}, function (response) {
ok(response.result, 42, "console.eval worked");
client.close(cleanup);
cleanup();
});
});
});
});
}
function cleanup() {
DebuggerServer.destroy();
iframe.remove();
SimpleTest.finish()
client.close(function () {
DebuggerServer.destroy();
iframe.remove();
SimpleTest.finish()
});
}
firstClient();
connect();
}
</script>

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

@ -243,6 +243,9 @@ const DebuggerClient = exports.DebuggerClient = function (aTransport)
* response, and the return value is considered the new response that
* will be passed to the callback. The |this| context is the instance of
* the client object we are defining a method for.
* @return Request
* The `Request` object that is a Promise object and resolves once
* we receive the response. (See request method for more details)
*/
DebuggerClient.requester = function (aPacketSkeleton,
{ telemetry, before, after }) {
@ -276,7 +279,7 @@ DebuggerClient.requester = function (aPacketSkeleton,
outgoingPacket = before.call(this, outgoingPacket);
}
this.request(outgoingPacket, DevToolsUtils.makeInfallible((aResponse) => {
return this.request(outgoingPacket, DevToolsUtils.makeInfallible((aResponse) => {
if (after) {
let { from } = aResponse;
aResponse = after.call(this, aResponse);

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

@ -0,0 +1,100 @@
/* 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 DEFAULT_MAX_DEPTH = 3;
const DEFAULT_MAX_SIBLINGS = 15;
/**
* A single node in a dominator tree.
*
* @param {NodeId} nodeId
* @param {NodeSize} retainedSize
*/
function DominatorTreeNode(nodeId, retainedSize) {
// The id of this node.
this.nodeId = nodeId;
// The retained size of this node.
this.retainedSize = retainedSize;
// The id of this node's parent or undefined if this node is the root.
this.parentId = undefined;
// An array of immediately dominated child `DominatorTreeNode`s, or undefined.
this.children = undefined;
// True iff the `children` property does not contain every immediately
// dominated node.
//
// * If children is an array and this property is true: the array does not
// contain the complete set of immediately dominated children.
// * If children is an array and this property is false: the array contains
// the complete set of immediately dominated children.
// * If children is undefined and this property is true: there exist
// immediately dominated children for this node, but they have not been
// loaded yet.
// * If children is undefined and this property is false: this node does not
// dominate any others and therefore has no children.
this.moreChildrenAvailable = true;
}
DominatorTreeNode.prototype = null;
module.exports = DominatorTreeNode;
/**
* Add `child` to the `parent`'s set of children.
*
* @param {DominatorTreeNode} parent
* @param {DominatorTreeNode} child
*/
DominatorTreeNode.addChild = function (parent, child) {
if (parent.children === undefined) {
parent.children = [];
}
parent.children.push(child);
child.parentId = parent.nodeId;
};
/**
* Do a partial traversal of the given dominator tree and convert it into a tree
* of `DominatorTreeNode`s. Dominator trees have a node for every node in the
* snapshot's heap graph, so we must not allocate a JS object for every node. It
* would be way too many and the node count is effectively unbounded.
*
* Go no deeper down the tree than `maxDepth` and only consider at most
* `maxSiblings` within any single node's children.
*
* @param {DominatorTree} dominatorTree
* @param {Number} maxDepth
* @param {Number} maxSiblings
*
* @returns {DominatorTreeNode}
*/
DominatorTreeNode.partialTraversal = function (dominatorTree,
maxDepth = DEFAULT_MAX_DEPTH,
maxSiblings = DEFAULT_MAX_SIBLINGS) {
function dfs(nodeId, depth) {
const size = dominatorTree.getRetainedSize(nodeId);
const node = new DominatorTreeNode(nodeId, size);
const childNodeIds = dominatorTree.getImmediatelyDominated(nodeId);
const newDepth = depth + 1;
if (newDepth < maxDepth) {
const endIdx = Math.min(childNodeIds.length, maxSiblings);
for (let i = 0; i < endIdx; i++) {
DominatorTreeNode.addChild(node, dfs(childNodeIds[i], newDepth));
}
node.moreChildrenAvailable = childNodeIds.length < endIdx;
} else {
node.moreChildrenAvailable = childNodeIds.length > 0;
}
return node;
}
return dfs(dominatorTree.root, 0);
};

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

@ -51,6 +51,22 @@ HeapAnalysesClient.prototype.readHeapSnapshot = function (snapshotFilePath) {
return this._worker.performTask("readHeapSnapshot", { snapshotFilePath });
};
/**
* Request the creation time given a snapshot file path. Returns `null`
* if snapshot does not exist.
*
* @param {String} snapshotFilePath
* The path to the snapshot.
* @return {Number?}
* The unix timestamp of the creation time of the snapshot, or null if
* snapshot does not exist.
*/
HeapAnalysesClient.prototype.getCreationTime = function (snapshotFilePath) {
return this._worker.performTask("getCreationTime", snapshotFilePath);
};
/*** Censuses *****************************************************************/
/**
* Ask the worker to perform a census analysis on the heap snapshot with the
* given path. The heap snapshot at the given path must have already been read
@ -136,16 +152,65 @@ HeapAnalysesClient.prototype.takeCensusDiff = function (firstSnapshotFilePath,
});
};
/*** Dominator Trees **********************************************************/
/**
* Request the creation time given a snapshot file path. Returns `null`
* if snapshot does not exist.
* Compute the dominator tree of the heap snapshot loaded from the given file
* path. Returns the id of the computed dominator tree.
*
* @param {String} snapshotFilePath
* The path to the snapshot.
* @return {Number?}
* The unix timestamp of the creation time of the snapshot, or null if
* snapshot does not exist.
*
* @returns {Promise<DominatorTreeId>}
*/
HeapAnalysesClient.prototype.getCreationTime = function (snapshotFilePath) {
return this._worker.performTask("getCreationTime", snapshotFilePath);
HeapAnalysesClient.prototype.computeDominatorTree = function (snapshotFilePath) {
return this._worker.performTask("computeDominatorTree", snapshotFilePath);
};
/**
* Get the initial, partial view of the dominator tree with the given id.
*
* @param {Object} opts
* An object specifying options for this request.
* - {DominatorTreeId} dominatorTreeId
* The id of the dominator tree.
* - {Number} maxDepth
* The maximum depth to traverse down the tree to create this initial
* view.
* - {Number} maxSiblings
* The maximum number of siblings to visit within each traversed node's
* children.
*
* @returns {Promise<DominatorTreeNode>}
*/
HeapAnalysesClient.prototype.getDominatorTree = function (opts) {
return this._worker.performTask("getDominatorTree", opts);
};
/**
* Get a subset of a nodes children in the dominator tree.
*
* @param {Object} opts
* An object specifying options for this request.
* - {DominatorTreeId} dominatorTreeId
* The id of the dominator tree.
* - {NodeId} nodeId
* The id of the node whose children are being found.
* - {Number} startIndex
* The starting index within the full set of immediately dominated
* children of the children being requested. Children are always sorted
* by greatest to least retained size.
* - {Number} maxCount
* The maximum number of children to return.
*
* @returns {Promise<Object>}
* A promise of an object with the following properties:
* - {Array<DominatorTreeNode>} nodes
* The requested nodes that are immediately dominated by the node
* identified by `opts.nodeId`.
* - {Boolean} moreChildrenAvailable
* True iff there are more children available after the returned
* nodes.
*/
HeapAnalysesClient.prototype.getImmediatelyDominated = function (opts) {
return this._worker.performTask("getImmediatelyDominated", opts);
};

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

@ -13,8 +13,12 @@
importScripts("resource://gre/modules/workers/require.js");
importScripts("resource://devtools/shared/worker/helper.js");
const { censusReportToCensusTreeNode } = require("resource://devtools/shared/heapsnapshot/census-tree-node.js");
const DominatorTreeNode = require("resource://devtools/shared/heapsnapshot/DominatorTreeNode.js");
const CensusUtils = require("resource://devtools/shared/heapsnapshot/CensusUtils.js");
const DEFAULT_START_INDEX = 0;
const DEFAULT_MAX_COUNT = 50;
// The set of HeapSnapshot instances this worker has read into memory. Keyed by
// snapshot file path.
const snapshots = Object.create(null);
@ -86,7 +90,92 @@ workerHelper.createTask(self, "takeCensusDiff", request => {
/**
* @see HeapAnalysesClient.prototype.getCreationTime
*/
workerHelper.createTask(self, "getCreationTime", (snapshotFilePath) => {
workerHelper.createTask(self, "getCreationTime", snapshotFilePath => {
let snapshot = snapshots[snapshotFilePath];
return snapshot ? snapshot.creationTime : null;
});
/**
* The set of `DominatorTree`s that have been computed, mapped by their id (aka
* the index into this array).
*
* @see /dom/webidl/DominatorTree.webidl
*/
const dominatorTrees = [];
/**
* @see HeapAnalysesClient.prototype.computeDominatorTree
*/
workerHelper.createTask(self, "computeDominatorTree", snapshotFilePath => {
const snapshot = snapshots[snapshotFilePath];
if (!snapshot) {
throw new Error(`No known heap snapshot for '${snapshotFilePath}'`);
}
const id = dominatorTrees.length;
dominatorTrees.push(snapshot.computeDominatorTree());
return id;
});
/**
* @see HeapAnalysesClient.prototype.getDominatorTree
*/
workerHelper.createTask(self, "getDominatorTree", request => {
const {
dominatorTreeId,
maxDepth,
maxSiblings
} = request;
if (!(0 <= dominatorTreeId && dominatorTreeId < dominatorTrees.length)) {
throw new Error(
`There does not exist a DominatorTree with the id ${dominatorTreeId}`);
}
return DominatorTreeNode.partialTraversal(dominatorTrees[dominatorTreeId],
maxDepth,
maxSiblings);
});
/**
* @see HeapAnalysesClient.prototype.getImmediatelyDominated
*/
workerHelper.createTask(self, "getImmediatelyDominated", request => {
const {
dominatorTreeId,
nodeId,
startIndex,
maxCount
} = request;
if (!(0 <= dominatorTreeId && dominatorTreeId < dominatorTrees.length)) {
throw new Error(
`There does not exist a DominatorTree with the id ${dominatorTreeId}`);
}
const dominatorTree = dominatorTrees[dominatorTreeId];
const childIds = dominatorTree.getImmediatelyDominated(nodeId);
if (!childIds) {
throw new Error(`${nodeId} is not a node id in the dominator tree`);
}
const start = startIndex || DEFAULT_START_INDEX;
const count = maxCount || DEFAULT_MAX_COUNT;
const end = start + count;
const nodes = childIds
.slice(start, end)
.map(id => {
const size = dominatorTree.getRetainedSize(id);
const node = new DominatorTreeNode(id, size);
node.parentId = nodeId;
// DominatorTree.getImmediatelyDominated will always return non-null here
// because we got the id directly from the dominator tree.
node.moreChildrenAvailable = dominatorTree.getImmediatelyDominated(id).length > 0;
return node;
});
const moreChildrenAvailable = childIds.length > end;
return { nodes, moreChildrenAvailable };
});

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

@ -48,6 +48,7 @@ FINAL_LIBRARY = 'xul'
DevToolsModules(
'census-tree-node.js',
'CensusUtils.js',
'DominatorTreeNode.js',
'HeapAnalysesClient.js',
'HeapAnalysesWorker.js',
'HeapSnapshotFileUtils.js',

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

@ -0,0 +1,22 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Test the HeapAnalyses{Client,Worker} "computeDominatorTree" request.
function run_test() {
run_next_test();
}
add_task(function* () {
const client = new HeapAnalysesClient();
const snapshotFilePath = saveNewHeapSnapshot();
yield client.readHeapSnapshot(snapshotFilePath);
ok(true, "Should have read the heap snapshot");
const dominatorTreeId = yield client.computeDominatorTree(snapshotFilePath);
equal(typeof dominatorTreeId, "number",
"should get a dominator tree id, and it should be a number");
client.destroy();
});

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

@ -0,0 +1,23 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Test the HeapAnalyses{Client,Worker} "computeDominatorTree" request with bad
// file paths.
function run_test() {
run_next_test();
}
add_task(function* () {
const client = new HeapAnalysesClient();
let threw = false;
try {
yield client.computeDominatorTree("/etc/passwd");
} catch (_) {
threw = true;
}
ok(threw, "should throw when given a bad path");
client.destroy();
});

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

@ -0,0 +1,51 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Test the HeapAnalyses{Client,Worker} "getDominatorTree" request.
function run_test() {
run_next_test();
}
add_task(function* () {
const client = new HeapAnalysesClient();
const snapshotFilePath = saveNewHeapSnapshot();
yield client.readHeapSnapshot(snapshotFilePath);
ok(true, "Should have read the heap snapshot");
const dominatorTreeId = yield client.computeDominatorTree(snapshotFilePath);
equal(typeof dominatorTreeId, "number",
"should get a dominator tree id, and it should be a number");
const partialTree = yield client.getDominatorTree({ dominatorTreeId });
ok(partialTree, "Should get a partial tree");
equal(typeof partialTree, "object",
"partialTree should be an object");
function checkTree(node) {
equal(typeof node.nodeId, "number", "each node should have an id");
if (node === partialTree) {
equal(node.parentId, undefined, "the root has no parent");
} else {
equal(typeof node.parentId, "number", "each node should have a parent id");
}
equal(typeof node.retainedSize, "number",
"each node should have a retained size");
ok(node.children === undefined || Array.isArray(node.children),
"each node either has a list of children, or undefined meaning no children loaded");
equal(typeof node.moreChildrenAvailable, "boolean",
"each node should indicate if there are more children available or not");
if (node.children) {
node.children.forEach(checkTree);
}
}
checkTree(partialTree);
client.destroy();
});

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

@ -0,0 +1,23 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Test the HeapAnalyses{Client,Worker} "getDominatorTree" request with bad
// dominator tree ids.
function run_test() {
run_next_test();
}
add_task(function* () {
const client = new HeapAnalysesClient();
let threw = false;
try {
yield client.getDominatorTree({ dominatorTreeId: 42 });
} catch (_) {
threw = true;
}
ok(threw, "should throw when given a bad id");
client.destroy();
});

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

@ -0,0 +1,46 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Test the HeapAnalyses{Client,Worker} "getImmediatelyDominated" request.
function run_test() {
run_next_test();
}
add_task(function* () {
const client = new HeapAnalysesClient();
const snapshotFilePath = saveNewHeapSnapshot();
yield client.readHeapSnapshot(snapshotFilePath);
const dominatorTreeId = yield client.computeDominatorTree(snapshotFilePath);
const partialTree = yield client.getDominatorTree({ dominatorTreeId });
ok(partialTree.children.length > 0,
"root should immediately dominate some nodes");
// First, test getting a subset of children available.
const response = yield client.getImmediatelyDominated({
dominatorTreeId,
nodeId: partialTree.nodeId,
startIndex: 0,
maxCount: partialTree.children.length - 1
});
ok(Array.isArray(response.nodes));
ok(response.nodes.every(node => node.parentId === partialTree.nodeId));
ok(response.moreChildrenAvailable);
// Next, test getting a subset of children available.
const secondResponse = yield client.getImmediatelyDominated({
dominatorTreeId,
nodeId: partialTree.nodeId,
startIndex: 0,
maxCount: Infinity
});
ok(Array.isArray(secondResponse.nodes));
ok(secondResponse.nodes.every(node => node.parentId === partialTree.nodeId));
ok(!secondResponse.moreChildrenAvailable);
client.destroy();
});

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

@ -33,7 +33,12 @@ support-files =
[test_DominatorTree_03.js]
[test_DominatorTree_04.js]
[test_DominatorTree_05.js]
[test_HeapAnalyses_computeDominatorTree_01.js]
[test_HeapAnalyses_computeDominatorTree_02.js]
[test_HeapAnalyses_getCreationTime_01.js]
[test_HeapAnalyses_getDominatorTree_01.js]
[test_HeapAnalyses_getDominatorTree_02.js]
[test_HeapAnalyses_getImmediatelyDominated_01.js]
[test_HeapAnalyses_readHeapSnapshot_01.js]
[test_HeapAnalyses_takeCensusDiff_01.js]
[test_HeapAnalyses_takeCensusDiff_02.js]

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

@ -375,19 +375,11 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Registry)
cb.NoteXPCOMChild(callbacks->mDetachedCallback.Value());
}
}
for (auto iter = tmp->mCandidatesMap.Iter(); !iter.Done(); iter.Next()) {
nsTArray<RefPtr<Element>>* elems = iter.UserData();
for (size_t i = 0; i < elems->Length(); ++i) {
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mCandidatesMap->Element");
cb.NoteXPCOMChild(elems->ElementAt(i));
}
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Registry)
tmp->mCustomDefinitions.Clear();
tmp->mCandidatesMap.Clear();
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Registry)
@ -5782,16 +5774,16 @@ nsDocument::RegisterUnresolvedElement(Element* aElement, nsIAtom* aTypeName)
return NS_OK;
}
nsTArray<RefPtr<Element>>* unresolved;
nsTArray<nsWeakPtr>* unresolved;
mRegistry->mCandidatesMap.Get(&key, &unresolved);
if (!unresolved) {
unresolved = new nsTArray<RefPtr<Element>>();
unresolved = new nsTArray<nsWeakPtr>();
// Ownership of unresolved is taken by mCandidatesMap.
mRegistry->mCandidatesMap.Put(&key, unresolved);
}
RefPtr<Element>* elem = unresolved->AppendElement();
*elem = aElement;
nsWeakPtr* elem = unresolved->AppendElement();
*elem = do_GetWeakReference(aElement);
aElement->AddStates(NS_EVENT_STATE_UNRESOLVED);
return NS_OK;
@ -6175,11 +6167,14 @@ nsDocument::RegisterElement(JSContext* aCx, const nsAString& aType,
definitions.Put(&key, definition);
// Do element upgrade.
nsAutoPtr<nsTArray<RefPtr<Element>>> candidates;
nsAutoPtr<nsTArray<nsWeakPtr>> candidates;
mRegistry->mCandidatesMap.RemoveAndForget(&key, candidates);
if (candidates) {
for (size_t i = 0; i < candidates->Length(); ++i) {
Element *elem = candidates->ElementAt(i);
nsCOMPtr<Element> elem = do_QueryReferent(candidates->ElementAt(i));
if (!elem) {
continue;
}
elem->RemoveStates(NS_EVENT_STATE_UNRESOLVED);

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

@ -427,7 +427,7 @@ protected:
mozilla::dom::CustomElementDefinition>
DefinitionMap;
typedef nsClassHashtable<mozilla::dom::CustomElementHashKey,
nsTArray<RefPtr<mozilla::dom::Element>>>
nsTArray<nsWeakPtr>>
CandidateMap;
// Hashtable for custom element definitions in web components.

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

@ -582,7 +582,7 @@ skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop spec
[test_bug558726.html]
[test_bug559526.html]
[test_bug560780.html]
skip-if = android_version == '18' # Android 4.3 intermittent, Bug 1154497
skip-if = (os == "android") # Failure with AccessibleCarets on Android, bug 1230229
[test_bug562137.html]
[test_bug562169-1.html]
[test_bug562169-2.html]

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

@ -410,51 +410,17 @@ class CGDOMJSClass(CGThing):
return ""
def define(self):
traceHook = 'nullptr'
callHook = LEGACYCALLER_HOOK_NAME if self.descriptor.operations["LegacyCaller"] else 'nullptr'
objectMovedHook = OBJECT_MOVED_HOOK_NAME if self.descriptor.wrapperCache else 'nullptr'
slotCount = INSTANCE_RESERVED_SLOTS + self.descriptor.interface.totalMembersInSlots
classFlags = "JSCLASS_IS_DOMJSCLASS | "
classExtensionAndObjectOps = fill(
"""
{
false, /* isWrappedNative */
nullptr, /* weakmapKeyDelegateOp */
${objectMoved} /* objectMovedOp */
},
JS_NULL_OBJECT_OPS
""",
objectMoved=objectMovedHook)
if self.descriptor.isGlobal():
classFlags += "JSCLASS_DOM_GLOBAL | JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(DOM_GLOBAL_SLOTS)"
traceHook = "JS_GlobalObjectTraceHook"
reservedSlots = "JSCLASS_GLOBAL_APPLICATION_SLOTS"
if self.descriptor.interface.identifier.name == "Window":
classExtensionAndObjectOps = fill(
"""
{
false, /* isWrappedNative */
nullptr, /* weakmapKeyDelegateOp */
${objectMoved} /* objectMovedOp */
},
{
nullptr, /* lookupProperty */
nullptr, /* defineProperty */
nullptr, /* hasProperty */
nullptr, /* getProperty */
nullptr, /* setProperty */
nullptr, /* getOwnPropertyDescriptor */
nullptr, /* deleteProperty */
nullptr, /* watch */
nullptr, /* unwatch */
nullptr, /* getElements */
nullptr, /* enumerate */
nullptr, /* funToString */
}
""",
objectMoved=objectMovedHook)
else:
classFlags += "JSCLASS_HAS_RESERVED_SLOTS(%d)" % slotCount
traceHook = 'nullptr'
reservedSlots = slotCount
if self.descriptor.interface.getExtendedAttribute("NeedResolve"):
resolveHook = RESOLVE_HOOK_NAME
@ -487,7 +453,12 @@ class CGDOMJSClass(CGThing):
nullptr, /* construct */
${trace}, /* trace */
JS_NULL_CLASS_SPEC,
$*{classExtensionAndObjectOps}
{
false, /* isWrappedNative */
nullptr, /* weakmapKeyDelegateOp */
${objectMoved} /* objectMovedOp */
},
JS_NULL_OBJECT_OPS
},
$*{descriptor}
};
@ -505,7 +476,7 @@ class CGDOMJSClass(CGThing):
finalize=FINALIZE_HOOK_NAME,
call=callHook,
trace=traceHook,
classExtensionAndObjectOps=classExtensionAndObjectOps,
objectMoved=objectMovedHook,
descriptor=DOMClass(self.descriptor),
instanceReservedSlots=INSTANCE_RESERVED_SLOTS,
reservedSlots=reservedSlots,

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

@ -88,7 +88,8 @@ skip-if = (toolkit == 'gonk')
[test_browserElement_oop_SecurityChange.html]
skip-if = toolkit == 'android' || (toolkit == 'gonk' && !debug) #TIMED_OUT, bug 766586
[test_browserElement_oop_SelectionStateBlur.html]
skip-if = (toolkit == 'gonk') # Disabled on b2g due to bug 1097419
skip-if = (os == "android" || toolkit == 'gonk') # Disabled on b2g due to bug 1097419
# Disabled on Android, see bug 1230230
[test_browserElement_oop_SendEvent.html]
[test_browserElement_oop_SetInputMethodActive.html]
skip-if = (os == "android")

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

@ -223,7 +223,8 @@ skip-if = (toolkit == 'gonk')
[test_browserElement_inproc_SecurityChange.html]
skip-if = toolkit == 'android' || (toolkit == 'gonk' && !debug) # android(TIMED_OUT, bug 766586) androidx86(TIMED_OUT, bug 766586)
[test_browserElement_inproc_SelectionStateBlur.html]
skip-if = (toolkit == 'gonk') # Disabled on b2g due to bug 1097419
skip-if = (os == "android" || toolkit == 'gonk') # Disabled on b2g due to bug 1097419
# Disabled on Android, see bug 1230230
[test_browserElement_inproc_SendEvent.html]
# The setInputMethodActive() tests will timed out on Android
[test_browserElement_inproc_SetInputMethodActive.html]

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

@ -107,3 +107,4 @@ LOCAL_INCLUDES += [
if CONFIG['ENABLE_INTL_API']:
CXXFLAGS += CONFIG['MOZ_ICU_CFLAGS']
LOCAL_INCLUDES += CONFIG['MOZ_ICU_INCLUDES']

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

@ -2965,6 +2965,15 @@ ContentChild::RecvShutdown()
GetIPCChannel()->SetAbortOnError(false);
#ifdef MOZ_ENABLE_PROFILER_SPS
if (profiler_is_active()) {
// We're shutting down while we were profiling. Send the
// profile up to the parent so that we don't lose this
// information.
Unused << RecvGatherProfile();
}
#endif
// Ignore errors here. If this fails, the parent will kill us after a
// timeout.
Unused << SendFinishShutdown();

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

@ -1569,6 +1569,11 @@ ContentParent::Init()
rv = profiler->GetStartParams(getter_AddRefs(currentProfilerParams));
MOZ_ASSERT(NS_SUCCEEDED(rv));
nsCOMPtr<nsISupports> gatherer;
rv = profiler->GetProfileGatherer(getter_AddRefs(gatherer));
MOZ_ASSERT(NS_SUCCEEDED(rv));
mGatherer = static_cast<ProfileGatherer*>(gatherer.get());
StartProfiler(currentProfilerParams);
}
#endif
@ -2089,6 +2094,12 @@ ContentParent::ActorDestroy(ActorDestroyReason why)
mConsoleService = nullptr;
#ifdef MOZ_ENABLE_PROFILER_SPS
if (mGatherer && !mProfile.IsEmpty()) {
mGatherer->OOPExitProfile(mProfile);
}
#endif
if (obs) {
RefPtr<nsHashPropertyBag> props = new nsHashPropertyBag();
@ -3293,6 +3304,7 @@ ContentParent::Observe(nsISupports* aSubject,
StartProfiler(params);
}
else if (!strcmp(aTopic, "profiler-stopped")) {
mGatherer = nullptr;
Unused << SendStopProfiler();
}
else if (!strcmp(aTopic, "profiler-paused")) {
@ -3302,9 +3314,10 @@ ContentParent::Observe(nsISupports* aSubject,
Unused << SendPauseProfiler(false);
}
else if (!strcmp(aTopic, "profiler-subprocess-gather")) {
mGatherer = static_cast<ProfileGatherer*>(aSubject);
mGatherer->WillGatherOOPProfile();
Unused << SendGatherProfile();
if (mGatherer) {
mGatherer->WillGatherOOPProfile();
Unused << SendGatherProfile();
}
}
else if (!strcmp(aTopic, "profiler-subprocess")) {
nsCOMPtr<nsIProfileSaveEvent> pse = do_QueryInterface(aSubject);
@ -5656,7 +5669,6 @@ ContentParent::RecvProfile(const nsCString& aProfile)
}
mProfile = aProfile;
mGatherer->GatheredOOPProfile();
mGatherer = nullptr;
#endif
return true;
}
@ -5747,6 +5759,14 @@ ContentParent::StartProfiler(nsIProfilerStartParams* aParams)
ipcParams.threadFilters() = aParams->GetThreadFilterNames();
Unused << SendStartProfiler(ipcParams);
nsCOMPtr<nsIProfiler> profiler(do_GetService("@mozilla.org/tools/profiler;1"));
if (NS_WARN_IF(!profiler)) {
return;
}
nsCOMPtr<nsISupports> gatherer;
profiler->GetProfileGatherer(getter_AddRefs(gatherer));
mGatherer = static_cast<ProfileGatherer*>(gatherer.get());
#endif
}

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

@ -88,7 +88,7 @@ public:
void SetCapacity(uint32_t aCapacity) {
MOZ_ASSERT(!mBuffer, "Buffer allocated.");
mCapacity = aCapacity;
mBuffer = new uint8_t[mCapacity];
mBuffer = MakeUnique<uint8_t[]>(mCapacity);
}
uint32_t Length() {
@ -137,12 +137,12 @@ public:
size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
{
size_t amount = 0;
amount += mBuffer.SizeOfExcludingThis(aMallocSizeOf);
amount += aMallocSizeOf(mBuffer.get());
return amount;
}
private:
nsAutoArrayPtr<uint8_t> mBuffer;
UniquePtr<uint8_t[]> mBuffer;
uint32_t mCapacity;
uint32_t mStart;
uint32_t mCount;

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

@ -9,6 +9,7 @@
#include "mozilla/Attributes.h"
#include "mozilla/Monitor.h"
#include "mozilla/UniquePtr.h"
#include "nsTArray.h"
#include "MediaCache.h"
#include "nsDeque.h"
@ -96,7 +97,7 @@ public:
explicit BlockChange(const uint8_t* aData)
: mSourceBlockIndex(-1)
{
mData = new uint8_t[BLOCK_SIZE];
mData = MakeUnique<uint8_t[]>(BLOCK_SIZE);
memcpy(mData.get(), aData, BLOCK_SIZE);
}
@ -105,7 +106,7 @@ public:
explicit BlockChange(int32_t aSourceBlockIndex)
: mSourceBlockIndex(aSourceBlockIndex) {}
nsAutoArrayPtr<uint8_t> mData;
UniquePtr<uint8_t[]> mData;
const int32_t mSourceBlockIndex;
bool IsMove() const {

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

@ -379,7 +379,7 @@ MediaCacheStream::MediaCacheStream(ChannelMediaResource* aClient)
mPinCount(0),
mCurrentMode(MODE_PLAYBACK),
mMetadataInPartialBlockBuffer(false),
mPartialBlockBuffer(new int64_t[BLOCK_SIZE/sizeof(int64_t)])
mPartialBlockBuffer(MakeUnique<int64_t[]>(BLOCK_SIZE/sizeof(int64_t)))
{
}
@ -393,7 +393,7 @@ size_t MediaCacheStream::SizeOfExcludingThis(
size += mReadaheadBlocks.SizeOfExcludingThis(aMallocSizeOf);
size += mMetadataBlocks.SizeOfExcludingThis(aMallocSizeOf);
size += mPlayedBlocks.SizeOfExcludingThis(aMallocSizeOf);
size += mPartialBlockBuffer.SizeOfExcludingThis(aMallocSizeOf);
size += aMallocSizeOf(mPartialBlockBuffer.get());
return size;
}
@ -1842,7 +1842,7 @@ MediaCacheStream::FlushPartialBlockInternal(bool aNotifyAll,
// Write back the partial block
memset(reinterpret_cast<char*>(mPartialBlockBuffer.get()) + blockOffset, 0,
BLOCK_SIZE - blockOffset);
gMediaCache->AllocateAndWriteBlock(this, mPartialBlockBuffer,
gMediaCache->AllocateAndWriteBlock(this, mPartialBlockBuffer.get(),
mMetadataInPartialBlockBuffer ? MODE_METADATA : MODE_PLAYBACK);
}

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

@ -12,6 +12,7 @@
#include "nsHashKeys.h"
#include "nsTHashtable.h"
#include "Intervals.h"
#include "mozilla/UniquePtr.h"
class nsIPrincipal;
@ -510,7 +511,7 @@ private:
// Use int64_t so that the data is well-aligned.
// Heap allocate this buffer since the exact power-of-2 will cause allocation
// slop when combined with the rest of the object members.
nsAutoArrayPtr<int64_t> mPartialBlockBuffer;
UniquePtr<int64_t[]> mPartialBlockBuffer;
};
} // namespace mozilla

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

@ -12,6 +12,7 @@
#endif
#include "VideoUtils.h"
#include "ImageContainer.h"
#include "mozilla/UniquePtrExtensions.h"
#ifdef MOZ_WIDGET_GONK
#include <cutils/properties.h>
@ -533,8 +534,7 @@ MediaRawData::EnsureCapacity(size_t aSize)
if (mData && mCapacity >= sizeNeeded) {
return true;
}
nsAutoArrayPtr<uint8_t> newBuffer;
newBuffer = new (fallible) uint8_t[sizeNeeded];
auto newBuffer = MakeUniqueFallible<uint8_t[]>(sizeNeeded);
if (!newBuffer) {
return false;
}
@ -546,7 +546,7 @@ MediaRawData::EnsureCapacity(size_t aSize)
MOZ_ASSERT(uintptr_t(newData) % (RAW_DATA_ALIGNMENT+1) == 0);
memcpy(newData, mData, mSize);
mBuffer = newBuffer.forget();
mBuffer = Move(newBuffer);
mCapacity = sizeNeeded;
mData = newData;

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

@ -425,7 +425,7 @@ private:
bool EnsureCapacity(size_t aSize);
uint8_t* mData;
size_t mSize;
nsAutoArrayPtr<uint8_t> mBuffer;
UniquePtr<uint8_t[]> mBuffer;
uint32_t mCapacity;
CryptoSample mCryptoInternal;
MediaRawData(const MediaRawData&); // Not implemented

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

@ -577,7 +577,7 @@ private:
// Returns true if we can play the entire media through without stopping
// to buffer, given the current download and playback rates.
bool CanPlayThrough();
virtual bool CanPlayThrough();
void SetAudioChannel(dom::AudioChannel aChannel) { mAudioChannel = aChannel; }
dom::AudioChannel GetAudioChannel() { return mAudioChannel; }

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

@ -12,6 +12,7 @@
#include "mozilla/dom/HTMLMediaElement.h"
#include "mozilla/Monitor.h"
#include "mozilla/Preferences.h"
#include "mozilla/UniquePtr.h"
#include "nsIScriptSecurityManager.h"
#include "nsIStreamingProtocolService.h"
#include "nsServiceManagerUtils.h"
@ -72,7 +73,7 @@ public:
MOZ_COUNT_CTOR(RtspTrackBuffer);
mTrackIdx = aTrackIdx;
MOZ_ASSERT(mSlotSize < UINT32_MAX / BUFFER_SLOT_NUM);
mRingBuffer = new uint8_t[mTotalBufferSize];
mRingBuffer = MakeUnique<uint8_t[]>(mTotalBufferSize);
Reset();
};
~RtspTrackBuffer() {
@ -85,7 +86,7 @@ public:
size_t size = aMallocSizeOf(this);
// excluding this
size += mRingBuffer.SizeOfExcludingThis(aMallocSizeOf);
size += aMallocSizeOf(mRingBuffer.get());
return size;
}
@ -179,7 +180,7 @@ private:
BufferSlotData mBufferSlotData[BUFFER_SLOT_NUM];
// The ring buffer pointer.
nsAutoArrayPtr<uint8_t> mRingBuffer;
UniquePtr<uint8_t[]> mRingBuffer;
// Each slot's size.
uint32_t mSlotSize;
// Total mRingBuffer's total size.

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

@ -68,7 +68,7 @@ VideoFrame::CreateBlackImage(const gfx::IntSize& aSize)
data.mYSize = gfx::IntSize(aSize.width, aSize.height);
data.mYStride = (int32_t) (aSize.width * lumaBpp / 8.0);
data.mCbCrStride = (int32_t) (aSize.width * chromaBpp / 8.0);
data.mCbChannel = frame.rwget() + aSize.height * data.mYStride;
data.mCbChannel = frame.get() + aSize.height * data.mYStride;
data.mCrChannel = data.mCbChannel + aSize.height * data.mCbCrStride / 2;
data.mCbCrSize = gfx::IntSize(aSize.width / 2, aSize.height / 2);
data.mPicX = 0;

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

@ -6,6 +6,7 @@
#include "mozilla/Assertions.h"
#include "mozilla/Base64.h"
#include "mozilla/IntegerPrintfMacros.h"
#include "mozilla/UniquePtr.h"
#include "nsThreadUtils.h"
#include "nsIServiceManager.h"
#include "nsISocketTransport.h"
@ -263,7 +264,7 @@ ServeResourceEvent::Run() {
// HTTP response headers sent below. A static_assert ensures
// this where the buffer is used.
const int buffer_size = 32768;
nsAutoArrayPtr<char> b(new char[buffer_size]);
auto b = MakeUnique<char[]>(buffer_size);
// If we know the length of the resource, send a Content-Length header.
int64_t contentlength = resource->GetLength() - start;
@ -271,8 +272,8 @@ ServeResourceEvent::Run() {
static_assert (buffer_size > 1024,
"buffer_size must be large enough "
"to hold response headers");
snprintf(b, buffer_size, "Content-Length: %" PRId64 "\r\n", contentlength);
rv = WriteAll(b, strlen(b));
snprintf(b.get(), buffer_size, "Content-Length: %" PRId64 "\r\n", contentlength);
rv = WriteAll(b.get(), strlen(b.get()));
if (NS_FAILED(rv)) { Shutdown(); return NS_OK; }
}
@ -282,10 +283,10 @@ ServeResourceEvent::Run() {
static_assert (buffer_size > 1024,
"buffer_size must be large enough "
"to hold response headers");
snprintf(b, buffer_size, "Content-Range: "
snprintf(b.get(), buffer_size, "Content-Range: "
"bytes %" PRId64 "-%" PRId64 "/%" PRId64 "\r\n",
start, resource->GetLength() - 1, resource->GetLength());
rv = WriteAll(b, strlen(b));
rv = WriteAll(b.get(), strlen(b.get()));
if (NS_FAILED(rv)) { Shutdown(); return NS_OK; }
}
@ -297,7 +298,7 @@ ServeResourceEvent::Run() {
// Read data from media resource
uint32_t bytesRead = 0; // Number of bytes read/written to streams
rv = resource->ReadAt(start, b, buffer_size, &bytesRead);
rv = resource->ReadAt(start, b.get(), buffer_size, &bytesRead);
while (NS_SUCCEEDED(rv) && bytesRead != 0) {
// Keep track of what we think the starting position for the next read
// is. This is used in subsequent ReadAt calls to ensure we are reading
@ -306,10 +307,10 @@ ServeResourceEvent::Run() {
start += bytesRead;
// Write data obtained from media resource to output stream
rv = WriteAll(b, bytesRead);
rv = WriteAll(b.get(), bytesRead);
if (NS_FAILED (rv)) break;
rv = resource->ReadAt(start, b, 32768, &bytesRead);
rv = resource->ReadAt(start, b.get(), 32768, &bytesRead);
}
Shutdown();

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

@ -209,11 +209,12 @@ MediaKeySession::GenerateRequest(const nsAString& aInitDataType,
aInitDataType, data);
EME_LOG("MediaKeySession[%p,'%s'] GenerateRequest() sent, "
"promiseId=%d initData(base64)='%s'",
"promiseId=%d initData(base64)='%s' initDataType='%s'",
this,
NS_ConvertUTF16toUTF8(mSessionId).get(),
pid,
base64InitData.get());
base64InitData.get(),
NS_ConvertUTF16toUTF8(aInitDataType).get());
return promise.forget();
}

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

@ -441,9 +441,12 @@ GetSupportedConfig(mozIGeckoMediaPluginService* aGMPService,
if (aCandidate.mInitDataTypes.WasPassed()) {
nsTArray<nsString> initDataTypes;
for (const nsString& candidate : aCandidate.mInitDataTypes.Value()) {
// All supported keySystems can handle "cenc" initDataType.
// ClearKey also supports "keyids" and "webm" initDataTypes.
if (candidate.EqualsLiteral("cenc")) {
initDataTypes.AppendElement(candidate);
} else if (candidate.EqualsLiteral("keyids") &&
} else if ((candidate.EqualsLiteral("keyids") ||
candidate.EqualsLiteral("webm)")) &&
aKeySystem.EqualsLiteral("org.w3.clearkey")) {
initDataTypes.AppendElement(candidate);
}

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

@ -127,7 +127,7 @@ TrackRunBox::fillSampleTable()
return 0;
}
uint32_t len = frames.Length();
sample_info_table = new tbl[len];
sample_info_table = MakeUnique<tbl[]>(len);
// Create sample table according to 14496-12 8.8.8.2.
for (uint32_t i = 0; i < len; i++) {
// Sample size.

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

@ -11,6 +11,7 @@
#include "nsTArray.h"
#include "nsAutoPtr.h"
#include "MuxerOperation.h"
#include "mozilla/UniquePtr.h"
#define WRITE_FULLBOX(_compositor, _size) \
BoxSizeChecker checker(_compositor, _size); \
@ -262,7 +263,7 @@ public:
// the following are optional fields
uint32_t data_offset; // data offset exists when audio/video are present in file.
uint32_t first_sample_flags;
nsAutoArrayPtr<tbl> sample_info_table;
UniquePtr<tbl[]> sample_info_table;
// MuxerOperation methods
nsresult Generate(uint32_t* aBoxSize) override;
@ -404,7 +405,7 @@ public:
} tbl;
uint32_t entry_count;
nsAutoArrayPtr<tbl> sample_tbl;
UniquePtr<tbl[]> sample_tbl;
// MuxerOperation methods
nsresult Generate(uint32_t* aBoxSize) override;
@ -430,7 +431,7 @@ public:
} tbl;
uint32_t entry_count;
nsAutoArrayPtr<tbl> sample_tbl;
UniquePtr<tbl[]> sample_tbl;
// MuxerOperation methods
nsresult Generate(uint32_t* aBoxSize) override;
@ -455,7 +456,7 @@ public:
} tbl;
uint32_t entry_count;
nsAutoArrayPtr<tbl> sample_tbl;
UniquePtr<tbl[]> sample_tbl;
// MuxerOperation methods
nsresult Generate(uint32_t* aBoxSize) override;

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