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

This commit is contained in:
Gurzau Raul 2018-11-13 23:49:10 +02:00
Родитель a80a7d22ae b8b0198b66
Коммит dcee77ca0f
22 изменённых файлов: 1053 добавлений и 926 удалений

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

@ -304,7 +304,7 @@ Object.defineProperty(this, "gHighPriorityNotificationBox", {
let notificationbox = new MozElements.NotificationBox(element => {
element.classList.add("global-notificationbox");
element.setAttribute("notificationside", "top");
document.getElementById("appcontent").append(element);
document.getElementById("appcontent").prepend(element);
});
return this.gHighPriorityNotificationBox = notificationbox;

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

@ -30,13 +30,15 @@ var SiteDataTestUtils = {
* @param {String} origin - the origin of the site to add test data for
* @param {String} name [optional] - the entry key
* @param {String} value [optional] - the entry value
* @param {Object} originAttributes [optional] - the originAttributes
*
* @returns a Promise that resolves when the data was added successfully.
*/
addToIndexedDB(origin, key = "foo", value = "bar") {
addToIndexedDB(origin, key = "foo", value = "bar", originAttributes = {}) {
return new Promise(resolve => {
let uri = Services.io.newURI(origin);
let principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {});
let principal =
Services.scriptSecurityManager.createCodebasePrincipal(uri, originAttributes);
let request = indexedDB.openForPrincipal(principal, "TestDatabase", 1);
request.onupgradeneeded = function(e) {
let db = e.target.result;

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

@ -2,15 +2,18 @@ ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
const {Sanitizer} = ChromeUtils.import("resource:///modules/Sanitizer.jsm", {});
const {SiteDataTestUtils} = ChromeUtils.import("resource://testing-common/SiteDataTestUtils.jsm", {});
function createIndexedDB(host) {
return SiteDataTestUtils.addToIndexedDB("https://" + host);
function createIndexedDB(host, originAttributes) {
return SiteDataTestUtils.addToIndexedDB("https://" + host, "foo", "bar",
originAttributes);
}
function checkIndexedDB(host) {
function checkIndexedDB(host, originAttributes) {
return new Promise(resolve => {
let data = true;
let uri = Services.io.newURI("https://" + host);
let principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {});
let principal =
Services.scriptSecurityManager.createCodebasePrincipal(uri,
originAttributes);
let request = indexedDB.openForPrincipal(principal, "TestDatabase", 1);
request.onupgradeneeded = function(e) {
data = false;
@ -21,21 +24,23 @@ function checkIndexedDB(host) {
});
}
function createHostCookie(host) {
function createHostCookie(host, originAttributes) {
Services.cookies.add(host, "/test", "foo", "bar",
false, false, false, Date.now() + 24000 * 60 * 60, {},
false, false, false, Date.now() + 24000 * 60 * 60, originAttributes,
Ci.nsICookie2.SAMESITE_UNSET);
}
function createDomainCookie(host) {
function createDomainCookie(host, originAttributes) {
Services.cookies.add("." + host, "/test", "foo", "bar",
false, false, false, Date.now() + 24000 * 60 * 60, {},
false, false, false, Date.now() + 24000 * 60 * 60, originAttributes,
Ci.nsICookie2.SAMESITE_UNSET);
}
function checkCookie(host) {
function checkCookie(host, originAttributes) {
for (let cookie of Services.cookies.enumerator) {
if (cookie.host.includes(host)) {
if (ChromeUtils.isOriginAttributesEqual(originAttributes,
cookie.originAttributes) &&
cookie.host.includes(host)) {
return true;
}
}
@ -52,27 +57,33 @@ async function deleteOnShutdown(opt) {
["network.cookie.lifetimePolicy", opt.lifetimePolicy],
]});
// Custom permission.
// Custom permission without considering OriginAttributes
if (opt.cookiePermission !== undefined) {
let uri = Services.io.newURI("https://www.example.com");
Services.perms.add(uri, "cookie", opt.cookiePermission);
}
// Let's create a tab with some data.
await opt.createData((opt.fullHost ? "www." : "") + "example.org");
ok(await opt.checkData((opt.fullHost ? "www." : "") + "example.org"),
await opt.createData((opt.fullHost ? "www." : "") + "example.org",
opt.originAttributes);
ok(await opt.checkData((opt.fullHost ? "www." : "") + "example.org",
opt.originAttributes),
"We have data for www.example.org");
await opt.createData((opt.fullHost ? "www." : "") + "example.com");
ok(await opt.checkData((opt.fullHost ? "www." : "") + "example.com"),
await opt.createData((opt.fullHost ? "www." : "") + "example.com",
opt.originAttributes);
ok(await opt.checkData((opt.fullHost ? "www." : "") + "example.com",
opt.originAttributes),
"We have data for www.example.com");
// Cleaning up.
await Sanitizer.runSanitizeOnShutdown();
// All gone!
is(!!(await opt.checkData((opt.fullHost ? "www." : "") + "example.org")),
is(!!(await opt.checkData((opt.fullHost ? "www." : "") + "example.org",
opt.originAttributes)),
opt.expectedForOrg, "Do we have data for www.example.org?");
is(!!(await opt.checkData((opt.fullHost ? "www." : "") + "example.com")),
is(!!(await opt.checkData((opt.fullHost ? "www." : "") + "example.com",
opt.originAttributes)),
opt.expectedForCom, "Do we have data for www.example.com?");
// Clean up.
@ -84,254 +95,141 @@ async function deleteOnShutdown(opt) {
}
}
// IDB: Delete all, no custom permission, data in example.com, cookie
// permission set for www.example.com
add_task(async function deleteStorageOnShutdown() {
await deleteOnShutdown(
{ lifetimePolicy: Ci.nsICookieService.ACCEPT_SESSION,
createData: createIndexedDB,
checkData: checkIndexedDB,
cookiePermission: undefined,
expectedForOrg: false,
expectedForCom: false,
fullHost: false,
let tests = [
{ name: "IDB",
createData: createIndexedDB,
checkData: checkIndexedDB },
{ name: "Host Cookie",
createData: createHostCookie,
checkData: checkCookie },
{ name: "Domain Cookie",
createData: createDomainCookie,
checkData: checkCookie },
];
let attributes = [
{name: "default", oa: {}},
{name: "container", oa: {userContextId: 1}},
];
// Delete all, no custom permission, data in example.com, cookie permission set
// for www.example.com
tests.forEach(methods => {
attributes.forEach(originAttributes => {
add_task(async function deleteStorageOnShutdown() {
info(methods.name + ": Delete all, no custom permission, data in example.com, cookie permission set for www.example.com - OA: " + originAttributes.name);
await deleteOnShutdown(
{ lifetimePolicy: Ci.nsICookieService.ACCEPT_SESSION,
createData: methods.createData,
checkData: methods.checkData,
originAttributes: originAttributes.oa,
cookiePermission: undefined,
expectedForOrg: false,
expectedForCom: false,
fullHost: false,
});
});
});
});
// IDB: Delete all, no custom permission, data in www.example.com, cookie
// permission set for www.example.com
add_task(async function deleteStorageOnShutdown() {
await deleteOnShutdown(
{ lifetimePolicy: Ci.nsICookieService.ACCEPT_SESSION,
createData: createIndexedDB,
checkData: checkIndexedDB,
cookiePermission: undefined,
expectedForOrg: false,
expectedForCom: false,
fullHost: true,
// Delete all, no custom permission, data in www.example.com, cookie permission
// set for www.example.com
tests.forEach(methods => {
attributes.forEach(originAttributes => {
add_task(async function deleteStorageOnShutdown() {
info(methods.name + ": Delete all, no custom permission, data in www.example.com, cookie permission set for www.example.com - OA: " + originAttributes.name);
await deleteOnShutdown(
{ lifetimePolicy: Ci.nsICookieService.ACCEPT_SESSION,
createData: methods.createData,
checkData: methods.checkData,
originAttributes: originAttributes.oa,
cookiePermission: undefined,
expectedForOrg: false,
expectedForCom: false,
fullHost: true,
});
});
});
});
// Host Cookie: Delete all, no custom permission, data in example.com, cookie
// permission set for www.example.com
add_task(async function deleteHostCookieOnShutdown() {
await deleteOnShutdown(
{ lifetimePolicy: Ci.nsICookieService.ACCEPT_SESSION,
createData: createHostCookie,
checkData: checkCookie,
cookiePermission: undefined,
expectedForOrg: false,
expectedForCom: false,
fullHost: false,
});
});
// Host Cookie: Delete all, no custom permission, data in www.example.com,
// All is session, but with ALLOW custom permission, data in example.com,
// cookie permission set for www.example.com
add_task(async function deleteHostCookieOnShutdown() {
await deleteOnShutdown(
{ lifetimePolicy: Ci.nsICookieService.ACCEPT_SESSION,
createData: createHostCookie,
checkData: checkCookie,
cookiePermission: undefined,
expectedForOrg: false,
expectedForCom: false,
fullHost: true,
tests.forEach(methods => {
attributes.forEach(originAttributes => {
add_task(async function deleteStorageWithCustomPermission() {
info(methods.name + ": All is session, but with ALLOW custom permission, data in example.com, cookie permission set for www.example.com - OA: " + originAttributes.name);
await deleteOnShutdown(
{ lifetimePolicy: Ci.nsICookieService.ACCEPT_SESSION,
createData: methods.createData,
checkData: methods.checkData,
originAttributes: originAttributes.oa,
cookiePermission: Ci.nsICookiePermission.ACCESS_ALLOW,
expectedForOrg: false,
expectedForCom: true,
fullHost: false,
});
});
});
});
// Domain Cookie: Delete all, no custom permission, data in example.com, cookie
// permission set for www.example.com
add_task(async function deleteDomainCookieOnShutdown() {
await deleteOnShutdown(
{ lifetimePolicy: Ci.nsICookieService.ACCEPT_SESSION,
createData: createDomainCookie,
checkData: checkCookie,
cookiePermission: undefined,
expectedForOrg: false,
expectedForCom: false,
fullHost: false,
});
});
// Domain Cookie: Delete all, no custom permission, data in www.example.com,
// All is session, but with ALLOW custom permission, data in www.example.com,
// cookie permission set for www.example.com
add_task(async function deleteDomainCookieOnShutdown() {
await deleteOnShutdown(
{ lifetimePolicy: Ci.nsICookieService.ACCEPT_SESSION,
createData: createDomainCookie,
checkData: checkCookie,
cookiePermission: undefined,
expectedForOrg: false,
expectedForCom: false,
fullHost: true,
tests.forEach(methods => {
attributes.forEach(originAttributes => {
add_task(async function deleteStorageWithCustomPermission() {
info(methods.name + ": All is session, but with ALLOW custom permission, data in www.example.com, cookie permission set for www.example.com - OA: " + originAttributes.name);
await deleteOnShutdown(
{ lifetimePolicy: Ci.nsICookieService.ACCEPT_SESSION,
createData: methods.createData,
checkData: methods.checkData,
originAttributes: originAttributes.oa,
cookiePermission: Ci.nsICookiePermission.ACCESS_ALLOW,
expectedForOrg: false,
expectedForCom: true,
fullHost: true,
});
});
});
});
// IDB: All is session, but with ALLOW custom permission, data in example.com,
// All is default, but with SESSION custom permission, data in example.com,
// cookie permission set for www.example.com
add_task(async function deleteStorageWithCustomPermission() {
await deleteOnShutdown(
{ lifetimePolicy: Ci.nsICookieService.ACCEPT_SESSION,
createData: createIndexedDB,
checkData: checkIndexedDB,
cookiePermission: Ci.nsICookiePermission.ACCESS_ALLOW,
expectedForOrg: false,
expectedForCom: true,
fullHost: false,
tests.forEach(methods => {
attributes.forEach(originAttributes => {
add_task(async function deleteStorageOnlyCustomPermission() {
info(methods.name + ": All is default, but with SESSION custom permission, data in example.com, cookie permission set for www.example.com - OA: " + originAttributes.name);
await deleteOnShutdown(
{ lifetimePolicy: Ci.nsICookieService.ACCEPT_NORMALLY,
createData: methods.createData,
checkData: methods.checkData,
originAttributes: originAttributes.oa,
cookiePermission: Ci.nsICookiePermission.ACCESS_SESSION,
expectedForOrg: true,
// expected data just for example.com when using indexedDB because
// QuotaManager deletes for principal.
expectedForCom: false,
fullHost: false,
});
});
});
});
// IDB: All is session, but with ALLOW custom permission, data in
// www.example.com, cookie permission set for www.example.com
add_task(async function deleteStorageWithCustomPermission() {
await deleteOnShutdown(
{ lifetimePolicy: Ci.nsICookieService.ACCEPT_SESSION,
createData: createIndexedDB,
checkData: checkIndexedDB,
cookiePermission: Ci.nsICookiePermission.ACCESS_ALLOW,
expectedForOrg: false,
expectedForCom: true,
fullHost: true,
});
});
// Host Cookie: All is session, but with ALLOW custom permission, data in
// example.com, cookie permission set for www.example.com
add_task(async function deleteHostCookieWithCustomPermission() {
await deleteOnShutdown(
{ lifetimePolicy: Ci.nsICookieService.ACCEPT_SESSION,
createData: createHostCookie,
checkData: checkCookie,
cookiePermission: Ci.nsICookiePermission.ACCESS_ALLOW,
expectedForOrg: false,
expectedForCom: true,
fullHost: false,
});
});
// Host Cookie: All is session, but with ALLOW custom permission, data in
// www.example.com, cookie permission set for www.example.com
add_task(async function deleteHostCookieWithCustomPermission() {
await deleteOnShutdown(
{ lifetimePolicy: Ci.nsICookieService.ACCEPT_SESSION,
createData: createHostCookie,
checkData: checkCookie,
cookiePermission: Ci.nsICookiePermission.ACCESS_ALLOW,
expectedForOrg: false,
expectedForCom: true,
fullHost: true,
});
});
// Domain Cookie: All is session, but with ALLOW custom permission, data in
// example.com, cookie permission set for www.example.com
add_task(async function deleteDomainCookieWithCustomPermission() {
await deleteOnShutdown(
{ lifetimePolicy: Ci.nsICookieService.ACCEPT_SESSION,
createData: createDomainCookie,
checkData: checkCookie,
cookiePermission: Ci.nsICookiePermission.ACCESS_ALLOW,
expectedForOrg: false,
expectedForCom: true,
fullHost: false,
});
});
// Domain Cookie: All is session, but with ALLOW custom permission, data in
// www.example.com, cookie permission set for www.example.com
add_task(async function deleteDomainCookieWithCustomPermission() {
await deleteOnShutdown(
{ lifetimePolicy: Ci.nsICookieService.ACCEPT_SESSION,
createData: createDomainCookie,
checkData: checkCookie,
cookiePermission: Ci.nsICookiePermission.ACCESS_ALLOW,
expectedForOrg: false,
expectedForCom: true,
fullHost: true,
});
});
// IDB: All is default, but with SESSION custom permission, data in
// example.com, cookie permission set for www.example.com
add_task(async function deleteStorageOnlyCustomPermission() {
await deleteOnShutdown(
{ lifetimePolicy: Ci.nsICookieService.ACCEPT_NORMALLY,
createData: createIndexedDB,
checkData: checkIndexedDB,
cookiePermission: Ci.nsICookiePermission.ACCESS_SESSION,
expectedForOrg: true,
expectedForCom: true,
fullHost: false,
});
});
// IDB: All is default, but with SESSION custom permission, data in
// www.example.com, cookie permission set for www.example.com
add_task(async function deleteStorageOnlyCustomPermission() {
await deleteOnShutdown(
{ lifetimePolicy: Ci.nsICookieService.ACCEPT_NORMALLY,
createData: createIndexedDB,
checkData: checkIndexedDB,
cookiePermission: Ci.nsICookiePermission.ACCESS_SESSION,
expectedForOrg: true,
expectedForCom: false,
fullHost: true,
});
});
// Host Cookie: All is default, but with SESSION custom permission, data in
// example.com, cookie permission set for www.example.com
add_task(async function deleteHostCookieOnlyCustomPermission() {
await deleteOnShutdown(
{ lifetimePolicy: Ci.nsICookieService.ACCEPT_NORMALLY,
createData: createHostCookie,
checkData: checkCookie,
cookiePermission: Ci.nsICookiePermission.ACCESS_SESSION,
expectedForOrg: true,
expectedForCom: false,
fullHost: false,
});
});
// Host Cookie: All is default, but with SESSION custom permission, data in
// www.example.com, cookie permission set for www.example.com
add_task(async function deleteHostCookieOnlyCustomPermission() {
await deleteOnShutdown(
{ lifetimePolicy: Ci.nsICookieService.ACCEPT_NORMALLY,
createData: createHostCookie,
checkData: checkCookie,
cookiePermission: Ci.nsICookiePermission.ACCESS_SESSION,
expectedForOrg: true,
expectedForCom: false,
fullHost: true,
});
});
// Domain Cookie: All is default, but with SESSION custom permission, data in
// example.com, cookie permission set for www.example.com
add_task(async function deleteDomainCookieOnlyCustomPermission() {
await deleteOnShutdown(
{ lifetimePolicy: Ci.nsICookieService.ACCEPT_NORMALLY,
createData: createDomainCookie,
checkData: checkCookie,
cookiePermission: Ci.nsICookiePermission.ACCESS_SESSION,
expectedForOrg: true,
expectedForCom: false,
fullHost: false,
});
});
// Domain Cookie: All is default, but with SESSION custom permission, data in
// www.example.com, cookie permission set for www.example.com
add_task(async function deleteDomainCookieOnlyCustomPermission() {
await deleteOnShutdown(
{ lifetimePolicy: Ci.nsICookieService.ACCEPT_NORMALLY,
createData: createDomainCookie,
checkData: checkCookie,
cookiePermission: Ci.nsICookiePermission.ACCESS_SESSION,
expectedForOrg: true,
expectedForCom: false,
fullHost: true,
// All is default, but with SESSION custom permission, data in www.example.com,
// cookie permission set for www.example.com
tests.forEach(methods => {
attributes.forEach(originAttributes => {
add_task(async function deleteStorageOnlyCustomPermission() {
info(methods.name + ": All is default, but with SESSION custom permission, data in www.example.com, cookie permission set for www.example.com - OA: " + originAttributes.name);
await deleteOnShutdown(
{ lifetimePolicy: Ci.nsICookieService.ACCEPT_NORMALLY,
createData: methods.createData,
checkData: methods.checkData,
originAttributes: originAttributes.oa,
cookiePermission: Ci.nsICookiePermission.ACCESS_SESSION,
expectedForOrg: true,
expectedForCom: false,
fullHost: true,
});
});
});
});

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

@ -682,12 +682,23 @@ async function sanitizeOnShutdown(progress) {
// the permission explicitly set to ACCEPT_SESSION need to be wiped. There
// are also other ways to think about and accomplish this, but this is what
// the logic below currently does!
await sanitizeSessionPrincipals();
if (Services.prefs.getIntPref(PREF_COOKIE_LIFETIME,
Ci.nsICookieService.ACCEPT_NORMALLY) == Ci.nsICookieService.ACCEPT_SESSION) {
let principals = await getAllPrincipals();
await maybeSanitizeSessionPrincipals(principals);
}
// Let's see if we have to forget some particular site.
for (let permission of Services.perms.enumerator) {
if (permission.type == "cookie" && permission.capability == Ci.nsICookiePermission.ACCESS_SESSION) {
await sanitizeSessionPrincipal(permission.principal);
// We use just the URI here, because permissions ignore OriginAttributes.
let principals = await getAllPrincipals(permission.principal.URI);
let promises = [];
principals.forEach(principal => {
promises.push(sanitizeSessionPrincipal(principal));
});
await Promise.all(promises);
}
}
@ -704,12 +715,10 @@ async function sanitizeOnShutdown(progress) {
}
}
async function sanitizeSessionPrincipals() {
if (Services.prefs.getIntPref(PREF_COOKIE_LIFETIME,
Ci.nsICookieService.ACCEPT_NORMALLY) != Ci.nsICookieService.ACCEPT_SESSION) {
return;
}
// Retrieve the list of nsIPrincipals with site data. If matchUri is not null,
// it returns only the principals matching that URI, ignoring the
// OriginAttributes.
async function getAllPrincipals(matchUri = null) {
let principals = await new Promise(resolve => {
quotaManagerService.getUsage(request => {
if (request.resultCode != Cr.NS_OK) {
@ -723,7 +732,8 @@ async function sanitizeSessionPrincipals() {
for (let item of request.result) {
let principal = Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(item.origin);
let uri = principal.URI;
if (uri.scheme == "http" || uri.scheme == "https" || uri.scheme == "file") {
if ((!matchUri || Services.eTLD.hasRootDomain(matchUri.host, uri.host)) &&
(uri.scheme == "http" || uri.scheme == "https" || uri.scheme == "file")) {
list.push(principal);
}
}
@ -734,14 +744,19 @@ async function sanitizeSessionPrincipals() {
let serviceWorkers = serviceWorkerManager.getAllRegistrations();
for (let i = 0; i < serviceWorkers.length; i++) {
let sw = serviceWorkers.queryElementAt(i, Ci.nsIServiceWorkerRegistrationInfo);
principals.push(sw.principal);
let uri = sw.principal.URI;
if (!matchUri || Services.eTLD.hasRootDomain(matchUri.host, uri.host)) {
principals.push(sw.principal);
}
}
// Let's take the list of unique hosts+OA from cookies.
let enumerator = Services.cookies.enumerator;
let hosts = new Set();
for (let cookie of enumerator) {
hosts.add(cookie.rawHost + ChromeUtils.originAttributesToSuffix(cookie.originAttributes));
if (!matchUri || Services.eTLD.hasRootDomain(matchUri.host, cookie.rawHost)) {
hosts.add(cookie.rawHost + ChromeUtils.originAttributesToSuffix(cookie.originAttributes));
}
}
hosts.forEach(host => {
@ -751,7 +766,7 @@ async function sanitizeSessionPrincipals() {
Services.scriptSecurityManager.createCodebasePrincipalFromOrigin("https://" + host));
});
await maybeSanitizeSessionPrincipals(principals);
return principals;
}
// This method receives a list of principals and it checks if some of them or
@ -788,11 +803,6 @@ function cookiesAllowedForDomainOrSubDomain(principal) {
continue;
}
if (!ChromeUtils.isOriginAttributesEqual(principal.originAttributes,
perm.principal.originAttributes)) {
continue;
}
// We don't care about scheme, port, and anything else.
if (Services.eTLD.hasRootDomain(perm.principal.URI.host,
principal.URI.host)) {

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

@ -243,7 +243,7 @@
button.open-accessibility-inspector,
button.open-inspector {
mask: url("../../../shared/components/reps/images/open-inspector.svg") no-repeat;
mask: url("resource://devtools/client/shared/components/reps/images/open-inspector.svg") no-repeat;
display: inline-block;
background-color: var(--comment-node-color);
height: 16px;
@ -264,7 +264,7 @@ button.open-inspector {
/* Jump to definition button */
button.jump-definition {
mask: url("../../../shared/components/reps/images/jump-definition.svg") no-repeat;
mask: url("resource://devtools/client/shared/components/reps/images/jump-definition.svg") no-repeat;
display: inline-block;
background-color: var(--comment-node-color);
height: 16px;
@ -338,7 +338,7 @@ button.jump-definition {
}
.tree-node img.arrow {
mask: url("../images/arrow.svg") no-repeat;
mask: url("resource://devtools/client/debugger/new/images/arrow.svg") no-repeat;
mask-size: 100%;
width: 9px;
height: 9px;
@ -951,7 +951,6 @@ menuseparator {
.split-box.horz > .splitter {
min-height: calc(var(--devtools-splitter-top-width) +
var(--devtools-splitter-bottom-width) + 1px);
border-top-width: var(--devtools-splitter-top-width);
border-bottom-width: var(--devtools-splitter-bottom-width);
@ -1035,39 +1034,39 @@ img.result-item-icon {
}
img.domain {
mask: url("../images/domain.svg") no-repeat;
mask: url("resource://devtools/client/debugger/new/images/domain.svg") no-repeat;
}
img.folder {
mask: url("../images/folder.svg") no-repeat;
mask: url("resource://devtools/client/debugger/new/images/folder.svg") no-repeat;
}
img.coffeescript {
mask: url("../images/coffeescript.svg") no-repeat;
mask: url("resource://devtools/client/debugger/new/images/coffeescript.svg") no-repeat;
}
img.javascript {
mask: url("../images/javascript.svg") no-repeat;
mask: url("resource://devtools/client/debugger/new/images/javascript.svg") no-repeat;
}
img.tab {
mask: url("../images/tab.svg") no-repeat;
mask: url("resource://devtools/client/debugger/new/images/tab.svg") no-repeat;
}
img.react {
mask: url("../images/react.svg") no-repeat;
mask: url("resource://devtools/client/debugger/new/images/react.svg") no-repeat;
}
img.typescript {
mask: url("../images/typescript.svg") no-repeat;
mask: url("resource://devtools/client/debugger/new/images/typescript.svg") no-repeat;
}
img.extension {
mask: url("../images/extension.svg") no-repeat;
mask: url("resource://devtools/client/debugger/new/images/extension.svg") no-repeat;
}
img.file {
mask: url("../images/file.svg") no-repeat;
mask: url("resource://devtools/client/debugger/new/images/file.svg") no-repeat;
width: 13px;
height: 13px;
}
@ -1096,7 +1095,7 @@ img.result-item-icon {
}
img.arrow {
mask: url("../images/arrow.svg");
mask: url("resource://devtools/client/debugger/new/images/arrow.svg");
margin-inline-end: 5px;
margin-top: 3px;
width: 9px;
@ -1244,7 +1243,7 @@ html[dir="rtl"] .managed-tree .tree .node > div {
}
.close-btn .close {
mask: url("../images/close.svg") no-repeat;
mask: url("resource://devtools/client/debugger/new/images/close.svg") no-repeat;
mask-size: 100%;
background-color: var(--theme-comment);
width: 8px;
@ -1862,7 +1861,7 @@ html .toggle-button.end.vertical svg {
}
.sources-list .managed-tree .tree .node img.blackBox {
mask: url("../images/blackBox.svg") no-repeat;
mask: url("resource://devtools/client/debugger/new/images/blackBox.svg") no-repeat;
mask-size: 100%;
background-color: var(--theme-highlight-blue);
width: 13px;
@ -2182,24 +2181,24 @@ menuseparator {
}
.source-icon.prettyPrint {
mask: url("../images/prettyPrint.svg") no-repeat;
mask: url("resource://devtools/client/debugger/new/images/prettyPrint.svg") no-repeat;
mask-size: 100%;
background: var(--theme-highlight-blue);
fill: var(--theme-textbox-box-shadow);
}
.source-icon.vue {
background: url("../images/vuejs.svg") 1px 1px no-repeat;
background: url("resource://devtools/client/debugger/new/images/vuejs.svg") 1px 1px no-repeat;
background-size: 15px;
}
.source-icon.angular {
background: url("../images/angular.svg") 1px 1px no-repeat;
background: url("resource://devtools/client/debugger/new/images/angular.svg") 1px 1px no-repeat;
background-size: 13px 13px;
}
.source-icon.blackBox {
mask: url("../images/blackBox.svg") no-repeat;
mask: url("resource://devtools/client/debugger/new/images/blackBox.svg") no-repeat;
mask-size: 100%;
background: var(--theme-highlight-blue);
}
@ -2274,14 +2273,14 @@ menuseparator {
}
.source-footer > .commands > .action > img.prettyPrint {
mask: url("../images/prettyPrint.svg") no-repeat;
mask: url("resource://devtools/client/debugger/new/images/prettyPrint.svg") no-repeat;
height: 16px;
width: 16px;
background: var(--theme-body-color);
}
.source-footer > .commands > .action > img.blackBox {
mask: url("../images/blackBox.svg") no-repeat;
mask: url("resource://devtools/client/debugger/new/images/blackBox.svg") no-repeat;
height: 16px;
width: 16px;
background: var(--theme-body-color);
@ -2682,7 +2681,7 @@ menuseparator {
.call-site::before {
content: "";
mask: url("../images/column-marker.svg") no-repeat 100% 100%;
mask: url("resource://devtools/client/debugger/new/images/column-marker.svg") no-repeat 100% 100%;
mask-size: contain;
display: inline-block;
background-color: var(--blue-55);
@ -2699,7 +2698,7 @@ menuseparator {
.call-site-bp::before {
content: "";
mask: url("../images/column-marker.svg") no-repeat 100% 100%;
mask: url("resource://devtools/client/debugger/new/images/column-marker.svg") no-repeat 100% 100%;
mask-size: contain;
display: inline-block;
background-color: var(--blue-55);
@ -2845,7 +2844,7 @@ html[dir="rtl"] .editor-mount {
height: 12px;
width: 9px;
background-color: var(--gutter-hover-background-color);
mask: url("../images/breakpoint.svg") no-repeat;
mask: url("resource://devtools/client/debugger/new/images/breakpoint.svg") no-repeat;
mask-size: auto 12px;
mask-position: right;
}
@ -3819,42 +3818,42 @@ img.skipPausing {
}
.command-bar img.pause {
mask: url("../images/pause.svg") no-repeat;
mask: url("resource://devtools/client/debugger/new/images/pause.svg") no-repeat;
}
.command-bar img.stepOver {
mask: url("../images/stepOver.svg") no-repeat;
mask: url("resource://devtools/client/debugger/new/images/stepOver.svg") no-repeat;
}
.command-bar img.stepIn {
mask: url("../images/stepIn.svg") no-repeat;
mask: url("resource://devtools/client/debugger/new/images/stepIn.svg") no-repeat;
}
.command-bar img.stepOut {
mask: url("../images/stepOut.svg") no-repeat;
mask: url("resource://devtools/client/debugger/new/images/stepOut.svg") no-repeat;
}
.command-bar img.resume {
mask: url("../images/resume.svg") no-repeat;
mask: url("resource://devtools/client/debugger/new/images/resume.svg") no-repeat;
}
.command-bar img.rewind {
mask: url("../images/resume.svg") no-repeat;
mask: url("resource://devtools/client/debugger/new/images/resume.svg") no-repeat;
transform: scaleX(-1);
}
.command-bar img.reverseStepOver {
mask: url("../images/stepOver.svg") no-repeat;
mask: url("resource://devtools/client/debugger/new/images/stepOver.svg") no-repeat;
transform: scaleX(-1);
}
.command-bar img.reverseStepIn {
mask: url("../images/stepIn.svg") no-repeat;
mask: url("resource://devtools/client/debugger/new/images/stepIn.svg") no-repeat;
transform: scaleX(-1);
}
.command-bar img.reverseStepOut {
mask: url("../images/stepOut.svg") no-repeat;
mask: url("resource://devtools/client/debugger/new/images/stepOut.svg") no-repeat;
transform: scaleX(-1);
}
@ -3863,7 +3862,7 @@ img.skipPausing {
}
.command-bar img.shortcuts {
mask: url("../images/help.svg") no-repeat;
mask: url("resource://devtools/client/debugger/new/images/help.svg") no-repeat;
mask-size: contain;
}
@ -3886,7 +3885,7 @@ img.skipPausing {
}
.command-bar .skipPausing {
mask: url("../images/disable-pausing.svg") no-repeat;
mask: url("resource://devtools/client/debugger/new/images/disable-pausing.svg") no-repeat;
mask-size: 100%;
}
@ -4316,7 +4315,7 @@ html .welcomebox .toggle-button-end.collapsed {
}
.source-tab img.react {
mask: url("../images/react.svg") no-repeat;
mask: url("resource://devtools/client/debugger/new/images/react.svg") no-repeat;
mask-size: 100%;
height: 14px;
width: 14px;
@ -4333,7 +4332,7 @@ html .welcomebox .toggle-button-end.collapsed {
}
img.moreTabs {
mask: url("../images/command-chevron.svg") no-repeat;
mask: url("resource://devtools/client/debugger/new/images/command-chevron.svg") no-repeat;
mask-size: 100%;
width: 12px;
height: 12px;
@ -4461,19 +4460,19 @@ html[dir="rtl"] .dropdown {
}
.dropdown-icon.prettyPrint {
mask: url("../images/prettyPrint.svg") no-repeat;
mask: url("resource://devtools/client/debugger/new/images/prettyPrint.svg") no-repeat;
mask-size: 100%;
background: var(--theme-highlight-blue);
}
.dropdown-icon.blackBox {
mask: url("../images/blackBox.svg") no-repeat;
mask: url("resource://devtools/client/debugger/new/images/blackBox.svg") no-repeat;
mask-size: 100%;
background: var(--theme-highlight-blue);
}
.dropdown-icon.file {
mask: url("../images/file.svg") no-repeat;
mask: url("resource://devtools/client/debugger/new/images/file.svg") no-repeat;
mask-size: 100%;
margin-bottom: 7px;
}

23
devtools/client/debugger/new/dist/vendors.css поставляемый
Просмотреть файл

@ -55,7 +55,7 @@
}
.tree-node img.arrow {
mask: url("chrome://devtools/skin/images/devtools-components/arrow.svg") no-repeat;
mask: url("resource://devtools/client/debugger/new/images/arrow.svg") no-repeat;
mask-size: 100%;
width: 9px;
height: 9px;
@ -148,7 +148,6 @@ html[dir="rtl"] .tree-node img.arrow {
.split-box.horz > .splitter {
min-height: calc(var(--devtools-splitter-top-width) +
var(--devtools-splitter-bottom-width) + 1px);
border-top-width: var(--devtools-splitter-top-width);
border-bottom-width: var(--devtools-splitter-bottom-width);
@ -232,39 +231,39 @@ img.result-item-icon {
}
img.domain {
mask: url("chrome://devtools/skin/images/debugger/domain.svg") no-repeat;
mask: url("resource://devtools/client/debugger/new/images/domain.svg") no-repeat;
}
img.folder {
mask: url("chrome://devtools/skin/images/debugger/folder.svg") no-repeat;
mask: url("resource://devtools/client/debugger/new/images/folder.svg") no-repeat;
}
img.coffeescript {
mask: url("chrome://devtools/skin/images/debugger/coffeescript.svg") no-repeat;
mask: url("resource://devtools/client/debugger/new/images/coffeescript.svg") no-repeat;
}
img.javascript {
mask: url("chrome://devtools/skin/images/debugger/javascript.svg") no-repeat;
mask: url("resource://devtools/client/debugger/new/images/javascript.svg") no-repeat;
}
img.tab {
mask: url("chrome://devtools/skin/images/debugger/tab.svg") no-repeat;
mask: url("resource://devtools/client/debugger/new/images/tab.svg") no-repeat;
}
img.react {
mask: url("chrome://devtools/skin/images/debugger/react.svg") no-repeat;
mask: url("resource://devtools/client/debugger/new/images/react.svg") no-repeat;
}
img.typescript {
mask: url("chrome://devtools/skin/images/debugger/typescript.svg") no-repeat;
mask: url("resource://devtools/client/debugger/new/images/typescript.svg") no-repeat;
}
img.extension {
mask: url("chrome://devtools/skin/images/debugger/extension.svg") no-repeat;
mask: url("resource://devtools/client/debugger/new/images/extension.svg") no-repeat;
}
img.file {
mask: url("chrome://devtools/skin/images/debugger/file.svg") no-repeat;
mask: url("resource://devtools/client/debugger/new/images/file.svg") no-repeat;
width: 13px;
height: 13px;
}
@ -293,7 +292,7 @@ img.result-item-icon {
}
img.arrow {
mask: url("chrome://devtools/skin/images/debugger/arrow.svg");
mask: url("resource://devtools/client/debugger/new/images/arrow.svg");
margin-inline-end: 5px;
margin-top: 3px;
width: 9px;

782
devtools/client/debugger/new/dist/vendors.js поставляемый
Просмотреть файл

@ -1241,13 +1241,6 @@ module.exports = "<!-- This Source Code Form is subject to the terms of the Mozi
/***/ }),
/***/ 1309:
/***/ (function(module, exports) {
// removed by extract-text-webpack-plugin
/***/ }),
/***/ 1310:
/***/ (function(module, exports) {
@ -1669,15 +1662,6 @@ module.exports = {
/***/ }),
/***/ 1440:
/***/ (function(module, exports, __webpack_require__) {
const SplitBox = __webpack_require__(1536);
module.exports = SplitBox;
/***/ }),
/***/ 1461:
/***/ (function(module, exports, __webpack_require__) {
@ -2556,337 +2540,6 @@ exports.register = function (window) {};
/***/ }),
/***/ 1536:
/***/ (function(module, exports, __webpack_require__) {
/* 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/. */
const React = __webpack_require__(0);
const ReactDOM = __webpack_require__(4);
const Draggable = React.createFactory(__webpack_require__(1537));
const { Component } = React;
const PropTypes = __webpack_require__(3642);
const dom = __webpack_require__(3643);
__webpack_require__(1309);
/**
* This component represents a Splitter. The splitter supports vertical
* as well as horizontal mode.
*/
class SplitBox extends Component {
static get propTypes() {
return {
// Custom class name. You can use more names separated by a space.
className: PropTypes.string,
// Initial size of controlled panel.
initialSize: PropTypes.any,
// Optional initial width of controlled panel.
initialWidth: PropTypes.number,
// Optional initial height of controlled panel.
initialHeight: PropTypes.number,
// Left/top panel
startPanel: PropTypes.any,
// Left/top panel collapse state.
startPanelCollapsed: PropTypes.bool,
// Min panel size.
minSize: PropTypes.any,
// Max panel size.
maxSize: PropTypes.any,
// Right/bottom panel
endPanel: PropTypes.any,
// Right/bottom panel collapse state.
endPanelCollapsed: PropTypes.bool,
// True if the right/bottom panel should be controlled.
endPanelControl: PropTypes.bool,
// Size of the splitter handle bar.
splitterSize: PropTypes.number,
// True if the splitter bar is vertical (default is vertical).
vert: PropTypes.bool,
// Optional style properties passed into the splitbox
style: PropTypes.object,
// Optional callback when splitbox resize stops
onResizeEnd: PropTypes.func
};
}
static get defaultProps() {
return {
splitterSize: 5,
vert: true,
endPanelControl: false,
endPanelCollapsed: false,
startPanelCollapsed: false
};
}
constructor(props) {
super(props);
this.state = {
vert: props.vert,
// We use integers for these properties
width: parseInt(props.initialWidth || props.initialSize, 10),
height: parseInt(props.initialHeight || props.initialSize, 10)
};
this.onStartMove = this.onStartMove.bind(this);
this.onStopMove = this.onStopMove.bind(this);
this.onMove = this.onMove.bind(this);
this.preparePanelStyles = this.preparePanelStyles.bind(this);
}
componentWillReceiveProps(nextProps) {
if (this.props.vert !== nextProps.vert) {
this.setState({ vert: nextProps.vert });
}
if (this.props.initialSize !== nextProps.initialSize || this.props.initialWidth !== nextProps.initialWidth || this.props.initialHeight !== nextProps.initialHeight) {
this.setState({
width: parseInt(nextProps.initialWidth || nextProps.initialSize, 10),
height: parseInt(nextProps.initialHeight || nextProps.initialSize, 10)
});
}
}
// Dragging Events
/**
* Set 'resizing' cursor on entire document during splitter dragging.
* This avoids cursor-flickering that happens when the mouse leaves
* the splitter bar area (happens frequently).
*/
onStartMove() {
const splitBox = ReactDOM.findDOMNode(this);
const doc = splitBox.ownerDocument;
let defaultCursor = doc.documentElement.style.cursor;
doc.documentElement.style.cursor = this.state.vert ? "ew-resize" : "ns-resize";
splitBox.classList.add("dragging");
document.dispatchEvent(new CustomEvent("drag:start"));
this.setState({
defaultCursor: defaultCursor
});
}
onStopMove() {
const splitBox = ReactDOM.findDOMNode(this);
const doc = splitBox.ownerDocument;
doc.documentElement.style.cursor = this.state.defaultCursor;
splitBox.classList.remove("dragging");
document.dispatchEvent(new CustomEvent("drag:end"));
if (this.props.onResizeEnd) {
this.props.onResizeEnd(this.state.vert ? this.state.width : this.state.height);
}
}
/**
* Adjust size of the controlled panel. Depending on the current
* orientation we either remember the width or height of
* the splitter box.
*/
onMove({ movementX, movementY }) {
const node = ReactDOM.findDOMNode(this);
const doc = node.ownerDocument;
if (this.props.endPanelControl) {
// For the end panel we need to increase the width/height when the
// movement is towards the left/top.
movementX = -movementX;
movementY = -movementY;
}
if (this.state.vert) {
const isRtl = doc.dir === "rtl";
if (isRtl) {
// In RTL we need to reverse the movement again -- but only for vertical
// splitters
movementX = -movementX;
}
this.setState((state, props) => ({
width: state.width + movementX
}));
} else {
this.setState((state, props) => ({
height: state.height + movementY
}));
}
}
// Rendering
preparePanelStyles() {
const vert = this.state.vert;
const {
minSize,
maxSize,
startPanelCollapsed,
endPanelControl,
endPanelCollapsed
} = this.props;
let leftPanelStyle, rightPanelStyle;
// Set proper size for panels depending on the current state.
if (vert) {
let startWidth = endPanelControl ? null : this.state.width,
endWidth = endPanelControl ? this.state.width : null;
leftPanelStyle = {
maxWidth: endPanelControl ? null : maxSize,
minWidth: endPanelControl ? null : minSize,
width: startPanelCollapsed ? 0 : startWidth
};
rightPanelStyle = {
maxWidth: endPanelControl ? maxSize : null,
minWidth: endPanelControl ? minSize : null,
width: endPanelCollapsed ? 0 : endWidth
};
} else {
let startHeight = endPanelControl ? null : this.state.height,
endHeight = endPanelControl ? this.state.height : null;
leftPanelStyle = {
maxHeight: endPanelControl ? null : maxSize,
minHeight: endPanelControl ? null : minSize,
height: endPanelCollapsed ? maxSize : startHeight
};
rightPanelStyle = {
maxHeight: endPanelControl ? maxSize : null,
minHeight: endPanelControl ? minSize : null,
height: startPanelCollapsed ? maxSize : endHeight
};
}
return { leftPanelStyle, rightPanelStyle };
}
render() {
const vert = this.state.vert;
const {
startPanelCollapsed,
startPanel,
endPanel,
endPanelControl,
splitterSize,
endPanelCollapsed
} = this.props;
let style = Object.assign({}, this.props.style);
// Calculate class names list.
let classNames = ["split-box"];
classNames.push(vert ? "vert" : "horz");
if (this.props.className) {
classNames = classNames.concat(this.props.className.split(" "));
}
const { leftPanelStyle, rightPanelStyle } = this.preparePanelStyles();
// Calculate splitter size
let splitterStyle = {
flex: `0 0 ${splitterSize}px`
};
return dom.div({
className: classNames.join(" "),
style: style
}, !startPanelCollapsed ? dom.div({
className: endPanelControl ? "uncontrolled" : "controlled",
style: leftPanelStyle
}, startPanel) : null, Draggable({
className: "splitter",
style: splitterStyle,
onStart: this.onStartMove,
onStop: this.onStopMove,
onMove: this.onMove
}), !endPanelCollapsed ? dom.div({
className: endPanelControl ? "controlled" : "uncontrolled",
style: rightPanelStyle
}, endPanel) : null);
}
}
module.exports = SplitBox;
/***/ }),
/***/ 1537:
/***/ (function(module, exports, __webpack_require__) {
/* 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/. */
const React = __webpack_require__(0);
const ReactDOM = __webpack_require__(4);
const { Component } = React;
const PropTypes = __webpack_require__(3642);
const dom = __webpack_require__(3643);
class Draggable extends Component {
static get propTypes() {
return {
onMove: PropTypes.func.isRequired,
onStart: PropTypes.func,
onStop: PropTypes.func,
style: PropTypes.object,
className: PropTypes.string
};
}
constructor(props) {
super(props);
this.startDragging = this.startDragging.bind(this);
this.onMove = this.onMove.bind(this);
this.onUp = this.onUp.bind(this);
}
startDragging(ev) {
ev.preventDefault();
const doc = ReactDOM.findDOMNode(this).ownerDocument;
doc.addEventListener("mousemove", this.onMove);
doc.addEventListener("mouseup", this.onUp);
this.props.onStart && this.props.onStart();
}
onMove(ev) {
ev.preventDefault();
// When the target is outside of the document, its tagName is undefined
if (!ev.target.tagName) {
return
}
// We pass the whole event because we don't know which properties
// the callee needs.
this.props.onMove(ev);
}
onUp(ev) {
ev.preventDefault();
const doc = ReactDOM.findDOMNode(this).ownerDocument;
doc.removeEventListener("mousemove", this.onMove);
doc.removeEventListener("mouseup", this.onUp);
this.props.onStop && this.props.onStop();
}
render() {
return dom.div({
style: this.props.style,
className: this.props.className,
onMouseDown: this.startDragging
});
}
}
module.exports = Draggable;
/***/ }),
/***/ 1540:
/***/ (function(module, exports, __webpack_require__) {
@ -7287,7 +6940,7 @@ var _classnames = __webpack_require__(175);
var _classnames2 = _interopRequireDefault(_classnames);
var _devtoolsSplitter = __webpack_require__(1440);
var _devtoolsSplitter = __webpack_require__(3802);
var _devtoolsSplitter2 = _interopRequireDefault(_devtoolsSplitter);
@ -8784,6 +8437,353 @@ module.exports = "<svg viewBox=\"0 0 9 12\" version=\"1.1\" xmlns=\"http://www.w
/***/ }),
/***/ 3802:
/***/ (function(module, exports, __webpack_require__) {
const SplitBox = __webpack_require__(3803);
module.exports = SplitBox;
/***/ }),
/***/ 3803:
/***/ (function(module, exports, __webpack_require__) {
/* 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/>. */
const React = __webpack_require__(0);
const ReactDOM = __webpack_require__(4);
const Draggable = React.createFactory(__webpack_require__(3804));
const { Component } = React;
const PropTypes = __webpack_require__(3642);
const dom = __webpack_require__(3643);
__webpack_require__(3805);
/**
* This component represents a Splitter. The splitter supports vertical
* as well as horizontal mode.
*/
class SplitBox extends Component {
static get propTypes() {
return {
// Custom class name. You can use more names separated by a space.
className: PropTypes.string,
// Initial size of controlled panel.
initialSize: PropTypes.any,
// Optional initial width of controlled panel.
initialWidth: PropTypes.number,
// Optional initial height of controlled panel.
initialHeight: PropTypes.number,
// Left/top panel
startPanel: PropTypes.any,
// Left/top panel collapse state.
startPanelCollapsed: PropTypes.bool,
// Min panel size.
minSize: PropTypes.any,
// Max panel size.
maxSize: PropTypes.any,
// Right/bottom panel
endPanel: PropTypes.any,
// Right/bottom panel collapse state.
endPanelCollapsed: PropTypes.bool,
// True if the right/bottom panel should be controlled.
endPanelControl: PropTypes.bool,
// Size of the splitter handle bar.
splitterSize: PropTypes.number,
// True if the splitter bar is vertical (default is vertical).
vert: PropTypes.bool,
// Optional style properties passed into the splitbox
style: PropTypes.object,
// Optional callback when splitbox resize stops
onResizeEnd: PropTypes.func
};
}
static get defaultProps() {
return {
splitterSize: 5,
vert: true,
endPanelControl: false,
endPanelCollapsed: false,
startPanelCollapsed: false
};
}
constructor(props) {
super(props);
this.state = {
vert: props.vert,
// We use integers for these properties
width: parseInt(props.initialWidth || props.initialSize, 10),
height: parseInt(props.initialHeight || props.initialSize, 10)
};
this.onStartMove = this.onStartMove.bind(this);
this.onStopMove = this.onStopMove.bind(this);
this.onMove = this.onMove.bind(this);
this.preparePanelStyles = this.preparePanelStyles.bind(this);
}
componentWillReceiveProps(nextProps) {
if (this.props.vert !== nextProps.vert) {
this.setState({ vert: nextProps.vert });
}
if (this.props.initialSize !== nextProps.initialSize || this.props.initialWidth !== nextProps.initialWidth || this.props.initialHeight !== nextProps.initialHeight) {
this.setState({
width: parseInt(nextProps.initialWidth || nextProps.initialSize, 10),
height: parseInt(nextProps.initialHeight || nextProps.initialSize, 10)
});
}
}
// Dragging Events
/**
* Set 'resizing' cursor on entire document during splitter dragging.
* This avoids cursor-flickering that happens when the mouse leaves
* the splitter bar area (happens frequently).
*/
onStartMove() {
const splitBox = ReactDOM.findDOMNode(this);
const doc = splitBox.ownerDocument;
const defaultCursor = doc.documentElement.style.cursor;
doc.documentElement.style.cursor = this.state.vert ? "ew-resize" : "ns-resize";
splitBox.classList.add("dragging");
document.dispatchEvent(new CustomEvent("drag:start"));
this.setState({
defaultCursor: defaultCursor
});
}
onStopMove() {
const splitBox = ReactDOM.findDOMNode(this);
const doc = splitBox.ownerDocument;
doc.documentElement.style.cursor = this.state.defaultCursor;
splitBox.classList.remove("dragging");
document.dispatchEvent(new CustomEvent("drag:end"));
if (this.props.onResizeEnd) {
this.props.onResizeEnd(this.state.vert ? this.state.width : this.state.height);
}
}
/**
* Adjust size of the controlled panel. Depending on the current
* orientation we either remember the width or height of
* the splitter box.
*/
onMove({ movementX, movementY }) {
const node = ReactDOM.findDOMNode(this);
const doc = node.ownerDocument;
if (this.props.endPanelControl) {
// For the end panel we need to increase the width/height when the
// movement is towards the left/top.
movementX = -movementX;
movementY = -movementY;
}
if (this.state.vert) {
const isRtl = doc.dir === "rtl";
if (isRtl) {
// In RTL we need to reverse the movement again -- but only for vertical
// splitters
movementX = -movementX;
}
this.setState((state, props) => ({
width: state.width + movementX
}));
} else {
this.setState((state, props) => ({
height: state.height + movementY
}));
}
}
// Rendering
preparePanelStyles() {
const vert = this.state.vert;
const {
minSize,
maxSize,
startPanelCollapsed,
endPanelControl,
endPanelCollapsed
} = this.props;
let leftPanelStyle, rightPanelStyle;
// Set proper size for panels depending on the current state.
if (vert) {
const startWidth = endPanelControl ? null : this.state.width,
endWidth = endPanelControl ? this.state.width : null;
leftPanelStyle = {
maxWidth: endPanelControl ? null : maxSize,
minWidth: endPanelControl ? null : minSize,
width: startPanelCollapsed ? 0 : startWidth
};
rightPanelStyle = {
maxWidth: endPanelControl ? maxSize : null,
minWidth: endPanelControl ? minSize : null,
width: endPanelCollapsed ? 0 : endWidth
};
} else {
const startHeight = endPanelControl ? null : this.state.height,
endHeight = endPanelControl ? this.state.height : null;
leftPanelStyle = {
maxHeight: endPanelControl ? null : maxSize,
minHeight: endPanelControl ? null : minSize,
height: endPanelCollapsed ? maxSize : startHeight
};
rightPanelStyle = {
maxHeight: endPanelControl ? maxSize : null,
minHeight: endPanelControl ? minSize : null,
height: startPanelCollapsed ? maxSize : endHeight
};
}
return { leftPanelStyle, rightPanelStyle };
}
render() {
const vert = this.state.vert;
const {
startPanelCollapsed,
startPanel,
endPanel,
endPanelControl,
splitterSize,
endPanelCollapsed
} = this.props;
const style = Object.assign({}, this.props.style);
// Calculate class names list.
let classNames = ["split-box"];
classNames.push(vert ? "vert" : "horz");
if (this.props.className) {
classNames = classNames.concat(this.props.className.split(" "));
}
const { leftPanelStyle, rightPanelStyle } = this.preparePanelStyles();
// Calculate splitter size
const splitterStyle = {
flex: `0 0 ${splitterSize}px`
};
return dom.div({
className: classNames.join(" "),
style: style
}, !startPanelCollapsed ? dom.div({
className: endPanelControl ? "uncontrolled" : "controlled",
style: leftPanelStyle
}, startPanel) : null, Draggable({
className: "splitter",
style: splitterStyle,
onStart: this.onStartMove,
onStop: this.onStopMove,
onMove: this.onMove
}), !endPanelCollapsed ? dom.div({
className: endPanelControl ? "controlled" : "uncontrolled",
style: rightPanelStyle
}, endPanel) : null);
}
}
module.exports = SplitBox;
/***/ }),
/***/ 3804:
/***/ (function(module, exports, __webpack_require__) {
/* 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/>. */
const React = __webpack_require__(0);
const ReactDOM = __webpack_require__(4);
const { Component } = React;
const PropTypes = __webpack_require__(3642);
const dom = __webpack_require__(3643);
class Draggable extends Component {
static get propTypes() {
return {
onMove: PropTypes.func.isRequired,
onStart: PropTypes.func,
onStop: PropTypes.func,
style: PropTypes.object,
className: PropTypes.string
};
}
constructor(props) {
super(props);
this.startDragging = this.startDragging.bind(this);
this.onMove = this.onMove.bind(this);
this.onUp = this.onUp.bind(this);
}
startDragging(ev) {
ev.preventDefault();
const doc = ReactDOM.findDOMNode(this).ownerDocument;
doc.addEventListener("mousemove", this.onMove);
doc.addEventListener("mouseup", this.onUp);
this.props.onStart && this.props.onStart();
}
onMove(ev) {
ev.preventDefault();
// When the target is outside of the document, its tagName is undefined
if (!ev.target.tagName) {
return;
}
// We pass the whole event because we don't know which properties
// the callee needs.
this.props.onMove(ev);
}
onUp(ev) {
ev.preventDefault();
const doc = ReactDOM.findDOMNode(this).ownerDocument;
doc.removeEventListener("mousemove", this.onMove);
doc.removeEventListener("mouseup", this.onUp);
this.props.onStop && this.props.onStop();
}
render() {
return dom.div({
style: this.props.style,
className: this.props.className,
onMouseDown: this.startDragging
});
}
}
module.exports = Draggable;
/***/ }),
/***/ 3805:
/***/ (function(module, exports) {
// removed by extract-text-webpack-plugin
/***/ }),
/***/ 4:
/***/ (function(module, exports) {
@ -9328,27 +9328,27 @@ module.exports = hashClear;
/***/ 792:
/***/ (function(module, exports) {
var g;
// This works in non-strict mode
g = (function() {
return this;
})();
try {
// This works if eval is allowed (see CSP)
g = g || Function("return this")() || (1,eval)("this");
} catch(e) {
// This works if the window reference is available
if(typeof window === "object")
g = window;
}
// g can still be undefined, but nothing to do about it...
// We return undefined, instead of nothing here, so it's
// easier to handle this case. if(!global) { ...}
module.exports = g;
var g;
// This works in non-strict mode
g = (function() {
return this;
})();
try {
// This works if eval is allowed (see CSP)
g = g || Function("return this")() || (1,eval)("this");
} catch(e) {
// This works if the window reference is available
if(typeof window === "object")
g = window;
}
// g can still be undefined, but nothing to do about it...
// We return undefined, instead of nothing here, so it's
// easier to handle this case. if(!global) { ...}
module.exports = g;
/***/ }),
@ -9356,28 +9356,28 @@ module.exports = g;
/***/ 793:
/***/ (function(module, exports) {
module.exports = function(module) {
if(!module.webpackPolyfill) {
module.deprecate = function() {};
module.paths = [];
// module.parent = undefined by default
if(!module.children) module.children = [];
Object.defineProperty(module, "loaded", {
enumerable: true,
get: function() {
return module.l;
}
});
Object.defineProperty(module, "id", {
enumerable: true,
get: function() {
return module.i;
}
});
module.webpackPolyfill = 1;
}
return module;
};
module.exports = function(module) {
if(!module.webpackPolyfill) {
module.deprecate = function() {};
module.paths = [];
// module.parent = undefined by default
if(!module.children) module.children = [];
Object.defineProperty(module, "loaded", {
enumerable: true,
get: function() {
return module.l;
}
});
Object.defineProperty(module, "id", {
enumerable: true,
get: function() {
return module.i;
}
});
module.webpackPolyfill = 1;
}
return module;
};
/***/ }),

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

@ -1,3 +1,4 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
@ -5,7 +6,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DevToolsModules(
'angular.svg',
'angular.svg',
'arrow.svg',
'blackBox.svg',
'breakpoint.svg',
@ -30,5 +31,4 @@ DevToolsModules(
'tab.svg',
'typescript.svg',
'vuejs.svg',
)
)

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

@ -14,8 +14,7 @@
height: 100%;
}
.network-monitor .panel-container,
.network-monitor .properties-view {
.network-monitor .panel-container {
display: flex;
flex-direction: column;
overflow-x: hidden;
@ -28,6 +27,8 @@
}
.network-monitor .properties-view {
display: flex;
flex-direction: column;
flex-grow: 1;
}

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

@ -243,7 +243,7 @@
button.open-accessibility-inspector,
button.open-inspector {
mask: url("./images/open-inspector.svg") no-repeat;
mask: url("resource://devtools/client/shared/components/reps/images/open-inspector.svg") no-repeat;
display: inline-block;
background-color: var(--comment-node-color);
height: 16px;
@ -264,7 +264,7 @@ button.open-inspector {
/* Jump to definition button */
button.jump-definition {
mask: url("./images/jump-definition.svg") no-repeat;
mask: url("resource://devtools/client/shared/components/reps/images/jump-definition.svg") no-repeat;
display: inline-block;
background-color: var(--comment-node-color);
height: 16px;
@ -338,7 +338,7 @@ button.jump-definition {
}
.tree-node img.arrow {
mask: url("chrome://devtools/skin/images/devtools-components/arrow.svg") no-repeat;
mask: url("resource://devtools/client/debugger/new/images/arrow.svg") no-repeat;
mask-size: 100%;
width: 9px;
height: 9px;

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

@ -320,8 +320,8 @@ public abstract class GeckoApp extends GeckoActivity
protected boolean mInitialized;
protected boolean mWindowFocusInitialized;
private Telemetry.Timer mJavaUiStartupTimer;
private Telemetry.Timer mGeckoReadyStartupTimer;
private TelemetryUtils.Timer mJavaUiStartupTimer;
private TelemetryUtils.Timer mGeckoReadyStartupTimer;
private String mPrivateBrowsingSession;
private boolean mPrivateBrowsingSessionOutdated;
@ -978,8 +978,8 @@ public abstract class GeckoApp extends GeckoActivity
}
// The clock starts...now. Better hurry!
mJavaUiStartupTimer = new Telemetry.UptimeTimer("FENNEC_STARTUP_TIME_JAVAUI");
mGeckoReadyStartupTimer = new Telemetry.UptimeTimer("FENNEC_STARTUP_TIME_GECKOREADY");
mJavaUiStartupTimer = new TelemetryUtils.UptimeTimer("FENNEC_STARTUP_TIME_JAVAUI");
mGeckoReadyStartupTimer = new TelemetryUtils.UptimeTimer("FENNEC_STARTUP_TIME_GECKOREADY");
final SafeIntent intent = new SafeIntent(getIntent());

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

@ -13,7 +13,6 @@ import org.mozilla.gecko.TelemetryContract.Reason;
import org.mozilla.gecko.TelemetryContract.Session;
import org.mozilla.gecko.mma.MmaDelegate;
import android.os.SystemClock;
import android.util.Log;
import static org.mozilla.gecko.mma.MmaDelegate.INTERACT_WITH_SEARCH_URL_AREA;
@ -23,138 +22,20 @@ import static org.mozilla.gecko.mma.MmaDelegate.SAVED_LOGIN_AND_PASSWORD;
import static org.mozilla.gecko.mma.MmaDelegate.SCREENSHOT;
/**
* All telemetry times are relative to one of two clocks:
*
* * Real time since the device was booted, including deep sleep. Use this
* as a substitute for wall clock.
* * Uptime since the device was booted, excluding deep sleep. Use this to
* avoid timing a user activity when their phone is in their pocket!
*
* The majority of methods in this class are defined in terms of real time.
*/
@RobocopTarget
public class Telemetry {
private static final String LOGTAG = "Telemetry";
@WrapForJNI(stubName = "AddHistogram", dispatchTo = "gecko")
private static native void nativeAddHistogram(String name, int value);
@WrapForJNI(stubName = "AddKeyedHistogram", dispatchTo = "gecko")
private static native void nativeAddKeyedHistogram(String name, String key, int value);
@WrapForJNI(stubName = "StartUISession", dispatchTo = "gecko")
private static native void nativeStartUiSession(String name, long timestamp);
@WrapForJNI(stubName = "StopUISession", dispatchTo = "gecko")
private static native void nativeStopUiSession(String name, String reason, long timestamp);
@WrapForJNI(stubName = "AddUIEvent", dispatchTo = "gecko")
private static native void nativeAddUiEvent(String action, String method,
long timestamp, String extras);
public static long uptime() {
return SystemClock.uptimeMillis();
}
public static long realtime() {
return SystemClock.elapsedRealtime();
}
// Define new histograms in:
// toolkit/components/telemetry/Histograms.json
public static void addToHistogram(String name, int value) {
if (GeckoThread.isRunning()) {
nativeAddHistogram(name, value);
} else {
GeckoThread.queueNativeCall(Telemetry.class, "nativeAddHistogram",
String.class, name, value);
}
TelemetryUtils.addToHistogram(name, value);
}
public static void addToKeyedHistogram(String name, String key, int value) {
if (GeckoThread.isRunning()) {
nativeAddKeyedHistogram(name, key, value);
} else {
GeckoThread.queueNativeCall(Telemetry.class, "nativeAddKeyedHistogram",
String.class, name, String.class, key, value);
}
}
public abstract static class Timer {
private final long mStartTime;
private final String mName;
private volatile boolean mHasFinished;
private volatile long mElapsed = -1;
protected abstract long now();
public Timer(String name) {
mName = name;
mStartTime = now();
}
public void cancel() {
mHasFinished = true;
}
public long getElapsed() {
return mElapsed;
}
public void stop() {
// Only the first stop counts.
if (mHasFinished) {
return;
}
mHasFinished = true;
final long elapsed = now() - mStartTime;
if (elapsed < 0) {
Log.e(LOGTAG, "Current time less than start time -- clock shenanigans?");
return;
}
mElapsed = elapsed;
if (elapsed > Integer.MAX_VALUE) {
Log.e(LOGTAG, "Duration of " + elapsed + "ms is too great to add to histogram.");
return;
}
addToHistogram(mName, (int) (elapsed));
}
}
public static class RealtimeTimer extends Timer {
public RealtimeTimer(String name) {
super(name);
}
@Override
protected long now() {
return Telemetry.realtime();
}
}
public static class UptimeTimer extends Timer {
public UptimeTimer(String name) {
super(name);
}
@Override
protected long now() {
return Telemetry.uptime();
}
TelemetryUtils.addToKeyedHistogram(name, key, value);
}
public static void startUISession(final Session session, final String sessionNameSuffix) {
final String sessionName = getSessionName(session, sessionNameSuffix);
Log.d(LOGTAG, "StartUISession: " + sessionName);
if (GeckoThread.isRunning()) {
nativeStartUiSession(sessionName, realtime());
} else {
GeckoThread.queueNativeCall(Telemetry.class, "nativeStartUiSession",
String.class, sessionName, realtime());
}
TelemetryUtils.startUISession(session, sessionNameSuffix);
}
public static void startUISession(final Session session) {
@ -163,16 +44,7 @@ public class Telemetry {
public static void stopUISession(final Session session, final String sessionNameSuffix,
final Reason reason) {
final String sessionName = getSessionName(session, sessionNameSuffix);
Log.d(LOGTAG, "StopUISession: " + sessionName + ", reason=" + reason);
if (GeckoThread.isRunning()) {
nativeStopUiSession(sessionName, reason.toString(), realtime());
} else {
GeckoThread.queueNativeCall(Telemetry.class, "nativeStopUiSession",
String.class, sessionName,
String.class, reason.toString(), realtime());
}
TelemetryUtils.stopUISession(session, sessionNameSuffix, reason);
}
public static void stopUISession(final Session session, final Reason reason) {
@ -187,35 +59,35 @@ public class Telemetry {
stopUISession(session, null, Reason.NONE);
}
private static String getSessionName(final Session session, final String sessionNameSuffix) {
if (sessionNameSuffix != null) {
return session.toString() + ":" + sessionNameSuffix;
} else {
return session.toString();
}
public static void sendUIEvent(final Event event, final Method method, final long timestamp,
final String extras) {
sendUIEvent(event.toString(), method, timestamp, extras);
}
public static void sendUIEvent(final Event event, final Method method, final long timestamp) {
sendUIEvent(event, method, timestamp, null);
}
public static void sendUIEvent(final Event event, final Method method, final String extras) {
sendUIEvent(event, method, TelemetryUtils.realtime(), extras);
}
public static void sendUIEvent(final Event event, final Method method) {
sendUIEvent(event, method, TelemetryUtils.realtime(), null);
}
public static void sendUIEvent(final Event event) {
sendUIEvent(event, Method.NONE, TelemetryUtils.realtime(), null);
}
public static void sendUIEvent(final Event event, final boolean eventStatus) {
final String eventName = event + ":" + eventStatus;
sendUIEvent(eventName, Method.NONE, TelemetryUtils.realtime(), null);
}
/**
* @param method A non-null method (if null is desired, consider using Method.NONE)
*/
private static void sendUIEvent(final String eventName, final Method method,
final long timestamp, final String extras) {
if (method == null) {
throw new IllegalArgumentException("Expected non-null method - use Method.NONE?");
}
if (!AppConstants.RELEASE_OR_BETA) {
final String logString = "SendUIEvent: event = " + eventName + " method = " + method + " timestamp = " +
timestamp + " extras = " + extras;
Log.d(LOGTAG, logString);
}
if (GeckoThread.isRunning()) {
nativeAddUiEvent(eventName, method.toString(), timestamp, extras);
} else {
GeckoThread.queueNativeCall(Telemetry.class, "nativeAddUiEvent",
String.class, eventName, String.class, method.toString(),
timestamp, String.class, extras);
}
TelemetryUtils.sendUIEvent(eventName, method, timestamp, extras);
mappingMmaTracking(eventName, method, extras);
}
@ -235,38 +107,4 @@ public class Telemetry {
MmaDelegate.track(SAVED_LOGIN_AND_PASSWORD);
}
}
public static void sendUIEvent(final Event event, final Method method, final long timestamp,
final String extras) {
sendUIEvent(event.toString(), method, timestamp, extras);
}
public static void sendUIEvent(final Event event, final Method method, final long timestamp) {
sendUIEvent(event, method, timestamp, null);
}
public static void sendUIEvent(final Event event, final Method method, final String extras) {
sendUIEvent(event, method, realtime(), extras);
}
public static void sendUIEvent(final Event event, final Method method) {
sendUIEvent(event, method, realtime(), null);
}
public static void sendUIEvent(final Event event) {
sendUIEvent(event, Method.NONE, realtime(), null);
}
/**
* Sends a UIEvent with the given status appended to the event name.
*
* This method is a slight bend of the Telemetry framework so chances
* are that you don't want to use this: please think really hard before you do.
*
* Intended for use with data policy notifications.
*/
public static void sendUIEvent(final Event event, final boolean eventStatus) {
final String eventName = event + ":" + eventStatus;
sendUIEvent(eventName, Method.NONE, realtime(), null);
}
}

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

@ -5,11 +5,16 @@
ChromeUtils.import("resource://gre/modules/GeckoViewChildModule.jsm");
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
ChromeUtils.import("resource://gre/modules/GeckoViewTelemetry.jsm");
XPCOMUtils.defineLazyModuleGetters(this, {
Services: "resource://gre/modules/Services.jsm",
});
const PAGE_LOAD_PROGRESS_PROBE =
new HistogramStopwatch("GV_PAGE_LOAD_PROGRESS_MS", content);
const PAGE_LOAD_PROBE = new HistogramStopwatch("GV_PAGE_LOAD_MS", content);
class GeckoViewProgressChild extends GeckoViewChildModule {
onInit() {
debug `onInit`;
@ -44,26 +49,35 @@ class GeckoViewProgressChild extends GeckoViewChildModule {
}
const uri = aRequest.QueryInterface(Ci.nsIChannel).URI.displaySpec;
if (aRequest.URI.schemeIs("about")) {
return;
}
debug `onStateChange: uri=${uri}`;
if (aStateFlags & Ci.nsIWebProgressListener.STATE_START) {
PAGE_LOAD_PROBE.start();
ProgressTracker.start(uri);
} else if ((aStateFlags & Ci.nsIWebProgressListener.STATE_STOP) &&
!aWebProgress.isLoadingDocument) {
PAGE_LOAD_PROBE.finish();
ProgressTracker.stop();
} else if (aStateFlags & Ci.nsIWebProgressListener.STATE_REDIRECTING) {
PAGE_LOAD_PROBE.start();
ProgressTracker.start(uri);
}
}
onLocationChange(aWebProgress, aRequest, aLocationURI, aFlags) {
debug `onLocationChange: location=${aLocationURI.displaySpec},
flags=${aFlags}`;
if (!aWebProgress || !aWebProgress.isTopLevel) {
if (!aWebProgress || !aWebProgress.isTopLevel ||
!aLocationURI || aLocationURI.schemeIs("about")) {
return;
}
debug `onLocationChange: location=${aLocationURI.displaySpec},
flags=${aFlags}`;
if (aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_ERROR_PAGE) {
ProgressTracker.stop();
} else {
@ -82,6 +96,7 @@ const ProgressTracker = {
debug `ProgressTracker start ${aUri}`;
if (this._tracking) {
PAGE_LOAD_PROGRESS_PROBE.cancel();
this.stop();
}
@ -101,6 +116,8 @@ const ProgressTracker = {
return;
}
PAGE_LOAD_PROGRESS_PROBE.start();
data.uri = aUri;
data.pageStart = true;
this.updateProgress();
@ -252,6 +269,8 @@ const ProgressTracker = {
return;
}
const now = content.performance.now();
let progress = 0;
if (data.pageStart) {
@ -272,7 +291,7 @@ const ProgressTracker = {
data.totalReceived = 1;
data.totalExpected = 1;
const channelOverdue = content.performance.now() - 300;
const channelOverdue = now - 300;
for (let channel in data.channels) {
if (data.channels[channel].max < 1 &&
@ -296,7 +315,8 @@ const ProgressTracker = {
progress += data.totalReceived / data.totalExpected * a;
}
debug `ProgressTracker onProgressChangeUpdate ${this._debugData()} ${data.totalReceived}/${data.totalExpected} progress=${progress}`;
debug `ProgressTracker updateProgress data=${this._debugData()}
progress=${progress}`;
if (data.prev >= progress) {
return;
@ -308,6 +328,10 @@ const ProgressTracker = {
});
data.prev = progress;
if (progress === 100) {
PAGE_LOAD_PROGRESS_PROBE.finish();
}
},
};

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

@ -10,6 +10,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
E10SUtils: "resource://gre/modules/E10SUtils.jsm",
EventDispatcher: "resource://gre/modules/Messaging.jsm",
GeckoViewUtils: "resource://gre/modules/GeckoViewUtils.jsm",
HistogramStopwatch: "resource://gre/modules/GeckoViewTelemetry.jsm",
Services: "resource://gre/modules/Services.jsm",
});
@ -31,6 +32,11 @@ var ModuleManager = {
},
init(aBrowser, aModules) {
const MODULES_INIT_PROBE =
new HistogramStopwatch("GV_STARTUP_MODULES_MS", aBrowser);
MODULES_INIT_PROBE.start();
const initData = this._initData;
this._browser = aBrowser;
this._settings = initData.settings;
@ -73,6 +79,8 @@ var ModuleManager = {
this._modules.clear();
});
MODULES_INIT_PROBE.finish();
},
get window() {

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

@ -5,6 +5,7 @@
package org.mozilla.gecko;
import org.mozilla.gecko.TelemetryUtils;
import org.mozilla.gecko.annotation.RobocopTarget;
import org.mozilla.gecko.annotation.WrapForJNI;
import org.mozilla.gecko.mozglue.GeckoLoader;
@ -126,6 +127,8 @@ public class GeckoThread extends Thread {
@WrapForJNI
private static int uiThreadId;
private static TelemetryUtils.Timer sInitTimer;
// Main process parameters
public static final int FLAG_DEBUGGING = 1 << 0; // Debugging mode.
public static final int FLAG_PRELOAD_CHILD = 1 << 1; // Preload child during main thread start.
@ -177,6 +180,8 @@ public class GeckoThread extends Thread {
return false;
}
sInitTimer = new TelemetryUtils.UptimeTimer("GV_STARTUP_RUNTIME_MS");
mInitInfo = info;
mInitInfo.extras = (info.extras != null) ? new Bundle(info.extras) : new Bundle(3);
@ -569,6 +574,11 @@ public class GeckoThread extends Thread {
final boolean result = sNativeQueue.checkAndSetState(expectedState, newState);
if (result) {
Log.d(LOGTAG, "State changed to " + newState);
if (sInitTimer != null && isRunning()) {
sInitTimer.stop();
sInitTimer = null;
}
}
return result;
}

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

@ -0,0 +1,247 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* 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/. */
package org.mozilla.gecko;
import org.mozilla.gecko.annotation.WrapForJNI;
import org.mozilla.gecko.TelemetryContract.Event;
import org.mozilla.gecko.TelemetryContract.Method;
import org.mozilla.gecko.TelemetryContract.Reason;
import org.mozilla.gecko.TelemetryContract.Session;
import android.os.SystemClock;
import android.util.Log;
/**
* All telemetry times are relative to one of two clocks:
*
* * Real time since the device was booted, including deep sleep. Use this
* as a substitute for wall clock.
* * Uptime since the device was booted, excluding deep sleep. Use this to
* avoid timing a user activity when their phone is in their pocket!
*
* The majority of methods in this class are defined in terms of real time.
*/
public class TelemetryUtils {
private static final boolean DEBUG = false;
private static final String LOGTAG = "TelemetryUtils";
@WrapForJNI(stubName = "AddHistogram", dispatchTo = "gecko")
private static native void nativeAddHistogram(String name, int value);
@WrapForJNI(stubName = "AddKeyedHistogram", dispatchTo = "gecko")
private static native void nativeAddKeyedHistogram(String name, String key, int value);
public static long uptime() {
return SystemClock.uptimeMillis();
}
public static long realtime() {
return SystemClock.elapsedRealtime();
}
// Define new histograms in:
// toolkit/components/telemetry/Histograms.json
public static void addToHistogram(String name, int value) {
if (GeckoThread.isRunning()) {
nativeAddHistogram(name, value);
} else {
GeckoThread.queueNativeCall(TelemetryUtils.class, "nativeAddHistogram",
String.class, name, value);
}
}
public static void addToKeyedHistogram(String name, String key, int value) {
if (GeckoThread.isRunning()) {
nativeAddKeyedHistogram(name, key, value);
} else {
GeckoThread.queueNativeCall(TelemetryUtils.class, "nativeAddKeyedHistogram",
String.class, name, String.class, key, value);
}
}
public abstract static class Timer {
private final long mStartTime;
private final String mName;
private volatile boolean mHasFinished;
private volatile long mElapsed = -1;
protected abstract long now();
public Timer(String name) {
mName = name;
mStartTime = now();
}
public void cancel() {
mHasFinished = true;
}
public long getElapsed() {
return mElapsed;
}
public void stop() {
// Only the first stop counts.
if (mHasFinished) {
return;
}
mHasFinished = true;
final long elapsed = now() - mStartTime;
if (elapsed < 0) {
Log.e(LOGTAG, "Current time less than start time -- clock shenanigans?");
return;
}
mElapsed = elapsed;
if (elapsed > Integer.MAX_VALUE) {
Log.e(LOGTAG, "Duration of " + elapsed + "ms is too great to add to histogram.");
return;
}
addToHistogram(mName, (int) (elapsed));
}
}
public static class RealtimeTimer extends Timer {
public RealtimeTimer(String name) {
super(name);
}
@Override
protected long now() {
return TelemetryUtils.realtime();
}
}
public static class UptimeTimer extends Timer {
public UptimeTimer(String name) {
super(name);
}
@Override
protected long now() {
return TelemetryUtils.uptime();
}
}
@WrapForJNI(stubName = "StartUISession", dispatchTo = "gecko")
private static native void nativeStartUiSession(String name, long timestamp);
@WrapForJNI(stubName = "StopUISession", dispatchTo = "gecko")
private static native void nativeStopUiSession(String name, String reason, long timestamp);
@WrapForJNI(stubName = "AddUIEvent", dispatchTo = "gecko")
private static native void nativeAddUiEvent(String action, String method,
long timestamp, String extras);
public static void startUISession(final Session session, final String sessionNameSuffix) {
final String sessionName = getSessionName(session, sessionNameSuffix);
Log.d(LOGTAG, "StartUISession: " + sessionName);
if (GeckoThread.isRunning()) {
nativeStartUiSession(sessionName, realtime());
} else {
GeckoThread.queueNativeCall(TelemetryUtils.class, "nativeStartUiSession",
String.class, sessionName, realtime());
}
}
public static void startUISession(final Session session) {
startUISession(session, null);
}
public static void stopUISession(final Session session, final String sessionNameSuffix,
final Reason reason) {
final String sessionName = getSessionName(session, sessionNameSuffix);
Log.d(LOGTAG, "StopUISession: " + sessionName + ", reason=" + reason);
if (GeckoThread.isRunning()) {
nativeStopUiSession(sessionName, reason.toString(), realtime());
} else {
GeckoThread.queueNativeCall(TelemetryUtils.class, "nativeStopUiSession",
String.class, sessionName,
String.class, reason.toString(), realtime());
}
}
public static void stopUISession(final Session session, final Reason reason) {
stopUISession(session, null, reason);
}
public static void stopUISession(final Session session, final String sessionNameSuffix) {
stopUISession(session, sessionNameSuffix, Reason.NONE);
}
public static void stopUISession(final Session session) {
stopUISession(session, null, Reason.NONE);
}
private static String getSessionName(final Session session, final String sessionNameSuffix) {
if (sessionNameSuffix != null) {
return session.toString() + ":" + sessionNameSuffix;
} else {
return session.toString();
}
}
/**
* @param method A non-null method (if null is desired, consider using Method.NONE)
*/
/* package */ static void sendUIEvent(final String eventName, final Method method,
final long timestamp, final String extras) {
if (method == null) {
throw new IllegalArgumentException("Expected non-null method - use Method.NONE?");
}
if (DEBUG) {
final String logString = "SendUIEvent: event = " + eventName + " method = " + method + " timestamp = " +
timestamp + " extras = " + extras;
Log.d(LOGTAG, logString);
}
if (GeckoThread.isRunning()) {
nativeAddUiEvent(eventName, method.toString(), timestamp, extras);
} else {
GeckoThread.queueNativeCall(TelemetryUtils.class, "nativeAddUiEvent",
String.class, eventName, String.class, method.toString(),
timestamp, String.class, extras);
}
}
public static void sendUIEvent(final Event event, final Method method, final long timestamp,
final String extras) {
sendUIEvent(event.toString(), method, timestamp, extras);
}
public static void sendUIEvent(final Event event, final Method method, final long timestamp) {
sendUIEvent(event, method, timestamp, null);
}
public static void sendUIEvent(final Event event, final Method method, final String extras) {
sendUIEvent(event, method, realtime(), extras);
}
public static void sendUIEvent(final Event event, final Method method) {
sendUIEvent(event, method, realtime(), null);
}
public static void sendUIEvent(final Event event) {
sendUIEvent(event, Method.NONE, realtime(), null);
}
/**
* Sends a UIEvent with the given status appended to the event name.
*
* This method is a slight bend of the Telemetry framework so chances
* are that you don't want to use this: please think really hard before you do.
*
* Intended for use with data policy notifications.
*/
public static void sendUIEvent(final Event event, final boolean eventStatus) {
final String eventName = event + ":" + eventStatus;
sendUIEvent(eventName, Method.NONE, realtime(), null);
}
}

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

@ -0,0 +1,37 @@
/* 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 EXPORTED_SYMBOLS = ["HistogramStopwatch"];
// A helper for histogram timer probes.
class HistogramStopwatch {
constructor(aName, aAssociated) {
this._name = aName;
this._obj = aAssociated;
}
isRunning() {
return TelemetryStopwatch.running(this._name, this._obj);
}
start() {
if (this.isRunning()) {
this.cancel();
}
TelemetryStopwatch.start(this._name, this._obj);
}
finish() {
TelemetryStopwatch.finish(this._name, this._obj);
}
cancel() {
TelemetryStopwatch.cancel(this._name, this._obj);
}
timeElapsed() {
return TelemetryStopwatch.timeElapsed(this._name, this._obj, false);
}
}

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

@ -19,6 +19,7 @@ EXTRA_JS_MODULES += [
'GeckoViewRemoteDebugger.jsm',
'GeckoViewSettings.jsm',
'GeckoViewTab.jsm',
'GeckoViewTelemetry.jsm',
'GeckoViewTrackingProtection.jsm',
'GeckoViewUtils.jsm',
'LoadURIDelegate.jsm',

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

@ -14256,5 +14256,57 @@
"releaseChannelCollection": "opt-out",
"alert_emails": ["ttung@mozilla.com"],
"description": "Time (ms) for the QuotaManager to initialize repositories."
},
"GV_PAGE_LOAD_PROGRESS_MS": {
"record_in_processes": ["main", "content"],
"alert_emails": [
"geckoview-team@mozilla.com",
"esawin@mozilla.com"
],
"expires_in_version": "never",
"kind": "exponential",
"high": 100000,
"n_buckets": 100,
"bug_numbers": [1499418],
"description": "GeckoView: The time between page load progress start (0) and completion (100) in ms."
},
"GV_PAGE_LOAD_MS": {
"record_in_processes": ["main", "content"],
"alert_emails": [
"geckoview-team@mozilla.com",
"esawin@mozilla.com"
],
"expires_in_version": "never",
"kind": "exponential",
"high": 100000,
"n_buckets": 100,
"bug_numbers": [1499418],
"description": "GeckoView: Time taken to load a page in ms. This includes all static contents, no dynamic content. Loading of about: pages is not counted."
},
"GV_STARTUP_RUNTIME_MS": {
"record_in_processes": ["main", "content"],
"alert_emails": [
"geckoview-team@mozilla.com",
"esawin@mozilla.com"
],
"expires_in_version": "never",
"kind": "exponential",
"high": 10000,
"n_buckets": 50,
"bug_numbers": [1499418],
"description": "GeckoView: Time taken to initialize GeckoRuntime in ms."
},
"GV_STARTUP_MODULES_MS": {
"record_in_processes": ["main"],
"alert_emails": [
"geckoview-team@mozilla.com",
"esawin@mozilla.com"
],
"expires_in_version": "never",
"kind": "exponential",
"high": 5000,
"n_buckets": 50,
"bug_numbers": [1499418],
"description": "GeckoView: Time taken to initialize all GeckoView modules in ms."
}
}

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

@ -16,7 +16,7 @@ namespace mozilla {
namespace widget {
class Telemetry final
: public java::Telemetry::Natives<Telemetry>
: public java::TelemetryUtils::Natives<Telemetry>
{
Telemetry() = delete;

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

@ -66,10 +66,10 @@
#include "GeckoSystemStateListener.h"
#include "GeckoVRManager.h"
#include "PrefsHelper.h"
#include "fennec/MemoryMonitor.h"
#include "fennec/Telemetry.h"
#include "fennec/ThumbnailHelper.h"
#include "ScreenHelperAndroid.h"
#include "Telemetry.h"
#include "fennec/MemoryMonitor.h"
#include "fennec/ThumbnailHelper.h"
#include "WebExecutorSupport.h"
#ifdef DEBUG_ANDROID_EVENTS
@ -412,6 +412,7 @@ nsAppShell::nsAppShell()
if (jni::IsAvailable()) {
GeckoThreadSupport::Init();
GeckoAppShellSupport::Init();
mozilla::widget::Telemetry::Init();
// Set the corresponding state in GeckoThread.
java::GeckoThread::SetState(java::GeckoThread::State::RUNNING());
@ -433,6 +434,7 @@ nsAppShell::nsAppShell()
mozilla::GeckoScreenOrientation::Init();
mozilla::GeckoSystemStateListener::Init();
mozilla::PrefsHelper::Init();
mozilla::widget::Telemetry::Init();
mozilla::widget::WebExecutorSupport::Init();
nsWindow::InitNatives();
@ -440,7 +442,6 @@ nsAppShell::nsAppShell()
BrowserLocaleManagerSupport::Init();
mozilla::ANRReporter::Init();
mozilla::MemoryMonitor::Init();
mozilla::widget::Telemetry::Init();
mozilla::ThumbnailHelper::Init();
}