Merge m-c to b2ginbound, a=merge
--HG-- extra : commitid : HBa9vqJvY25
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|