Merge autoland to central, a=merge

This commit is contained in:
Wes Kocher 2017-04-03 14:43:05 -07:00
Родитель 381a7b8f8a 8858633e3a
Коммит ad3c125e24
174 изменённых файлов: 26519 добавлений и 2611 удалений

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

@ -71,6 +71,8 @@ browser/extensions/pdfjs/content/web**
browser/extensions/pocket/content/panels/js/tmpl.js
browser/extensions/pocket/content/panels/js/vendor/**
browser/locales/**
# vendor library files in activity-stream
browser/extensions/activity-stream/vendor/**
# imported from chromium
browser/extensions/mortar/**

4
.gitignore поставляемый
Просмотреть файл

@ -100,8 +100,8 @@ testing/mozharness/logs/
testing/mozharness/.coverage
testing/mozharness/nosetests.xml
# Ignore node_modules
tools/lint/eslint/node_modules/
# Ignore ESLint node_modules
node_modules/
# Ignore talos virtualenv and tp5n files.
# The tp5n set is supposed to be decompressed at

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

@ -112,8 +112,8 @@ GPATH
# Ignore tox generated dir
.tox/
# Ignore node_modules
^tools/lint/eslint/node_modules/
# Ignore ESLint node_modules
^node_modules/
# Ignore talos virtualenv and tp5n files.
# The tp5n set is supposed to be decompressed at

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

@ -27,13 +27,14 @@ add_task(function*() {
// Simulate a dumb font backend.
win.FontBuilder._enumerator = {
_list: ["MockedFont1", "MockedFont2", "MockedFont3"],
_defaultFont: null,
EnumerateFonts(lang, type, list) {
return this._list;
},
EnumerateAllFonts() {
return this._list;
},
getDefaultFont() { return null; },
getDefaultFont() { return this._defaultFont; },
getStandardFamilyName(name) { return name; },
};
win.FontBuilder._allFonts = null;
@ -49,6 +50,8 @@ add_task(function*() {
selectLangsField.value = armenian;
is(serifField.value, "", "Font family should not be set.");
let armenianSerifElement = doc.getElementById("font.name.serif.x-armn");
langGroupElement.value = western;
selectLangsField.value = western;
@ -60,7 +63,7 @@ add_task(function*() {
langGroupElement.value = armenian;
selectLangsField.value = armenian;
is(serifField.value, "MockedFont2", "Font family should be set.");
is(serifField.value, "", "Font family should still be empty for indicating using 'default' font.");
langGroupElement.value = western;
selectLangsField.value = western;
@ -72,5 +75,35 @@ add_task(function*() {
selectLangsField.value = armenian;
is(serifField.value, "", "Font family should not be set.");
// Setting default font to "MockedFont3". Then, when serifField.value is
// empty, it should indicate using "MockedFont3" but it shouldn't be saved
// to "MockedFont3" in the pref. It should be resolved at runtime.
win.FontBuilder._enumerator._list = ["MockedFont1", "MockedFont2", "MockedFont3"];
win.FontBuilder._enumerator._defaultFont = "MockedFont3";
langGroupElement.value = armenian;
selectLangsField.value = armenian;
is(serifField.value, "", "Font family should be empty even if there is a default font.");
armenianSerifElement.value = "MockedFont2";
serifField.value = "MockedFont2";
is(serifField.value, "MockedFont2", "Font family should be \"MockedFont2\" for now.");
langGroupElement.value = western;
selectLangsField.value = western;
is(serifField.value, "", "Font family of other language should not be set.");
langGroupElement.value = armenian;
selectLangsField.value = armenian;
is(serifField.value, "MockedFont2", "Font family should not be changed even after switching the language.");
// If MochedFont2 is removed from the system, the value should be treated
// as empty (i.e., 'default' font) after rebuilding the font list.
win.FontBuilder._enumerator._list = ["MockedFont1", "MockedFont3"];
win.FontBuilder._enumerator._allFonts = ["MockedFont1", "MockedFont3"];
serifField.removeAllItems(); // This will cause rebuilding the font list from available fonts.
langGroupElement.value = armenian;
selectLangsField.value = armenian;
is(serifField.value, "", "Font family should become empty due to the font uninstalled.");
gBrowser.removeCurrentTab();
});

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

@ -5,7 +5,6 @@ support-files =
site_data_test.html
[browser_applications_selection.js]
[browser_advanced_siteData.js]
[browser_advanced_update.js]
skip-if = !updater
[browser_basic_rebuild_fonts_test.js]
@ -38,6 +37,8 @@ skip-if = true || !healthreport # Bug 1185403 for the "true"
[browser_sanitizeOnShutdown_prefLocked.js]
[browser_searchsuggestions.js]
[browser_security.js]
[browser_siteData.js]
[browser_siteData2.js]
[browser_subdialogs.js]
support-files =
subdialog.xul

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

@ -27,13 +27,14 @@ add_task(function*() {
// Simulate a dumb font backend.
win.FontBuilder._enumerator = {
_list: ["MockedFont1", "MockedFont2", "MockedFont3"],
_defaultFont: null,
EnumerateFonts(lang, type, list) {
return this._list;
},
EnumerateAllFonts() {
return this._list;
},
getDefaultFont() { return null; },
getDefaultFont() { return this._defaultFont; },
getStandardFamilyName(name) { return name; },
};
win.FontBuilder._allFonts = null;
@ -49,6 +50,8 @@ add_task(function*() {
selectLangsField.value = armenian;
is(serifField.value, "", "Font family should not be set.");
let armenianSerifElement = doc.getElementById("font.name.serif.x-armn");
langGroupElement.value = western;
selectLangsField.value = western;
@ -60,7 +63,7 @@ add_task(function*() {
langGroupElement.value = armenian;
selectLangsField.value = armenian;
is(serifField.value, "MockedFont2", "Font family should be set.");
is(serifField.value, "", "Font family should still be empty for indicating using 'default' font.");
langGroupElement.value = western;
selectLangsField.value = western;
@ -72,5 +75,35 @@ add_task(function*() {
selectLangsField.value = armenian;
is(serifField.value, "", "Font family should not be set.");
// Setting default font to "MockedFont3". Then, when serifField.value is
// empty, it should indicate using "MockedFont3" but it shouldn't be saved
// to "MockedFont3" in the pref. It should be resolved at runtime.
win.FontBuilder._enumerator._list = ["MockedFont1", "MockedFont2", "MockedFont3"];
win.FontBuilder._enumerator._defaultFont = "MockedFont3";
langGroupElement.value = armenian;
selectLangsField.value = armenian;
is(serifField.value, "", "Font family should be empty even if there is a default font.");
armenianSerifElement.value = "MockedFont2";
serifField.value = "MockedFont2";
is(serifField.value, "MockedFont2", "Font family should be \"MockedFont2\" for now.");
langGroupElement.value = western;
selectLangsField.value = western;
is(serifField.value, "", "Font family of other language should not be set.");
langGroupElement.value = armenian;
selectLangsField.value = armenian;
is(serifField.value, "MockedFont2", "Font family should not be changed even after switching the language.");
// If MochedFont2 is removed from the system, the value should be treated
// as empty (i.e., 'default' font) after rebuilding the font list.
win.FontBuilder._enumerator._list = ["MockedFont1", "MockedFont3"];
win.FontBuilder._enumerator._allFonts = ["MockedFont1", "MockedFont3"];
serifField.removeAllItems(); // This will cause rebuilding the font list from available fonts.
langGroupElement.value = armenian;
selectLangsField.value = armenian;
is(serifField.value, "", "Font family should become empty due to the font uninstalled.");
gBrowser.removeCurrentTab();
});

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

@ -110,18 +110,6 @@ const mockSiteDataManager = {
}
};
function addPersistentStoragePerm(origin) {
let uri = NetUtil.newURI(origin);
let principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {});
Services.perms.addFromPrincipal(principal, "persistent-storage", Ci.nsIPermissionManager.ALLOW_ACTION);
}
function removePersistentStoragePerm(origin) {
let uri = NetUtil.newURI(origin);
let principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {});
Services.perms.removeFromPrincipal(principal, "persistent-storage");
}
function getPersistentStoragePermStatus(origin) {
let uri = NetUtil.newURI(origin);
let principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {});
@ -165,59 +153,12 @@ const cacheUsageGetter = {
]),
};
function openSettingsDialog() {
let doc = gBrowser.selectedBrowser.contentDocument;
let settingsBtn = doc.getElementById("siteDataSettings");
let dialogOverlay = doc.getElementById("dialogOverlay");
let dialogLoadPromise = promiseLoadSubDialog("chrome://browser/content/preferences/siteDataSettings.xul");
let dialogInitPromise = TestUtils.topicObserved("sitedata-settings-init", () => true);
let fullyLoadPromise = Promise.all([ dialogLoadPromise, dialogInitPromise ]).then(() => {
is(dialogOverlay.style.visibility, "visible", "The Settings dialog should be visible");
});
settingsBtn.doCommand();
return fullyLoadPromise;
}
function promiseSettingsDialogClose() {
return new Promise(resolve => {
let doc = gBrowser.selectedBrowser.contentDocument;
let dialogOverlay = doc.getElementById("dialogOverlay");
let win = content.gSubDialog._frame.contentWindow;
win.addEventListener("unload", function unload() {
if (win.document.documentURI === "chrome://browser/content/preferences/siteDataSettings.xul") {
isnot(dialogOverlay.style.visibility, "visible", "The Settings dialog should be hidden");
resolve();
}
}, { once: true });
});
}
function promiseSitesUpdated() {
return TestUtils.topicObserved("sitedatamanager:sites-updated", () => true);
}
function promiseCookiesCleared() {
return TestUtils.topicObserved("cookie-changed", (subj, data) => {
return data === "cleared";
});
}
function assertSitesListed(doc, origins) {
let frameDoc = doc.getElementById("dialogFrame").contentDocument;
let removeBtn = frameDoc.getElementById("removeSelected");
let removeAllBtn = frameDoc.getElementById("removeAll");
let sitesList = frameDoc.getElementById("sitesList");
let totalSitesNumber = sitesList.getElementsByTagName("richlistitem").length;
is(totalSitesNumber, origins.length, "Should list the right sites number");
origins.forEach(origin => {
let site = sitesList.querySelector(`richlistitem[data-origin="${origin}"]`);
let host = site.getAttribute("host");
ok(origin.includes(host), `Should list the site of ${origin}`);
});
is(removeBtn.disabled, false, "Should enable the removeSelected button");
is(removeAllBtn.disabled, false, "Should enable the removeAllBtn button");
}
registerCleanupFunction(function() {
delete window.sinon;
delete window.setImmediate;
@ -266,7 +207,7 @@ add_task(function* () {
// Test accepting "Clear All Data"
// Click "Clear All Data" button and then accept
let acceptPromise = promiseAlertDialogOpen("accept");
let updatePromise = promiseSitesUpdated();
let updatePromise = promiseSiteDataManagerSitesUpdated();
let cookiesClearedPromise = promiseCookiesCleared();
mockOfflineAppCacheHelper.register();
@ -298,10 +239,10 @@ add_task(function* () {
yield SpecialPowers.pushPrefEnv({set: [["browser.storageManager.enabled", true]]});
mockSiteDataManager.register();
let updatePromise = promiseSitesUpdated();
let updatePromise = promiseSiteDataManagerSitesUpdated();
yield openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true });
yield updatePromise;
yield openSettingsDialog();
yield openSiteDataSettingsDialog();
let doc = gBrowser.selectedBrowser.contentDocument;
let dialogFrame = doc.getElementById("dialogFrame");
@ -389,10 +330,10 @@ add_task(function* () {
yield SpecialPowers.pushPrefEnv({set: [["browser.storageManager.enabled", true]]});
mockSiteDataManager.register();
let updatePromise = promiseSitesUpdated();
let updatePromise = promiseSiteDataManagerSitesUpdated();
yield openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true });
yield updatePromise;
yield openSettingsDialog();
yield openSiteDataSettingsDialog();
let doc = gBrowser.selectedBrowser.contentDocument;
let frameDoc = doc.getElementById("dialogFrame").contentDocument;
@ -414,236 +355,3 @@ add_task(function* () {
mockSiteDataManager.unregister();
yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
});
// Test selecting and removing all sites one by one
add_task(function* () {
yield SpecialPowers.pushPrefEnv({set: [["browser.storageManager.enabled", true]]});
let fakeOrigins = [
"https://news.foo.com/",
"https://mails.bar.com/",
"https://videos.xyz.com/",
"https://books.foo.com/",
"https://account.bar.com/",
"https://shopping.xyz.com/"
];
fakeOrigins.forEach(origin => addPersistentStoragePerm(origin));
let updatePromise = promiseSitesUpdated();
yield openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true });
yield updatePromise;
yield openSettingsDialog();
let doc = gBrowser.selectedBrowser.contentDocument;
let frameDoc = null;
let saveBtn = null;
let cancelBtn = null;
let settingsDialogClosePromise = null;
// Test the initial state
assertAllSitesListed();
// Test the "Cancel" button
settingsDialogClosePromise = promiseSettingsDialogClose();
frameDoc = doc.getElementById("dialogFrame").contentDocument;
cancelBtn = frameDoc.getElementById("cancel");
removeAllSitesOneByOne();
assertAllSitesNotListed();
cancelBtn.doCommand();
yield settingsDialogClosePromise;
yield openSettingsDialog();
assertAllSitesListed();
// Test the "Save Changes" button but cancelling save
let cancelPromise = promiseAlertDialogOpen("cancel");
settingsDialogClosePromise = promiseSettingsDialogClose();
frameDoc = doc.getElementById("dialogFrame").contentDocument;
saveBtn = frameDoc.getElementById("save");
removeAllSitesOneByOne();
assertAllSitesNotListed();
saveBtn.doCommand();
yield cancelPromise;
yield settingsDialogClosePromise;
yield openSettingsDialog();
assertAllSitesListed();
// Test the "Save Changes" button and accepting save
let acceptPromise = promiseAlertDialogOpen("accept");
settingsDialogClosePromise = promiseSettingsDialogClose();
updatePromise = promiseSitesUpdated();
frameDoc = doc.getElementById("dialogFrame").contentDocument;
saveBtn = frameDoc.getElementById("save");
removeAllSitesOneByOne();
assertAllSitesNotListed();
saveBtn.doCommand();
yield acceptPromise;
yield settingsDialogClosePromise;
yield updatePromise;
yield openSettingsDialog();
assertAllSitesNotListed();
// Always clean up the fake origins
fakeOrigins.forEach(origin => removePersistentStoragePerm(origin));
yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
function removeAllSitesOneByOne() {
frameDoc = doc.getElementById("dialogFrame").contentDocument;
let removeBtn = frameDoc.getElementById("removeSelected");
let sitesList = frameDoc.getElementById("sitesList");
let sites = sitesList.getElementsByTagName("richlistitem");
for (let i = sites.length - 1; i >= 0; --i) {
sites[i].click();
removeBtn.doCommand();
}
}
function assertAllSitesListed() {
frameDoc = doc.getElementById("dialogFrame").contentDocument;
let removeBtn = frameDoc.getElementById("removeSelected");
let removeAllBtn = frameDoc.getElementById("removeAll");
let sitesList = frameDoc.getElementById("sitesList");
let sites = sitesList.getElementsByTagName("richlistitem");
is(sites.length, fakeOrigins.length, "Should list all sites");
is(removeBtn.disabled, false, "Should enable the removeSelected button");
is(removeAllBtn.disabled, false, "Should enable the removeAllBtn button");
}
function assertAllSitesNotListed() {
frameDoc = doc.getElementById("dialogFrame").contentDocument;
let removeBtn = frameDoc.getElementById("removeSelected");
let removeAllBtn = frameDoc.getElementById("removeAll");
let sitesList = frameDoc.getElementById("sitesList");
let sites = sitesList.getElementsByTagName("richlistitem");
is(sites.length, 0, "Should not list all sites");
is(removeBtn.disabled, true, "Should disable the removeSelected button");
is(removeAllBtn.disabled, true, "Should disable the removeAllBtn button");
}
});
// Test selecting and removing partial sites
add_task(function* () {
yield SpecialPowers.pushPrefEnv({set: [["browser.storageManager.enabled", true]]});
let fakeOrigins = [
"https://news.foo.com/",
"https://mails.bar.com/",
"https://videos.xyz.com/",
"https://books.foo.com/",
"https://account.bar.com/",
"https://shopping.xyz.com/"
];
fakeOrigins.forEach(origin => addPersistentStoragePerm(origin));
let updatePromise = promiseSitesUpdated();
yield openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true });
yield updatePromise;
yield openSettingsDialog();
let doc = gBrowser.selectedBrowser.contentDocument;
let frameDoc = null;
let saveBtn = null;
let cancelBtn = null;
let removeDialogOpenPromise = null;
let settingsDialogClosePromise = null;
// Test the initial state
assertSitesListed(doc, fakeOrigins);
// Test the "Cancel" button
settingsDialogClosePromise = promiseSettingsDialogClose();
frameDoc = doc.getElementById("dialogFrame").contentDocument;
cancelBtn = frameDoc.getElementById("cancel");
removeSelectedSite(fakeOrigins.slice(0, 4));
assertSitesListed(doc, fakeOrigins.slice(4));
cancelBtn.doCommand();
yield settingsDialogClosePromise;
yield openSettingsDialog();
assertSitesListed(doc, fakeOrigins);
// Test the "Save Changes" button but canceling save
removeDialogOpenPromise = promiseWindowDialogOpen("cancel", REMOVE_DIALOG_URL);
settingsDialogClosePromise = promiseSettingsDialogClose();
frameDoc = doc.getElementById("dialogFrame").contentDocument;
saveBtn = frameDoc.getElementById("save");
removeSelectedSite(fakeOrigins.slice(0, 4));
assertSitesListed(doc, fakeOrigins.slice(4));
saveBtn.doCommand();
yield removeDialogOpenPromise;
yield settingsDialogClosePromise;
yield openSettingsDialog();
assertSitesListed(doc, fakeOrigins);
// Test the "Save Changes" button and accepting save
removeDialogOpenPromise = promiseWindowDialogOpen("accept", REMOVE_DIALOG_URL);
settingsDialogClosePromise = promiseSettingsDialogClose();
frameDoc = doc.getElementById("dialogFrame").contentDocument;
saveBtn = frameDoc.getElementById("save");
removeSelectedSite(fakeOrigins.slice(0, 4));
assertSitesListed(doc, fakeOrigins.slice(4));
saveBtn.doCommand();
yield removeDialogOpenPromise;
yield settingsDialogClosePromise;
yield openSettingsDialog();
assertSitesListed(doc, fakeOrigins.slice(4));
// Always clean up the fake origins
fakeOrigins.forEach(origin => removePersistentStoragePerm(origin));
yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
function removeSelectedSite(origins) {
frameDoc = doc.getElementById("dialogFrame").contentDocument;
let removeBtn = frameDoc.getElementById("removeSelected");
let sitesList = frameDoc.getElementById("sitesList");
origins.forEach(origin => {
let site = sitesList.querySelector(`richlistitem[data-origin="${origin}"]`);
if (site) {
site.click();
removeBtn.doCommand();
} else {
ok(false, `Should not select and remove inexisted site of ${origin}`);
}
});
}
});
add_task(function* () {
yield SpecialPowers.pushPrefEnv({set: [["browser.storageManager.enabled", true]]});
let fakeOrigins = [
"https://news.foo.com/",
"https://books.foo.com/",
"https://mails.bar.com/",
"https://account.bar.com/",
"https://videos.xyz.com/",
"https://shopping.xyz.com/"
];
fakeOrigins.forEach(origin => addPersistentStoragePerm(origin));
let updatePromise = promiseSitesUpdated();
yield openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true });
yield updatePromise;
yield openSettingsDialog();
// Search "foo" to only list foo.com sites
let doc = gBrowser.selectedBrowser.contentDocument;
let frameDoc = doc.getElementById("dialogFrame").contentDocument;
let searchBox = frameDoc.getElementById("searchBox");
searchBox.value = "foo";
searchBox.doCommand();
assertSitesListed(doc, fakeOrigins.slice(0, 2));
// Test only removing all visible sites listed
updatePromise = promiseSitesUpdated();
let acceptRemovePromise = promiseWindowDialogOpen("accept", REMOVE_DIALOG_URL);
let settingsDialogClosePromise = promiseSettingsDialogClose();
let removeAllBtn = frameDoc.getElementById("removeAll");
let saveBtn = frameDoc.getElementById("save");
removeAllBtn.doCommand();
saveBtn.doCommand();
yield acceptRemovePromise;
yield settingsDialogClosePromise;
yield updatePromise;
yield openSettingsDialog();
assertSitesListed(doc, fakeOrigins.slice(2));
// Always clean up the fake origins
fakeOrigins.forEach(origin => removePersistentStoragePerm(origin));
yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
});

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

@ -0,0 +1,256 @@
"use strict";
const REMOVE_DIALOG_URL = "chrome://browser/content/preferences/siteDataRemoveSelected.xul";
// Test selecting and removing all sites one by one
add_task(function* () {
yield SpecialPowers.pushPrefEnv({set: [["browser.storageManager.enabled", true]]});
let fakeOrigins = [
"https://news.foo.com/",
"https://mails.bar.com/",
"https://videos.xyz.com/",
"https://books.foo.com/",
"https://account.bar.com/",
"https://shopping.xyz.com/"
];
fakeOrigins.forEach(origin => addPersistentStoragePerm(origin));
let updatePromise = promiseSiteDataManagerSitesUpdated();
yield openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true });
yield updatePromise;
yield openSiteDataSettingsDialog();
let doc = gBrowser.selectedBrowser.contentDocument;
let frameDoc = null;
let saveBtn = null;
let cancelBtn = null;
let settingsDialogClosePromise = null;
// Test the initial state
assertAllSitesListed();
// Test the "Cancel" button
settingsDialogClosePromise = promiseSettingsDialogClose();
frameDoc = doc.getElementById("dialogFrame").contentDocument;
cancelBtn = frameDoc.getElementById("cancel");
removeAllSitesOneByOne();
assertAllSitesNotListed();
cancelBtn.doCommand();
yield settingsDialogClosePromise;
yield openSiteDataSettingsDialog();
assertAllSitesListed();
// Test the "Save Changes" button but cancelling save
let cancelPromise = promiseAlertDialogOpen("cancel");
settingsDialogClosePromise = promiseSettingsDialogClose();
frameDoc = doc.getElementById("dialogFrame").contentDocument;
saveBtn = frameDoc.getElementById("save");
removeAllSitesOneByOne();
assertAllSitesNotListed();
saveBtn.doCommand();
yield cancelPromise;
yield settingsDialogClosePromise;
yield openSiteDataSettingsDialog();
assertAllSitesListed();
// Test the "Save Changes" button and accepting save
let acceptPromise = promiseAlertDialogOpen("accept");
settingsDialogClosePromise = promiseSettingsDialogClose();
updatePromise = promiseSiteDataManagerSitesUpdated();
frameDoc = doc.getElementById("dialogFrame").contentDocument;
saveBtn = frameDoc.getElementById("save");
removeAllSitesOneByOne();
assertAllSitesNotListed();
saveBtn.doCommand();
yield acceptPromise;
yield settingsDialogClosePromise;
yield updatePromise;
yield openSiteDataSettingsDialog();
assertAllSitesNotListed();
// Always clean up the fake origins
fakeOrigins.forEach(origin => removePersistentStoragePerm(origin));
yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
function removeAllSitesOneByOne() {
frameDoc = doc.getElementById("dialogFrame").contentDocument;
let removeBtn = frameDoc.getElementById("removeSelected");
let sitesList = frameDoc.getElementById("sitesList");
let sites = sitesList.getElementsByTagName("richlistitem");
for (let i = sites.length - 1; i >= 0; --i) {
sites[i].click();
removeBtn.doCommand();
}
}
function assertAllSitesListed() {
frameDoc = doc.getElementById("dialogFrame").contentDocument;
let removeBtn = frameDoc.getElementById("removeSelected");
let removeAllBtn = frameDoc.getElementById("removeAll");
let sitesList = frameDoc.getElementById("sitesList");
let sites = sitesList.getElementsByTagName("richlistitem");
is(sites.length, fakeOrigins.length, "Should list all sites");
is(removeBtn.disabled, false, "Should enable the removeSelected button");
is(removeAllBtn.disabled, false, "Should enable the removeAllBtn button");
}
function assertAllSitesNotListed() {
frameDoc = doc.getElementById("dialogFrame").contentDocument;
let removeBtn = frameDoc.getElementById("removeSelected");
let removeAllBtn = frameDoc.getElementById("removeAll");
let sitesList = frameDoc.getElementById("sitesList");
let sites = sitesList.getElementsByTagName("richlistitem");
is(sites.length, 0, "Should not list all sites");
is(removeBtn.disabled, true, "Should disable the removeSelected button");
is(removeAllBtn.disabled, true, "Should disable the removeAllBtn button");
}
});
// Test selecting and removing partial sites
add_task(function* () {
yield SpecialPowers.pushPrefEnv({set: [["browser.storageManager.enabled", true]]});
let fakeOrigins = [
"https://news.foo.com/",
"https://mails.bar.com/",
"https://videos.xyz.com/",
"https://books.foo.com/",
"https://account.bar.com/",
"https://shopping.xyz.com/"
];
fakeOrigins.forEach(origin => addPersistentStoragePerm(origin));
let updatePromise = promiseSiteDataManagerSitesUpdated();
yield openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true });
yield updatePromise;
yield openSiteDataSettingsDialog();
let doc = gBrowser.selectedBrowser.contentDocument;
let frameDoc = null;
let saveBtn = null;
let cancelBtn = null;
let removeDialogOpenPromise = null;
let settingsDialogClosePromise = null;
// Test the initial state
assertSitesListed(doc, fakeOrigins);
// Test the "Cancel" button
settingsDialogClosePromise = promiseSettingsDialogClose();
frameDoc = doc.getElementById("dialogFrame").contentDocument;
cancelBtn = frameDoc.getElementById("cancel");
removeSelectedSite(fakeOrigins.slice(0, 4));
assertSitesListed(doc, fakeOrigins.slice(4));
cancelBtn.doCommand();
yield settingsDialogClosePromise;
yield openSiteDataSettingsDialog();
assertSitesListed(doc, fakeOrigins);
// Test the "Save Changes" button but canceling save
removeDialogOpenPromise = promiseWindowDialogOpen("cancel", REMOVE_DIALOG_URL);
settingsDialogClosePromise = promiseSettingsDialogClose();
frameDoc = doc.getElementById("dialogFrame").contentDocument;
saveBtn = frameDoc.getElementById("save");
removeSelectedSite(fakeOrigins.slice(0, 4));
assertSitesListed(doc, fakeOrigins.slice(4));
saveBtn.doCommand();
yield removeDialogOpenPromise;
yield settingsDialogClosePromise;
yield openSiteDataSettingsDialog();
assertSitesListed(doc, fakeOrigins);
// Test the "Save Changes" button and accepting save
removeDialogOpenPromise = promiseWindowDialogOpen("accept", REMOVE_DIALOG_URL);
settingsDialogClosePromise = promiseSettingsDialogClose();
frameDoc = doc.getElementById("dialogFrame").contentDocument;
saveBtn = frameDoc.getElementById("save");
removeSelectedSite(fakeOrigins.slice(0, 4));
assertSitesListed(doc, fakeOrigins.slice(4));
saveBtn.doCommand();
yield removeDialogOpenPromise;
yield settingsDialogClosePromise;
yield openSiteDataSettingsDialog();
assertSitesListed(doc, fakeOrigins.slice(4));
// Always clean up the fake origins
fakeOrigins.forEach(origin => removePersistentStoragePerm(origin));
yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
function removeSelectedSite(origins) {
frameDoc = doc.getElementById("dialogFrame").contentDocument;
let removeBtn = frameDoc.getElementById("removeSelected");
let sitesList = frameDoc.getElementById("sitesList");
origins.forEach(origin => {
let site = sitesList.querySelector(`richlistitem[data-origin="${origin}"]`);
if (site) {
site.click();
removeBtn.doCommand();
} else {
ok(false, `Should not select and remove inexisted site of ${origin}`);
}
});
}
});
add_task(function* () {
yield SpecialPowers.pushPrefEnv({set: [["browser.storageManager.enabled", true]]});
let fakeOrigins = [
"https://news.foo.com/",
"https://books.foo.com/",
"https://mails.bar.com/",
"https://account.bar.com/",
"https://videos.xyz.com/",
"https://shopping.xyz.com/"
];
fakeOrigins.forEach(origin => addPersistentStoragePerm(origin));
let updatePromise = promiseSiteDataManagerSitesUpdated();
yield openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true });
yield updatePromise;
yield openSiteDataSettingsDialog();
// Search "foo" to only list foo.com sites
let doc = gBrowser.selectedBrowser.contentDocument;
let frameDoc = doc.getElementById("dialogFrame").contentDocument;
let searchBox = frameDoc.getElementById("searchBox");
searchBox.value = "foo";
searchBox.doCommand();
assertSitesListed(doc, fakeOrigins.slice(0, 2));
// Test only removing all visible sites listed
updatePromise = promiseSiteDataManagerSitesUpdated();
let acceptRemovePromise = promiseWindowDialogOpen("accept", REMOVE_DIALOG_URL);
let settingsDialogClosePromise = promiseSettingsDialogClose();
let removeAllBtn = frameDoc.getElementById("removeAll");
let saveBtn = frameDoc.getElementById("save");
removeAllBtn.doCommand();
saveBtn.doCommand();
yield acceptRemovePromise;
yield settingsDialogClosePromise;
yield updatePromise;
yield openSiteDataSettingsDialog();
assertSitesListed(doc, fakeOrigins.slice(2));
// Always clean up the fake origins
fakeOrigins.forEach(origin => removePersistentStoragePerm(origin));
yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
});
function promiseSettingsDialogClose() {
return new Promise(resolve => {
let doc = gBrowser.selectedBrowser.contentDocument;
let dialogOverlay = doc.getElementById("dialogOverlay");
let win = content.gSubDialog._frame.contentWindow;
win.addEventListener("unload", function unload() {
if (win.document.documentURI === "chrome://browser/content/preferences/siteDataSettings.xul") {
isnot(dialogOverlay.style.visibility, "visible", "The Settings dialog should be hidden");
resolve();
}
}, { once: true });
});
}
function removePersistentStoragePerm(origin) {
let uri = NetUtil.newURI(origin);
let principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {});
Services.perms.removeFromPrincipal(principal, "persistent-storage");
}

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

@ -179,3 +179,42 @@ function promiseWindowDialogOpen(buttonAction, url) {
function promiseAlertDialogOpen(buttonAction) {
return promiseWindowDialogOpen(buttonAction, "chrome://global/content/commonDialog.xul");
}
function addPersistentStoragePerm(origin) {
let uri = NetUtil.newURI(origin);
let principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {});
Services.perms.addFromPrincipal(principal, "persistent-storage", Ci.nsIPermissionManager.ALLOW_ACTION);
}
function promiseSiteDataManagerSitesUpdated() {
return TestUtils.topicObserved("sitedatamanager:sites-updated", () => true);
}
function openSiteDataSettingsDialog() {
let doc = gBrowser.selectedBrowser.contentDocument;
let settingsBtn = doc.getElementById("siteDataSettings");
let dialogOverlay = doc.getElementById("dialogOverlay");
let dialogLoadPromise = promiseLoadSubDialog("chrome://browser/content/preferences/siteDataSettings.xul");
let dialogInitPromise = TestUtils.topicObserved("sitedata-settings-init", () => true);
let fullyLoadPromise = Promise.all([ dialogLoadPromise, dialogInitPromise ]).then(() => {
is(dialogOverlay.style.visibility, "visible", "The Settings dialog should be visible");
});
settingsBtn.doCommand();
return fullyLoadPromise;
}
function assertSitesListed(doc, origins) {
let frameDoc = doc.getElementById("dialogFrame").contentDocument;
let removeBtn = frameDoc.getElementById("removeSelected");
let removeAllBtn = frameDoc.getElementById("removeAll");
let sitesList = frameDoc.getElementById("sitesList");
let totalSitesNumber = sitesList.getElementsByTagName("richlistitem").length;
is(totalSitesNumber, origins.length, "Should list the right sites number");
origins.forEach(origin => {
let site = sitesList.querySelector(`richlistitem[data-origin="${origin}"]`);
let host = site.getAttribute("host");
ok(origin.includes(host), `Should list the site of ${origin}`);
});
is(removeBtn.disabled, false, "Should enable the removeSelected button");
is(removeAllBtn.disabled, false, "Should enable the removeAllBtn button");
}

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

@ -33,10 +33,10 @@
"size": 1020700
},
{
"version": "https://github.com/andreas56/libdmg-hfsplus rev 81dd75fd1549b24bf8af9736ac25518b367e6b63",
"size": 62032,
"version": "https://github.com/mozilla/libdmg-hfsplus rev ba04b00435a0853f1499d751617177828ee8ec00",
"size": 57060,
"visibility": "public",
"digest": "9073c41034784eb8823ec817aed42bbc65c8da63ad3fac572726fa48b36320ee302ca8f51b23576e7fdbeec6ab300610d0c58bbd9c52024577dfdb13d95aa2ec",
"digest": "0c96f0d3ace71c4110abec6f7ead013600b0a73c89465d840276090d849279e555d977fb2aa6bbabb7891d7191fc8cc8a4e8242be888114be52346b77a512fcc",
"algorithm": "sha512",
"unpack": true,
"filename": "dmg.tar.xz"

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

@ -0,0 +1,8 @@
# activity-stream
This system add-on replaces the new tab page in Firefox with a new design and
functionality as part of the Activity Stream project. It can be enabled (or disabled)
via the browser.newtabpage.activity-stream.enabled pref.
The files in this directory, including vendor dependencies, are imported from the
system-addon directory in https://github.com/mozilla/activity-stream.

21
browser/extensions/activity-stream/vendor/REACT_REDUX_LICENSE поставляемый Normal file
Просмотреть файл

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2015-present Dan Abramov
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

21
browser/extensions/activity-stream/vendor/REDUX_LICENSE поставляемый Normal file
Просмотреть файл

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2015-present Dan Abramov
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

1320
browser/extensions/activity-stream/vendor/Redux.jsm поставляемый Normal file

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

3757
browser/extensions/activity-stream/vendor/react-dev.js поставляемый Normal file

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

18265
browser/extensions/activity-stream/vendor/react-dom-dev.js поставляемый Normal file

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

15
browser/extensions/activity-stream/vendor/react-dom.js поставляемый Normal file

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

4
browser/extensions/activity-stream/vendor/react-redux.js поставляемый Normal file

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

12
browser/extensions/activity-stream/vendor/react.js поставляемый Normal file

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

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

@ -77,7 +77,6 @@ module.exports = envConfig => {
"method": path.join(__dirname, "../../../addon-sdk/source/lib/method"),
"modules/libpref/init/all":
path.join(__dirname, "../../../modules/libpref/init/all.js"),
"sdk/system/unload": path.join(__dirname, "./webpack/system-unload-sham.js"),
"sdk": path.join(__dirname, "../../../addon-sdk/source/lib/sdk"),
"Services": path.join(__dirname, "../shared/shim/Services.js"),
"toolkit/locales":

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

@ -38,7 +38,7 @@ define(function (require, exports, module) {
let data = this.props.data;
return (
div({className: "headersPanelBox"},
div({className: "headersPanelBox tab-panel-inner"},
HeadersToolbar({actions: this.props.actions}),
div({className: "panelContent"},
Headers({data: data})

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

@ -144,7 +144,7 @@ define(function (require, exports, module) {
}
return (
div({className: "jsonPanelBox"},
div({className: "jsonPanelBox tab-panel-inner"},
JsonToolbar({actions: this.props.actions}),
div({className: "panelContent"},
content

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

@ -32,7 +32,7 @@ define(function (require, exports, module) {
render: function () {
return (
div({className: "textPanelBox"},
div({className: "textPanelBox tab-panel-inner"},
TextToolbar({actions: this.props.actions}),
div({className: "panelContent"},
pre({className: "data"},

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

@ -17,10 +17,17 @@
/******************************************************************************/
/* Panel Content */
.tab-panel-inner {
display: flex;
flex-direction: column;
height: 100%;
}
.panelContent {
direction: ltr;
overflow-y: auto;
width: 100%;
flex: 1;
}
/* The tree takes the entire horizontal space within the panel content. */
@ -41,20 +48,9 @@
/******************************************************************************/
/* Theme Firebug */
.theme-firebug .panelContent {
height: calc(100% - 30px);
}
/* JSON View is using bigger font-size for the main tabs so,
let's overwrite the default value. */
.theme-firebug .tabs .tabs-navigation {
font-size: 14px;
}
/******************************************************************************/
/* Theme Light & Theme Dark*/
.theme-dark .panelContent,
.theme-light .panelContent {
height: calc(100% - 27px);
}

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

@ -453,6 +453,10 @@ netmonitor.tab.response=Response
# in the network details pane identifying the timings tab.
netmonitor.tab.timings=Timings
# LOCALIZATION NOTE (netmonitor.tab.stackTrace): This is the label displayed
# in the network details pane identifying the stack-trace tab.
netmonitor.tab.stackTrace=Stack Trace
# LOCALIZATION NOTE (netmonitor.tab.preview): This is the label displayed
# in the network details pane identifying the preview tab.
netmonitor.tab.preview=Preview

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

@ -6,37 +6,7 @@
@import "resource://devtools/client/shared/components/tree/tree-view.css";
@import "resource://devtools/client/shared/components/tabs/tabs.css";
@import "resource://devtools/client/shared/components/tabs/tabbar.css";
* {
box-sizing: border-box;
}
.toolbar-labels {
overflow: hidden;
display: flex;
flex: auto;
}
.devtools-toolbar-container {
display: flex;
justify-content: space-between;
}
.devtools-toolbar-group {
display: flex;
flex: 0 0 auto;
flex-wrap: nowrap;
align-items: center;
}
#response-content-image-box {
overflow: auto;
}
.cropped-textbox .textbox-input {
/* workaround for textbox not supporting the @crop attribute */
text-overflow: ellipsis;
}
@import "chrome://devtools/skin/components-frame.css";
:root.theme-dark {
--table-splitter-color: rgba(255,255,255,0.15);
@ -69,31 +39,104 @@
}
:root.theme-firebug {
--table-splitter-color: rgba(0,0,0,0.15);
--table-zebra-background: rgba(0,0,0,0.05);
--timing-blocked-color: rgba(235, 83, 104, 0.8); /* red */
--timing-dns-color: rgba(223, 128, 255, 0.8); /* pink */
--timing-connect-color: rgba(217, 102, 41, 0.8); /* orange */
--timing-send-color: rgba(70, 175, 227, 0.8); /* light blue */
--timing-wait-color: rgba(94, 136, 176, 0.8); /* blue grey */
--timing-receive-color: rgba(112, 191, 83, 0.8); /* green */
--sort-ascending-image: url(chrome://devtools/skin/images/firebug/arrow-up.svg);
--sort-descending-image: url(chrome://devtools/skin/images/firebug/arrow-down.svg);
}
/* General */
html,
body,
.root,
#mount,
.network-monitor,
.monitor-panel {
display: flex;
flex-direction: column;
height: 100%;
overflow: hidden;
}
* {
box-sizing: border-box;
}
.split-box {
overflow: hidden;
}
.toolbar-labels {
overflow: hidden;
display: flex;
flex: auto;
}
.devtools-toolbar {
display: flex;
}
.devtools-toolbar-container {
justify-content: space-between;
}
.devtools-toolbar-group {
display: flex;
flex: 0 0 auto;
flex-wrap: nowrap;
align-items: center;
}
#response-content-image-box {
overflow: auto;
}
.cropped-textbox .textbox-input {
/* workaround for textbox not supporting the @crop attribute */
text-overflow: ellipsis;
}
/* Status bar */
.status-bar-label {
display: inline-flex;
align-content: stretch;
margin-inline-end: 10px;
}
.status-bar-label::before {
content: "";
display: inline-block;
margin-inline-end: 10px;
margin-top: 4px;
margin-bottom: 4px;
width: 1px;
background: var(--theme-splitter-color);
}
.status-bar-label.dom-content-loaded {
color: blue;
}
.status-bar-label.load {
color: red;
}
/* Request list */
.request-list-container {
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
overflow: hidden;
}
.request-list-empty-notice {
margin: 0;
padding: 12px;
font-size: 120%;
flex: 1;
overflow: auto;
}
.notice-perf-message {
@ -138,6 +181,7 @@
flex-direction: column;
overflow-x: hidden;
overflow-y: auto;
flex: 1;
--timings-scale: 1;
--timings-rev-scale: 1;
}
@ -157,6 +201,8 @@
text-overflow: ellipsis;
}
/* Requests list header */
.requests-list-header {
display: flex;
flex: none;
@ -642,8 +688,147 @@
/* Network request details tabpanels */
.theme-firebug .variables-view-scope:focus > .title {
color: var(--theme-body-color);
.network-details-panel {
width: 100%;
height: 100%;
overflow: hidden;
}
.panel-container {
height: 100%;
}
.panel-container,
.properties-view {
display: flex;
flex-direction: column;
overflow: auto;
}
.properties-view {
flex-grow: 1;
}
.properties-view .searchbox-section {
flex: 0 1 auto;
}
.properties-view .devtools-searchbox {
padding: 0;
}
.properties-view .devtools-searchbox input {
margin: 1px 3px;
}
/* Empty notices in tab panels */
.empty-notice {
color: var(--theme-body-color-alt);
padding: 3px 8px;
}
/* Text inputs in tab panels */
.textbox-input {
text-overflow: ellipsis;
border: none;
background: none;
color: inherit;
width: 100%;
}
.textbox-input:focus {
outline: 0;
box-shadow: var(--theme-focus-box-shadow-textbox);
}
/* Tree table in tab panels */
.tree-container, .tree-container .treeTable {
position: relative;
height: 100%;
width: 100%;
overflow: auto;
flex: 1;
}
.tree-container .treeTable,
.tree-container .treeTable tbody {
display: flex;
flex-direction: column;
}
.tree-container .treeTable tbody {
/* Apply flex to table will create an anonymous table element outside of tbody
* See also http://stackoverflow.com/a/30851678
* Therefore, we set height with this magic number in order to remove the
* redundant scrollbar when source editor appears.
*/
height: calc(100% - 4px);
}
.tree-container .treeTable tr {
display: block;
}
/* Make right td fill available horizontal space */
.tree-container .treeTable td:last-child {
width: 100%;
}
.properties-view .devtools-searchbox,
.tree-container .treeTable .tree-section {
width: 100%;
background-color: var(--theme-toolbar-background);
}
.tree-container .treeTable tr.tree-section:not(:first-child) td:not([class=""]) {
border-top: 1px solid var(--theme-splitter-color);
}
.properties-view .devtools-searchbox,
.tree-container .treeTable tr.tree-section:not(:last-child) td:not([class=""]) {
border-bottom: 1px solid var(--theme-splitter-color);
}
.tree-container .treeTable .tree-section > * {
vertical-align: middle;
}
.tree-container .treeTable .treeRow.tree-section > .treeLabelCell > .treeLabel,
.tree-container .treeTable .treeRow.tree-section > .treeLabelCell > .treeLabel:hover {
color: var(--theme-body-color-alt);
}
.tree-container .treeTable .treeValueCell {
/* FIXME: Make value cell can be reduced to shorter width */
max-width: 0;
padding-inline-end: 5px;
}
/* Source editor in tab panels */
/* If there is a source editor shows up in the last row of TreeView,
* it should occupy the available vertical space.
*/
.tree-container .treeTable .editor-row-container,
.tree-container .treeTable tr:last-child td[colspan="2"] {
display: block;
height: 100%;
}
.editor-container,
.editor-mount,
.panel-container iframe {
border: none;
width: 100%;
height: 100%;
}
.headers-summary-label,
.tree-container .objectBox {
white-space: nowrap;
}
/* Summary tabpanel */
@ -674,6 +859,46 @@
background: var(--theme-toolbar-background);
}
.headers-summary,
.response-summary {
display: flex;
align-items: center;
}
.headers-summary .devtools-button {
margin-inline-end: 6px;
}
.headers-summary .requests-list-status-icon {
min-width: 10px;
}
.headers-summary .raw-headers-container {
display: flex;
width: 100%;
}
.headers-summary .raw-headers {
width: 50%;
padding: 0 4px;
}
.headers-summary .raw-headers textarea {
width: 100%;
height: 50vh;
font: message-box;
resize: none;
box-sizing: border-box;
}
.headers-summary .raw-headers .tabpanel-summary-label {
padding: 0 0 4px 0;
}
.headers-summary .textbox-input {
margin-inline-end: 2px;
}
.headers-summary .status-text {
width: auto!important;
}
@ -746,6 +971,39 @@
color: var(--theme-body-color);
}
/* Stack trace panel */
.stack-trace {
font-family: var(--monospace-font-family);
/* The markup contains extra whitespace to improve formatting of clipboard text.
Make sure this whitespace doesn't affect the HTML rendering */
white-space: normal;
padding: 5px;
}
.stack-trace .frame-link-source,
.message-location .frame-link-source {
/* Makes the file name truncated (and ellipsis shown) on the left side */
direction: rtl;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.stack-trace .frame-link-source-inner,
.message-location .frame-link-source-inner {
/* Enforce LTR direction for the file name - fixes bug 1290056 */
direction: ltr;
unicode-bidi: embed;
}
.stack-trace .frame-link-function-display-name {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
margin-inline-end: 1ch;
}
/* Security tabpanel */
/* Overwrite tree-view cell colon `:` for security panel and tree section */
@ -1091,9 +1349,6 @@
}
/* Platform overrides (copied in from the old platform specific files) */
:root[platform="win"] .requests-list-header-button > .button-box {
padding: 0;
}
:root[platform="win"] .requests-list-timings-division {
padding-top: 1px;
@ -1114,205 +1369,3 @@
font-size: 85%;
}
}
.textbox-input {
text-overflow: ellipsis;
border: none;
background: none;
color: inherit;
width: 100%;
}
.treeTable .textbox-input:focus {
outline: 0;
box-shadow: var(--theme-focus-box-shadow-textbox);
}
.panel-container,
.properties-view {
display: flex;
flex-direction: column;
flex-grow: 1;
height: 100%;
}
.properties-view .searchbox-section {
flex: 0 1 auto;
}
.properties-view .devtools-searchbox {
padding: 0;
}
.properties-view .devtools-searchbox input {
margin: 1px 3px;
}
.tree-container {
position: relative;
height: 100%;
}
/* Make treeTable fill parent element and scrollable */
.tree-container .treeTable {
position: absolute;
display: block;
overflow-y: auto;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
/* Apply flex to table tbody in order to fill available vertical space */
.tree-container .treeTable tbody {
display: flex;
flex-direction: column;
/* Apply flex to table will create an anonymous table element outside of tbody
* See also http://stackoverflow.com/a/30851678
* Therefore, we set height with this magic number in order to remove the
* redundant scrollbar when source editor appears.
*/
height: calc(100% - 4px);
}
.tree-container .treeTable tr {
display: block;
}
/* Make right td fill available horizontal space */
.tree-container .treeTable td:last-child {
width: 100%;
}
/* If there is a source editor shows up in the last row of TreeView,
* it should occupy the available vertical space.
*/
.tree-container .treeTable .editor-row-container,
.tree-container .treeTable tr:last-child td[colspan="2"] {
display: block;
height: 100%;
}
.properties-view .devtools-searchbox,
.tree-container .treeTable .tree-section {
width: 100%;
background-color: var(--theme-toolbar-background);
}
.tree-container .treeTable tr.tree-section:not(:first-child) td:not([class=""]) {
border-top: 1px solid var(--theme-splitter-color);
}
.properties-view .devtools-searchbox,
.tree-container .treeTable tr.tree-section:not(:last-child) td:not([class=""]) {
border-bottom: 1px solid var(--theme-splitter-color);
}
.tree-container .treeTable .tree-section > * {
vertical-align: middle;
}
.tree-container .treeTable .treeRow.tree-section > .treeLabelCell > .treeLabel,
.tree-container .treeTable .treeRow.tree-section > .treeLabelCell > .treeLabel:hover {
color: var(--theme-body-color-alt);
}
.tree-container .treeTable .treeValueCell {
/* FIXME: Make value cell can be reduced to shorter width */
max-width: 0;
padding-inline-end: 5px;
}
.headers-summary input:not([type="button"]) {
width: 100%;
background: none;
border: none;
color: inherit;
margin-inline-end: 2px;
}
.headers-summary input:not([type="button"]):focus {
outline: none;
box-shadow: var(--theme-focus-box-shadow-textbox);
transition: all 0.2s ease-in-out;
}
.headers-summary-label,
.tree-container .objectBox {
white-space: nowrap;
}
.headers-summary,
.response-summary {
display: flex;
align-items: center;
}
.headers-summary .devtools-button {
margin-inline-end: 6px;
}
.headers-summary .requests-list-status-icon {
min-width: 10px;
}
.headers-summary .raw-headers-container {
display: flex;
width: 100%;
}
.headers-summary .raw-headers {
width: 50%;
padding: 0 4px;
}
.headers-summary .raw-headers textarea {
width: 100%;
height: 50vh;
font: message-box;
resize: none;
box-sizing: border-box;
}
.headers-summary .raw-headers .tabpanel-summary-label {
padding: 0 0 4px 0;
}
.empty-notice {
color: var(--theme-body-color-alt);
padding: 3px 8px;
}
.response-summary {
display: flex;
}
.editor-container,
.editor-mount,
.panel-container iframe {
border: none;
width: 100%;
height: 100%;
}
.network-details-panel {
width: 100%;
height: 100%;
overflow: hidden;
}
.split-box {
overflow: hidden;
}
html,
body,
#mount,
.network-monitor,
.monitor-panel {
display: flex;
flex-direction: column;
height: 100%;
overflow: hidden;
}

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

@ -21,7 +21,9 @@ DevToolsModules(
'request-list.js',
'response-panel.js',
'security-panel.js',
'stack-trace-panel.js',
'statistics-panel.js',
'status-bar.js',
'tabbox-panel.js',
'timings-panel.js',
'toolbar.js',

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

@ -13,10 +13,7 @@ const {
const { connect } = require("devtools/client/shared/vendor/react-redux");
const { HTMLTooltip } = require("devtools/client/shared/widgets/tooltip/HTMLTooltip");
const Actions = require("../actions/index");
const {
setTooltipImageContent,
setTooltipStackTraceContent,
} = require("../request-list-tooltip");
const { setTooltipImageContent } = require("../request-list-tooltip");
const {
getDisplayedRequests,
getWaterfallScale,
@ -42,6 +39,7 @@ const RequestListContent = createClass({
displayedRequests: PropTypes.object.isRequired,
firstRequestStartedMillis: PropTypes.number.isRequired,
fromCache: PropTypes.bool.isRequired,
onCauseBadgeClick: PropTypes.func.isRequired,
onItemMouseDown: PropTypes.func.isRequired,
onSecurityIconClick: PropTypes.func.isRequired,
onSelectDelta: PropTypes.func.isRequired,
@ -157,8 +155,6 @@ const RequestListContent = createClass({
if (requestItem.responseContent && target.closest(".requests-list-icon-and-file")) {
return setTooltipImageContent(tooltip, itemEl, requestItem);
} else if (requestItem.cause && target.closest(".requests-list-cause-stack")) {
return setTooltipStackTraceContent(tooltip, requestItem);
}
return false;
@ -227,6 +223,7 @@ const RequestListContent = createClass({
displayedRequests,
firstRequestStartedMillis,
selectedRequestId,
onCauseBadgeClick,
onItemMouseDown,
onSecurityIconClick,
} = this.props;
@ -248,6 +245,7 @@ const RequestListContent = createClass({
onContextMenu: this.onContextMenu,
onFocusedNodeChange: this.onFocusedNodeChange,
onMouseDown: () => onItemMouseDown(item.id),
onCauseBadgeClick: () => onCauseBadgeClick(item.cause),
onSecurityIconClick: () => onSecurityIconClick(item.securityState),
}))
)
@ -274,6 +272,14 @@ module.exports = connect(
dispatch(Actions.selectDetailsPanelTab("security"));
}
},
/**
* A handler that opens the stack trace tab when a stack trace is available
*/
onCauseBadgeClick: (cause) => {
if (cause.stacktrace && cause.stacktrace.length > 0) {
dispatch(Actions.selectDetailsPanelTab("stack-trace"));
}
},
onSelectDelta: (delta) => dispatch(Actions.selectDelta(delta)),
}),
)(RequestListContent);

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

@ -37,7 +37,7 @@ const RequestListEmptyNotice = createClass({
span(null, L10N.getStr("netmonitor.reloadNotice1")),
button(
{
className: "devtools-toolbarbutton requests-list-reload-notice-button",
className: "devtools-button requests-list-reload-notice-button",
"data-standalone": true,
onClick: this.props.onReloadClick,
},

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

@ -66,6 +66,7 @@ const RequestListItem = createClass({
isSelected: PropTypes.bool.isRequired,
firstRequestStartedMillis: PropTypes.number.isRequired,
fromCache: PropTypes.bool.isRequired,
onCauseBadgeClick: PropTypes.func.isRequired,
onContextMenu: PropTypes.func.isRequired,
onFocusedNodeChange: PropTypes.func,
onMouseDown: PropTypes.func.isRequired,
@ -101,6 +102,7 @@ const RequestListItem = createClass({
fromCache,
onContextMenu,
onMouseDown,
onCauseBadgeClick,
onSecurityIconClick
} = this.props;
@ -128,7 +130,7 @@ const RequestListItem = createClass({
MethodColumn({ item }),
FileColumn({ item }),
DomainColumn({ item, onSecurityIconClick }),
CauseColumn({ item }),
CauseColumn({ item, onCauseBadgeClick }),
TypeColumn({ item }),
TransferredSizeColumn({ item }),
ContentSizeColumn({ item }),
@ -301,6 +303,7 @@ const CauseColumn = createFactory(createClass({
propTypes: {
item: PropTypes.object.isRequired,
onCauseBadgeClick: PropTypes.func.isRequired,
},
shouldComponentUpdate(nextProps) {
@ -308,7 +311,12 @@ const CauseColumn = createFactory(createClass({
},
render() {
const { cause } = this.props.item;
const {
item,
onCauseBadgeClick,
} = this.props;
const { cause } = item;
let causeType = "";
let causeUri = undefined;
@ -329,6 +337,7 @@ const CauseColumn = createFactory(createClass({
span({
className: "requests-list-cause-stack",
hidden: !causeHasStack,
onClick: onCauseBadgeClick,
}, "JS"),
span({ className: "subitem-label" }, causeType),
)

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

@ -14,6 +14,7 @@ const {
const RequestListContent = createFactory(require("./request-list-content"));
const RequestListEmptyNotice = createFactory(require("./request-list-empty-notice"));
const RequestListHeader = createFactory(require("./request-list-header"));
const StatusBar = createFactory(require("./status-bar"));
const { div } = DOM;
@ -25,6 +26,7 @@ function RequestList({ isEmpty }) {
div({ className: "request-list-container" },
RequestListHeader(),
isEmpty ? RequestListEmptyNotice() : RequestListContent(),
StatusBar(),
)
);
}

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

@ -0,0 +1,39 @@
/* 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 {
createFactory,
DOM,
PropTypes,
} = require("devtools/client/shared/vendor/react");
const { div } = DOM;
// Components
const StackTrace = createFactory(require("devtools/client/shared/components/stack-trace"));
function StackTracePanel({ request }) {
let { stacktrace } = request.cause;
return (
div({ className: "panel-container" },
StackTrace({
stacktrace,
onViewSourceInDebugger: (name, line) => {
window.NetMonitorController.viewSourceInDebugger(name, line);
},
}),
)
);
}
StackTracePanel.displayName = "StackTracePanel";
StackTracePanel.propTypes = {
request: PropTypes.object.isRequired,
};
module.exports = StackTracePanel;

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

@ -0,0 +1,84 @@
/* 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 {
DOM,
PropTypes,
} = require("devtools/client/shared/vendor/react");
const { connect } = require("devtools/client/shared/vendor/react-redux");
const { PluralForm } = require("devtools/shared/plural-form");
const Actions = require("../actions/index");
const {
getDisplayedRequestsSummary,
getDisplayedTimingMarker,
} = require("../selectors/index");
const {
getFormattedSize,
getFormattedTime
} = require("../utils/format-utils");
const { L10N } = require("../utils/l10n");
// Components
const { div, button, span } = DOM;
function StatusBar({ summary, openStatistics, timingMarkers }) {
let { count, contentSize, transferredSize, millis } = summary;
let {
DOMContentLoaded,
load,
} = timingMarkers;
let text = (count === 0) ? L10N.getStr("networkMenu.empty") :
PluralForm.get(count, L10N.getStr("networkMenu.summary3"))
.replace("#1", count)
.replace("#2", getFormattedSize(contentSize))
.replace("#3", getFormattedSize(transferredSize))
.replace("#4", getFormattedTime(millis));
return (
div({ className: "devtools-toolbar devtools-toolbar-bottom" },
button({
className: "devtools-button requests-list-network-summary-button",
title: count ? text : L10N.getStr("netmonitor.toolbar.perf"),
onClick: openStatistics,
},
span({ className: "summary-info-icon" }),
span({ className: "summary-info-text" }, text),
),
DOMContentLoaded > -1 &&
span({ className: "status-bar-label dom-content-loaded" },
`DOMContentLoaded: ${getFormattedTime(DOMContentLoaded)}`),
load > -1 &&
span({ className: "status-bar-label load" },
`load: ${getFormattedTime(load)}`),
)
);
}
StatusBar.displayName = "StatusBar";
StatusBar.propTypes = {
openStatistics: PropTypes.func.isRequired,
summary: PropTypes.object.isRequired,
timingMarkers: PropTypes.object.isRequired,
};
module.exports = connect(
(state) => ({
summary: getDisplayedRequestsSummary(state),
timingMarkers: {
DOMContentLoaded:
getDisplayedTimingMarker(state, "firstDocumentDOMContentLoadedTimestamp"),
load: getDisplayedTimingMarker(state, "firstDocumentLoadTimestamp"),
},
}),
(dispatch) => ({
openStatistics: () => dispatch(Actions.openStatistics(true)),
}),
)(StatusBar);

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

@ -23,15 +23,17 @@ const ParamsPanel = createFactory(require("./params-panel"));
const PreviewPanel = createFactory(require("./preview-panel"));
const ResponsePanel = createFactory(require("./response-panel"));
const SecurityPanel = createFactory(require("./security-panel"));
const StackTracePanel = createFactory(require("./stack-trace-panel"));
const TimingsPanel = createFactory(require("./timings-panel"));
const HEADERS_TITLE = L10N.getStr("netmonitor.tab.headers");
const COOKIES_TITLE = L10N.getStr("netmonitor.tab.cookies");
const HEADERS_TITLE = L10N.getStr("netmonitor.tab.headers");
const PARAMS_TITLE = L10N.getStr("netmonitor.tab.params");
const RESPONSE_TITLE = L10N.getStr("netmonitor.tab.response");
const TIMINGS_TITLE = L10N.getStr("netmonitor.tab.timings");
const SECURITY_TITLE = L10N.getStr("netmonitor.tab.security");
const PREVIEW_TITLE = L10N.getStr("netmonitor.tab.preview");
const RESPONSE_TITLE = L10N.getStr("netmonitor.tab.response");
const SECURITY_TITLE = L10N.getStr("netmonitor.tab.security");
const STACK_TRACE_TITLE = L10N.getStr("netmonitor.tab.stackTrace");
const TIMINGS_TITLE = L10N.getStr("netmonitor.tab.timings");
/*
* Tabbox panel component
@ -84,6 +86,13 @@ function TabboxPanel({
},
TimingsPanel({ request }),
),
request.cause.stacktrace && request.cause.stacktrace.length > 0 &&
TabPanel({
id: "stack-trace",
title: STACK_TRACE_TITLE,
},
StackTracePanel({ request }),
),
request.securityState && request.securityState !== "insecure" &&
TabPanel({
id: "security",

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

@ -11,7 +11,6 @@ const {
PropTypes,
} = require("devtools/client/shared/vendor/react");
const { connect } = require("devtools/client/shared/vendor/react-redux");
const { PluralForm } = require("devtools/shared/plural-form");
const Actions = require("../actions/index");
const { FILTER_SEARCH_DELAY } = require("../constants");
const {
@ -19,10 +18,7 @@ const {
getRequestFilterTypes,
isNetworkDetailsToggleButtonDisabled,
} = require("../selectors/index");
const {
getFormattedSize,
getFormattedTime
} = require("../utils/format-utils");
const { L10N } = require("../utils/l10n");
// Components
@ -45,12 +41,10 @@ const Toolbar = createClass({
propTypes: {
clearRequests: PropTypes.func.isRequired,
openStatistics: PropTypes.func.isRequired,
requestFilterTypes: PropTypes.array.isRequired,
setRequestFilterText: PropTypes.func.isRequired,
networkDetailsToggleDisabled: PropTypes.bool.isRequired,
networkDetailsOpen: PropTypes.bool.isRequired,
summary: PropTypes.object.isRequired,
toggleNetworkDetails: PropTypes.func.isRequired,
toggleRequestFilterType: PropTypes.func.isRequired,
},
@ -65,12 +59,10 @@ const Toolbar = createClass({
render() {
let {
clearRequests,
openStatistics,
requestFilterTypes,
setRequestFilterText,
networkDetailsToggleDisabled,
networkDetailsOpen,
summary,
toggleNetworkDetails,
} = this.props;
@ -82,14 +74,6 @@ const Toolbar = createClass({
toggleButtonClassName.push("pane-collapsed");
}
let { count, contentSize, transferredSize, millis } = summary;
let text = (count === 0) ? L10N.getStr("networkMenu.empty") :
PluralForm.get(count, L10N.getStr("networkMenu.summary3"))
.replace("#1", count)
.replace("#2", getFormattedSize(contentSize))
.replace("#3", getFormattedSize(transferredSize))
.replace("#4", getFormattedTime(millis));
let buttons = requestFilterTypes.map(([type, checked]) => {
let classList = ["devtools-button", `requests-list-filter-${type}-button`];
checked && classList.push("checked");
@ -119,14 +103,6 @@ const Toolbar = createClass({
div({ className: "requests-list-filter-buttons" }, buttons),
),
span({ className: "devtools-toolbar-group" },
button({
className: "devtools-button requests-list-network-summary-button",
title: count ? text : L10N.getStr("netmonitor.toolbar.perf"),
onClick: openStatistics,
},
span({ className: "summary-info-icon" }),
span({ className: "summary-info-text" }, text),
),
SearchBox({
delay: FILTER_SEARCH_DELAY,
keyShortcut: SEARCH_KEY_SHORTCUT,
@ -156,7 +132,6 @@ module.exports = connect(
}),
(dispatch) => ({
clearRequests: () => dispatch(Actions.clearRequests()),
openStatistics: () => dispatch(Actions.openStatistics(true)),
setRequestFilterText: (text) => dispatch(Actions.setRequestFilterText(text)),
toggleRequestFilterType: (type) => dispatch(Actions.toggleRequestFilterType(type)),
toggleNetworkDetails: () => dispatch(Actions.toggleNetworkDetails()),

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

@ -9,13 +9,9 @@ const {
getImageDimensions,
} = require("devtools/client/shared/widgets/tooltip/ImageTooltipHelper");
const { getLongString } = require("./utils/client");
const { WEBCONSOLE_L10N } = require("./utils/l10n");
const { formDataURI } = require("./utils/request-utils");
const REQUESTS_TOOLTIP_IMAGE_MAX_DIM = 400; // px
const REQUESTS_TOOLTIP_STACK_TRACE_WIDTH = 600; // px
const HTML_NS = "http://www.w3.org/1999/xhtml";
async function setTooltipImageContent(tooltip, itemEl, requestItem) {
let { mimeType, text, encoding } = requestItem.responseContent.content;
@ -34,72 +30,6 @@ async function setTooltipImageContent(tooltip, itemEl, requestItem) {
return itemEl.querySelector(".requests-list-icon");
}
async function setTooltipStackTraceContent(tooltip, requestItem) {
let {stacktrace} = requestItem.cause;
if (!stacktrace || stacktrace.length == 0) {
return false;
}
let doc = tooltip.doc;
let el = doc.createElementNS(HTML_NS, "div");
el.className = "stack-trace-tooltip devtools-monospace";
for (let f of stacktrace) {
let { functionName, filename, lineNumber, columnNumber, asyncCause } = f;
if (asyncCause) {
// if there is asyncCause, append a "divider" row into the trace
let asyncFrameEl = doc.createElementNS(HTML_NS, "div");
asyncFrameEl.className = "stack-frame stack-frame-async";
asyncFrameEl.textContent =
WEBCONSOLE_L10N.getFormatStr("stacktrace.asyncStack", asyncCause);
el.appendChild(asyncFrameEl);
}
// Parse a source name in format "url -> url"
let sourceUrl = filename.split(" -> ").pop();
let frameEl = doc.createElementNS(HTML_NS, "div");
frameEl.className = "stack-frame stack-frame-call";
let funcEl = doc.createElementNS(HTML_NS, "span");
funcEl.className = "stack-frame-function-name";
funcEl.textContent =
functionName || WEBCONSOLE_L10N.getStr("stacktrace.anonymousFunction");
frameEl.appendChild(funcEl);
let sourceEl = doc.createElementNS(HTML_NS, "span");
sourceEl.className = "stack-frame-source-name";
frameEl.appendChild(sourceEl);
let sourceInnerEl = doc.createElementNS(HTML_NS, "span");
sourceInnerEl.className = "stack-frame-source-name-inner";
sourceEl.appendChild(sourceInnerEl);
sourceInnerEl.textContent = sourceUrl;
sourceInnerEl.title = sourceUrl;
let lineEl = doc.createElementNS(HTML_NS, "span");
lineEl.className = "stack-frame-line";
lineEl.textContent = `:${lineNumber}:${columnNumber}`;
sourceInnerEl.appendChild(lineEl);
frameEl.addEventListener("click", () => {
// hide the tooltip immediately, not after delay
tooltip.hide();
window.NetMonitorController.viewSourceInDebugger(filename, lineNumber);
});
el.appendChild(frameEl);
}
tooltip.setContent(el, {width: REQUESTS_TOOLTIP_STACK_TRACE_WIDTH});
return true;
}
module.exports = {
setTooltipImageContent,
setTooltipStackTraceContent,
};

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

@ -6,10 +6,12 @@
const filters = require("./filters");
const requests = require("./requests");
const timingMarkers = require("./timing-markers");
const ui = require("./ui");
Object.assign(exports,
filters,
requests,
timingMarkers,
ui
);

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

@ -6,5 +6,6 @@ DevToolsModules(
'filters.js',
'index.js',
'requests.js',
'timing-markers.js',
'ui.js',
)

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

@ -1,11 +1,13 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
function getDisplayedTimingMarker(state, marker) {
return state.timingMarkers.get(marker) - state.requests.get("firstStartedMillis");
}
module.exports = {
when: () => {},
getDisplayedTimingMarker,
};

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

@ -5,7 +5,6 @@ support-files =
dropmarker.svg
head.js
html_cause-test-page.html
html_content-type-test-page.html
html_content-type-without-cache-test-page.html
html_brotli-test-page.html
html_image-tooltip-test-page.html
@ -106,7 +105,6 @@ skip-if = (os == 'linux' && debug && bits == 32) # Bug 1303439
[browser_net_filter-03.js]
[browser_net_filter-04.js]
[browser_net_footer-summary.js]
[browser_net_html-preview.js]
[browser_net_icon-preview.js]
[browser_net_image-tooltip.js]
[browser_net_json-b64.js]

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

@ -1,65 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
/**
* Tests if html responses show and properly populate a "Preview" tab.
*/
add_task(function* () {
let { tab, monitor } = yield initNetMonitor(CONTENT_TYPE_URL);
info("Starting test... ");
let { document, gStore, windowRequire } = monitor.panelWin;
let Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
gStore.dispatch(Actions.batchEnable(false));
let wait = waitForNetworkEvents(monitor, 6);
yield ContentTask.spawn(tab.linkedBrowser, {}, function* () {
content.wrappedJSObject.performRequests();
});
yield wait;
EventUtils.sendMouseEvent({ type: "click" },
document.querySelector(".network-details-panel-toggle"));
ok(document.querySelector("#headers-tab[aria-selected=true]"),
"The headers tab in the details panel should be selected.");
ok(!document.querySelector("#preview-tab"),
"The preview tab should be hidden for non html responses.");
ok(!document.querySelector("#preview-panel"),
"The preview panel is hidden for non html responses.");
EventUtils.sendMouseEvent({ type: "mousedown" },
document.querySelectorAll(".request-list-item")[4]);
document.querySelector("#preview-tab").click();
ok(document.querySelector("#preview-tab[aria-selected=true]"),
"The preview tab in the details panel should be selected.");
ok(document.querySelector("#preview-panel"),
"The preview panel should be visible now.");
let iframe = document.querySelector("#preview-panel iframe");
yield once(iframe, "DOMContentLoaded");
ok(iframe,
"There should be a response preview iframe available.");
ok(iframe.contentDocument,
"The iframe's content document should be available.");
is(iframe.contentDocument.querySelector("blink").textContent, "Not Found",
"The iframe's content document should be loaded and correct.");
EventUtils.sendMouseEvent({ type: "mousedown" },
document.querySelectorAll(".request-list-item")[5]);
ok(document.querySelector("#headers-tab[aria-selected=true]"),
"The headers tab in the details panel should be selected again.");
ok(!document.querySelector("#preview-tab"),
"The preview tab should be hidden again for non html responses.");
ok(!document.querySelector("#preview-panel"),
"The preview panel is hidden again for non html responses.");
yield teardown(monitor);
});

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

@ -28,7 +28,6 @@ const HTTPS_EXAMPLE_URL = "https://example.com/browser/devtools/client/netmonito
const API_CALLS_URL = EXAMPLE_URL + "html_api-calls-test-page.html";
const SIMPLE_URL = EXAMPLE_URL + "html_simple-test-page.html";
const NAVIGATE_URL = EXAMPLE_URL + "html_navigate-test-page.html";
const CONTENT_TYPE_URL = EXAMPLE_URL + "html_content-type-test-page.html";
const CONTENT_TYPE_WITHOUT_CACHE_URL = EXAMPLE_URL + "html_content-type-without-cache-test-page.html";
const CONTENT_TYPE_WITHOUT_CACHE_REQUESTS = 8;
const CYRILLIC_URL = EXAMPLE_URL + "html_cyrillic-test-page.html";

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

@ -1,53 +0,0 @@
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<!doctype html>
<html>
<head>
<meta charset="utf-8"/>
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<title>Network Monitor test page</title>
</head>
<body>
<p>Content type test</p>
<script type="text/javascript">
/* exported performRequests */
"use strict";
function get(address, callback) {
let xhr = new XMLHttpRequest();
xhr.open("GET", address, true);
xhr.onreadystatechange = function () {
if (this.readyState == this.DONE) {
callback();
}
};
xhr.send(null);
}
function performRequests() {
/* eslint-disable max-nested-callbacks */
get("sjs_content-type-test-server.sjs?fmt=xml", function () {
get("sjs_content-type-test-server.sjs?fmt=css", function () {
get("sjs_content-type-test-server.sjs?fmt=js", function () {
get("sjs_content-type-test-server.sjs?fmt=json", function () {
get("sjs_content-type-test-server.sjs?fmt=bogus", function () {
get("test-image.png", function () {
// Done.
});
});
});
});
});
});
/* eslint-enable max-nested-callbacks */
}
</script>
</body>
</html>

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

@ -8,10 +8,11 @@
.tabs {
height: 100%;
background: var(--theme-body-background);
display: flex;
flex-direction: column;
}
.tabs .tabs-menu {
display: table;
list-style: none;
padding: 0;
margin: 0;
@ -41,14 +42,15 @@
-moz-user-select: none;
}
/* Make sure panel content takes entire vertical space.
(minus the height of the tab bar) */
/* Make sure panel content takes entire vertical space. */
.tabs .panels {
height: calc(100% - 24px);
flex: 1;
overflow: hidden;
}
.tabs .tab-panel {
height: 100%;
overflow: auto;
}
.tabs .tabs-navigation,

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

@ -39,7 +39,7 @@
/* Toolbars */
.devtools-toolbar,
.devtools-sidebar-tabs tabs {
-moz-appearance: none; appearance: none;
-moz-appearance: none;
padding: 0;
border-width: 0;
border-bottom-width: 1px;
@ -74,6 +74,11 @@
padding: 0;
}
.devtools-toolbar-bottom {
border-top-width: 1px;
border-bottom: none;
}
.devtools-separator {
margin: 0 2px;
width: 2px;

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

@ -258,14 +258,6 @@
stroke-width: 2;
}
/* Rect Highlighter */
:-moz-native-anonymous .highlighted-rect {
position: absolute;
background: var(--highlighter-content-color);
opacity: 0.8;
}
/* Element Geometry Highlighter */
:-moz-native-anonymous .geometry-editor-root {

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

@ -129,6 +129,11 @@ KeyframeEffect::SetTarget(const Nullable<ElementOrCSSPseudoElement>& aTarget)
// New target is null, so fall back to distribute spacing.
KeyframeUtils::ApplyDistributeSpacing(mKeyframes);
}
// If the new target frame is also oversized we should probably record that
// too so we have a more complete picture of the type of frame sizes we
// encounter, hence we reset the telemetry flag here.
mRecordedContentTooLarge = false;
}
void

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

@ -6,6 +6,7 @@
#include "mozilla/dom/KeyframeEffectReadOnly.h"
#include "gfxPrefs.h"
#include "mozilla/dom/KeyframeAnimationOptionsBinding.h"
// For UnrestrictedDoubleOrKeyframeAnimationOptions;
#include "mozilla/dom/CSSPseudoElement.h"
@ -18,6 +19,7 @@
#include "mozilla/LookAndFeel.h" // For LookAndFeel::GetInt
#include "mozilla/KeyframeUtils.h"
#include "mozilla/ServoBindings.h"
#include "mozilla/Telemetry.h"
#include "mozilla/TypeTraits.h"
#include "Layers.h" // For Layer
#include "nsComputedDOMStyle.h" // nsComputedDOMStyle::GetStyleContextForElement
@ -1597,6 +1599,31 @@ KeyframeEffectReadOnly::SetPerformanceWarning(
nsCSSPropertyID aProperty,
const AnimationPerformanceWarning& aWarning)
{
if (aWarning.mType == AnimationPerformanceWarning::Type::ContentTooLarge &&
!mRecordedContentTooLarge) {
// ContentTooLarge stores: frameSize (w x h),
// relativeLimit (w x h), i.e. =~ viewport size *
// ratioLimit
// absoluteLimit (w x h)
MOZ_ASSERT(aWarning.mParams && aWarning.mParams->Length() >= 4,
"ContentTooLarge warning should have at least 4 parameters");
const nsTArray<int32_t>& params = aWarning.mParams.ref();
uint32_t frameSize = uint32_t(params[0]) * params[1];
float viewportRatioX = gfxPrefs::AnimationPrerenderViewportRatioLimitX();
float viewportRatioY = gfxPrefs::AnimationPrerenderViewportRatioLimitY();
double viewportWidth = viewportRatioX ? params[2] / viewportRatioX
: params[2];
double viewportHeight = viewportRatioY ? params[3] / viewportRatioY
: params[3];
double viewportSize = viewportWidth * viewportHeight;
uint32_t frameToViewport = frameSize / viewportSize * 100.0;
Telemetry::Accumulate(
Telemetry::ASYNC_ANIMATION_CONTENT_TOO_LARGE_FRAME_SIZE, frameSize);
Telemetry::Accumulate(
Telemetry::ASYNC_ANIMATION_CONTENT_TOO_LARGE_PERCENTAGE, frameToViewport);
mRecordedContentTooLarge = true;
}
for (AnimationProperty& property : mProperties) {
if (property.mProperty == aProperty &&
(!property.mPerformanceWarning ||

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

@ -455,6 +455,11 @@ protected:
// (i.e. it uses the additive or accumulate composite mode).
nsDataHashtable<nsUint32HashKey, StyleAnimationValue> mBaseStyleValues;
// We only want to record telemetry data for "ContentTooLarge" warnings once
// per effect:target pair so we use this member to record if we have already
// reported a "ContentTooLarge" warning for the current target.
bool mRecordedContentTooLarge = false;
private:
nsChangeHint mCumulativeChangeHint;

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

@ -1020,16 +1020,14 @@ MakePropertyValuePair(nsCSSPropertyID aProperty, const nsAString& aStringValue,
NS_ConvertUTF16toUTF8 value(aStringValue);
nsCString baseString;
// FIXME this is using the wrong base uri (bug 1343919)
RefPtr<css::URLExtraData> data =
new css::URLExtraData(aDocument->GetDocumentURI(),
aDocument->GetDocumentURI(),
aDocument->NodePrincipal());
aDocument->GetDocumentURI()->GetSpec(baseString);
RefPtr<RawServoDeclarationBlock> servoDeclarationBlock =
Servo_ParseProperty(&name, &value, &baseString, data).Consume();
Servo_ParseProperty(&name, &value, data).Consume();
if (servoDeclarationBlock) {
result.mServoDeclarationBlock = servoDeclarationBlock.forget();

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

@ -116,14 +116,12 @@ TimingParams::ParseEasing(const nsAString& aEasing,
if (aDocument->IsStyledByServo()) {
nsTimingFunction timingFunction;
nsCString baseString;
// FIXME this is using the wrong base uri (bug 1343919)
RefPtr<css::URLExtraData> data =
new css::URLExtraData(aDocument->GetDocumentURI(),
aDocument->GetDocumentURI(),
aDocument->NodePrincipal());
aDocument->GetDocumentURI()->GetSpec(baseString);
if (!Servo_ParseEasing(&aEasing, &baseString, data, &timingFunction)) {
if (!Servo_ParseEasing(&aEasing, data, &timingFunction)) {
aRv.ThrowTypeError<dom::MSG_INVALID_EASING_ERROR>(aEasing);
return Nothing();
}

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

@ -1234,13 +1234,11 @@ MappedAttrParser::ParseMappedAttrValue(nsIAtom* aMappedAttrName,
} else {
NS_ConvertUTF16toUTF8 value(aMappedAttrValue);
// FIXME (bug 1343964): Figure out a better solution for sending the base uri to servo
nsCString baseString;
RefPtr<css::URLExtraData> data =
new css::URLExtraData(mBaseURI, mDocURI, mElement->NodePrincipal());
mBaseURI->GetSpec(baseString);
// FIXME (bug 1342559): Set SVG parsing mode for lengths
changed = Servo_DeclarationBlock_SetPropertyById(mDecl->AsServo()->Raw(), propertyID,
&value, false, &baseString, data);
&value, false, data);
}
if (changed) {

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

@ -1343,86 +1343,92 @@ HTMLEditRules::WillInsertText(EditAction aAction,
int32_t pos = 0;
NS_NAMED_LITERAL_STRING(newlineStr, LFSTR);
// for efficiency, break out the pre case separately. This is because
// its a lot cheaper to search the input string for only newlines than
// it is to search for both tabs and newlines.
if (isPRE || IsPlaintextEditor()) {
while (unicodeBuf && pos != -1 &&
pos < static_cast<int32_t>(inString->Length())) {
int32_t oldPos = pos;
int32_t subStrLen;
pos = tString.FindChar(nsCRT::LF, oldPos);
{
NS_ENSURE_STATE(mHTMLEditor);
AutoTrackDOMPoint tracker(mHTMLEditor->mRangeUpdater,
address_of(selNode), &selOffset);
if (pos != -1) {
subStrLen = pos - oldPos;
// if first char is newline, then use just it
if (!subStrLen) {
subStrLen = 1;
// for efficiency, break out the pre case separately. This is because
// its a lot cheaper to search the input string for only newlines than
// it is to search for both tabs and newlines.
if (isPRE || IsPlaintextEditor()) {
while (unicodeBuf && pos != -1 &&
pos < static_cast<int32_t>(inString->Length())) {
int32_t oldPos = pos;
int32_t subStrLen;
pos = tString.FindChar(nsCRT::LF, oldPos);
if (pos != -1) {
subStrLen = pos - oldPos;
// if first char is newline, then use just it
if (!subStrLen) {
subStrLen = 1;
}
} else {
subStrLen = tString.Length() - oldPos;
pos = tString.Length();
}
} else {
subStrLen = tString.Length() - oldPos;
pos = tString.Length();
}
nsDependentSubstring subStr(tString, oldPos, subStrLen);
nsDependentSubstring subStr(tString, oldPos, subStrLen);
// is it a return?
if (subStr.Equals(newlineStr)) {
NS_ENSURE_STATE(mHTMLEditor);
nsCOMPtr<Element> br =
mHTMLEditor->CreateBRImpl(address_of(curNode), &curOffset,
nsIEditor::eNone);
NS_ENSURE_STATE(br);
pos++;
} else {
NS_ENSURE_STATE(mHTMLEditor);
rv = mHTMLEditor->InsertTextImpl(subStr, address_of(curNode),
&curOffset, doc);
NS_ENSURE_SUCCESS(rv, rv);
}
}
} else {
NS_NAMED_LITERAL_STRING(tabStr, "\t");
NS_NAMED_LITERAL_STRING(spacesStr, " ");
char specialChars[] = {TAB, nsCRT::LF, 0};
while (unicodeBuf && pos != -1 &&
pos < static_cast<int32_t>(inString->Length())) {
int32_t oldPos = pos;
int32_t subStrLen;
pos = tString.FindCharInSet(specialChars, oldPos);
if (pos != -1) {
subStrLen = pos - oldPos;
// if first char is newline, then use just it
if (!subStrLen) {
subStrLen = 1;
// is it a return?
if (subStr.Equals(newlineStr)) {
NS_ENSURE_STATE(mHTMLEditor);
nsCOMPtr<Element> br =
mHTMLEditor->CreateBRImpl(address_of(curNode), &curOffset,
nsIEditor::eNone);
NS_ENSURE_STATE(br);
pos++;
} else {
NS_ENSURE_STATE(mHTMLEditor);
rv = mHTMLEditor->InsertTextImpl(subStr, address_of(curNode),
&curOffset, doc);
NS_ENSURE_SUCCESS(rv, rv);
}
} else {
subStrLen = tString.Length() - oldPos;
pos = tString.Length();
}
} else {
NS_NAMED_LITERAL_STRING(tabStr, "\t");
NS_NAMED_LITERAL_STRING(spacesStr, " ");
char specialChars[] = {TAB, nsCRT::LF, 0};
while (unicodeBuf && pos != -1 &&
pos < static_cast<int32_t>(inString->Length())) {
int32_t oldPos = pos;
int32_t subStrLen;
pos = tString.FindCharInSet(specialChars, oldPos);
nsDependentSubstring subStr(tString, oldPos, subStrLen);
NS_ENSURE_STATE(mHTMLEditor);
WSRunObject wsObj(mHTMLEditor, curNode, curOffset);
if (pos != -1) {
subStrLen = pos - oldPos;
// if first char is newline, then use just it
if (!subStrLen) {
subStrLen = 1;
}
} else {
subStrLen = tString.Length() - oldPos;
pos = tString.Length();
}
// is it a tab?
if (subStr.Equals(tabStr)) {
rv =
wsObj.InsertText(spacesStr, address_of(curNode), &curOffset, doc);
NS_ENSURE_SUCCESS(rv, rv);
pos++;
}
// is it a return?
else if (subStr.Equals(newlineStr)) {
nsCOMPtr<Element> br = wsObj.InsertBreak(address_of(curNode),
&curOffset,
nsIEditor::eNone);
NS_ENSURE_TRUE(br, NS_ERROR_FAILURE);
pos++;
} else {
rv = wsObj.InsertText(subStr, address_of(curNode), &curOffset, doc);
NS_ENSURE_SUCCESS(rv, rv);
nsDependentSubstring subStr(tString, oldPos, subStrLen);
NS_ENSURE_STATE(mHTMLEditor);
WSRunObject wsObj(mHTMLEditor, curNode, curOffset);
// is it a tab?
if (subStr.Equals(tabStr)) {
rv =
wsObj.InsertText(spacesStr, address_of(curNode), &curOffset, doc);
NS_ENSURE_SUCCESS(rv, rv);
pos++;
}
// is it a return?
else if (subStr.Equals(newlineStr)) {
nsCOMPtr<Element> br = wsObj.InsertBreak(address_of(curNode),
&curOffset,
nsIEditor::eNone);
NS_ENSURE_TRUE(br, NS_ERROR_FAILURE);
pos++;
} else {
rv = wsObj.InsertText(subStr, address_of(curNode), &curOffset, doc);
NS_ENSURE_SUCCESS(rv, rv);
}
}
}
}

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

@ -196,6 +196,7 @@ skip-if = os == 'android'
[test_bug1101392.html]
subsuite = clipboard
[test_bug1109465.html]
[test_bug1130651.html]
[test_bug1140105.html]
[test_bug1140617.html]
subsuite = clipboard

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

@ -0,0 +1,17 @@
<!DOCTYPE html>
<title>Test for Bug 1130651</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1332876">Mozilla Bug 1332876</a>
<div contenteditable>a b</div>
<script>
var div = document.querySelector("div");
div.focus();
getSelection().collapse(div.firstChild, 2);
try {
document.execCommand("inserttext", false, "\n");
ok(true, "No exception thrown");
} catch(e) {
ok(false, "Exception: " + e);
}
</script>

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

@ -91,8 +91,18 @@ nsThebesFontEnumerator::GetDefaultFont(const char *aLangGroup,
const char *aGeneric,
char16_t **aResult)
{
NS_ENSURE_ARG_POINTER(aResult);
if (NS_WARN_IF(!aResult) || NS_WARN_IF(!aLangGroup) ||
NS_WARN_IF(!aGeneric)) {
return NS_ERROR_INVALID_ARG;
}
*aResult = nullptr;
nsAutoString defaultFontName(gfxPlatform::GetPlatform()->
GetDefaultFontName(nsDependentCString(aLangGroup),
nsDependentCString(aGeneric)));
if (!defaultFontName.IsEmpty()) {
*aResult = ToNewUnicode(defaultFontName);
}
return NS_OK;
}

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

@ -184,6 +184,16 @@ gfxDWriteFontFamily::FindStyleVariations(FontInfoData *aFontInfoData)
fullID.Append(' ');
fullID.Append(faceName);
// Ignore italic style's "Meiryo" because "Meiryo (Bold) Italic" has
// non-italic style glyphs as Japanese characters. However, using it
// causes serious problem if web pages wants some elements to be
// different style from others only with font-style. For example,
// <em> and <i> should be rendered as italic in the default style.
if (fullID.EqualsLiteral("Meiryo Italic") ||
fullID.EqualsLiteral("Meiryo Bold Italic")) {
continue;
}
gfxDWriteFontEntry *fe = new gfxDWriteFontEntry(fullID, font);
fe->SetForceGDIClassic(mForceGDIClassic);
AddFontEntry(fe);

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

@ -1569,6 +1569,7 @@ gfxFcPlatformFontList::GetStandardFamilyName(const nsAString& aFontName,
}
static const char kFontNamePrefix[] = "font.name.";
static const char kFontNameListPrefix[] = "font.name-list.";
void
gfxFcPlatformFontList::AddGenericFonts(mozilla::FontFamilyType aGenericType,
@ -1604,6 +1605,17 @@ gfxFcPlatformFontList::AddGenericFonts(mozilla::FontFamilyType aGenericType,
prefFontName.Append('.');
prefFontName.Append(langGroupStr);
nsAdoptingString fontlistValue = Preferences::GetString(prefFontName.get());
if (fontlistValue.IsEmpty()) {
nsAutoCString prefFontNameListName(kFontNameListPrefix);
prefFontNameListName.Append(generic);
prefFontNameListName.Append('.');
prefFontNameListName.Append(langGroupStr);
// The font name list may have two or more family names as comma
// separated list. In such case, not matching with generic font
// name is fine because if the list prefers specific font, we
// should try to use the pref with complicated path.
fontlistValue = Preferences::GetString(prefFontNameListName.get());
}
if (fontlistValue) {
if (!fontlistValue.EqualsLiteral("serif") &&
!fontlistValue.EqualsLiteral("sans-serif") &&
@ -1781,6 +1793,11 @@ gfxFcPlatformFontList::PrefFontListsUseOnlyGenerics()
// Ex: font.name.serif.ar ==> "serif" (ok)
// Ex: font.name.serif.ar ==> "monospace" (return false)
// Ex: font.name.serif.ar ==> "DejaVu Serif" (return false)
// Ex: font.name.serif.ar ==> "" and
// font.name-list.serif.ar ==> "serif" (ok)
// Ex: font.name.serif.ar ==> "" and
// font.name-list.serif.ar ==> "Something, serif"
// (return false)
nsDependentCString prefName(names[i] +
ArrayLength(kFontNamePrefix) - 1);
@ -1788,6 +1805,17 @@ gfxFcPlatformFontList::PrefFontListsUseOnlyGenerics()
const nsDependentCSubstring& generic = tokenizer.nextToken();
const nsDependentCSubstring& langGroup = tokenizer.nextToken();
nsAdoptingCString fontPrefValue = Preferences::GetCString(names[i]);
if (fontPrefValue.IsEmpty()) {
nsAutoCString nameListPrefName(kFontNameListPrefix);
nameListPrefName.Append(generic);
nameListPrefName.Append('.');
nameListPrefName.Append(langGroup);
// The font name list may have two or more family names as comma
// separated list. In such case, not matching with generic font
// name is fine because if the list prefers specific font, this
// should return false.
fontPrefValue = Preferences::GetCString(nameListPrefName.get());
}
if (!langGroup.EqualsLiteral("x-math") &&
!generic.Equals(fontPrefValue)) {

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

@ -849,8 +849,10 @@ void gfxFontUtils::ParseFontList(const nsAString& aFamilyList,
fontname = Substring(nameStart, p);
fontname.CompressWhitespace(true, true);
// append it to the list
aFontList.AppendElement(fontname);
// append it to the list if it's not empty
if (!fontname.IsEmpty()) {
aFontList.AppendElement(fontname);
}
++p;
}
}

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

@ -413,6 +413,18 @@ GDIFontEntry::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
*
*/
static bool
ShouldIgnoreItalicStyle(const nsAString& aName)
{
// Ignore italic style's "Meiryo" because "Meiryo (Bold) Italic" has
// non-italic style glyphs as Japanese characters. However, using it
// causes serious problem if web pages wants some elements to be
// different style from others only with font-style. For example,
// <em> and <i> should be rendered as italic in the default style.
return aName.EqualsLiteral("Meiryo") ||
aName.Equals(NS_LITERAL_STRING(u"\x30E1\x30A4\x30EA\x30AA"));
}
int CALLBACK
GDIFontFamily::FamilyAddStylesProc(const ENUMLOGFONTEXW *lpelfe,
const NEWTEXTMETRICEXW *nmetrics,
@ -422,6 +434,10 @@ GDIFontFamily::FamilyAddStylesProc(const ENUMLOGFONTEXW *lpelfe,
LOGFONTW logFont = lpelfe->elfLogFont;
GDIFontFamily *ff = reinterpret_cast<GDIFontFamily*>(data);
if (logFont.lfItalic && ShouldIgnoreItalicStyle(ff->mName)) {
return 1;
}
// Some fonts claim to support things > 900, but we don't so clamp the sizes
logFont.lfWeight = clamped(logFont.lfWeight, LONG(100), LONG(900));
@ -531,14 +547,23 @@ GDIFontFamily::FindStyleVariations(FontInfoData *aFontInfoData)
// check for existence of italic face(s); if present, set the
// FamilyHasItalic flag on all faces so that we'll know *not*
// to use GDI's fake-italic effect with them
size_t count = mAvailableFonts.Length();
for (size_t i = 0; i < count; ++i) {
if (mAvailableFonts[i]->IsItalic()) {
for (uint32_t j = 0; j < count; ++j) {
static_cast<GDIFontEntry*>(mAvailableFonts[j].get())->
mFamilyHasItalicFace = true;
// If we ignored italic face(s), we should mark this has italic face.
bool hasItalicFace = ShouldIgnoreItalicStyle(mName);
if (!hasItalicFace) {
for (RefPtr<gfxFontEntry>& fontEntry : mAvailableFonts) {
if (fontEntry->IsItalic()) {
hasItalicFace = true;
break;
}
break;
}
}
if (hasItalicFace) {
for (RefPtr<gfxFontEntry>& fontEntry : mAvailableFonts) {
static_cast<GDIFontEntry*>(fontEntry.get())->
mFamilyHasItalicFace = true;
}
}
}

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

@ -1550,6 +1550,20 @@ gfxPlatform::GetStandardFamilyName(const nsAString& aFontName,
return NS_OK;
}
nsString
gfxPlatform::GetDefaultFontName(const nsACString& aLangGroup,
const nsACString& aGenericFamily)
{
gfxFontFamily* fontFamily = gfxPlatformFontList::PlatformFontList()->
GetDefaultFontFamily(aLangGroup, aGenericFamily);
if (!fontFamily) {
return EmptyString();
}
nsAutoString result;
fontFamily->LocalizedName(result);
return result;
}
bool
gfxPlatform::DownloadableFontsEnabled()
{

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

@ -355,6 +355,16 @@ public:
*/
virtual nsresult GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName);
/**
* Returns default font name (localized family name) for aLangGroup and
* aGenericFamily. The result is typically the first font in
* font.name-list.<aGenericFamily>.<aLangGroup>. However, if it's not
* available in the system, this may return second or later font in the
* pref. If there are no available fonts in the pref, returns empty string.
*/
nsString GetDefaultFontName(const nsACString& aLangGroup,
const nsACString& aGenericFamily);
/**
* Create the appropriate platform font group
*/

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

@ -793,6 +793,31 @@ gfxPlatformFontList::GetStandardFamilyName(const nsAString& aFontName, nsAString
return true;
}
gfxFontFamily*
gfxPlatformFontList::GetDefaultFontFamily(const nsACString& aLangGroup,
const nsACString& aGenericFamily)
{
if (NS_WARN_IF(aLangGroup.IsEmpty()) ||
NS_WARN_IF(aGenericFamily.IsEmpty())) {
return nullptr;
}
AutoTArray<nsString,4> names;
nsAutoCString prefName("font.name-list.");
prefName.Append(aGenericFamily);
prefName.Append('.');
prefName.Append(aLangGroup);
gfxFontUtils::AppendPrefsFontList(prefName.get(), names);
for (nsString& name : names) {
gfxFontFamily* fontFamily = FindFamily(name);
if (fontFamily) {
return fontFamily;
}
}
return nullptr;
}
gfxCharacterMap*
gfxPlatformFontList::FindCharMap(gfxCharacterMap *aCmap)
{

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

@ -176,6 +176,12 @@ public:
// (platforms may override, eg Mac)
virtual bool GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName);
// get the default font name which is available on the system from
// font.name-list.*. if there are no available fonts in the pref,
// returns nullptr.
gfxFontFamily* GetDefaultFontFamily(const nsACString& aLangGroup,
const nsACString& aGenericFamily);
virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
FontListSizes* aSizes) const;
virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,

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

@ -5771,25 +5771,21 @@ IonBuilder::compareTrySharedStub(bool* emitted, JSOp op, MDefinition* left, MDef
return Ok();
}
static bool
IsCallOpcode(JSOp op)
{
// TODO: Support tracking optimizations for inlining a call and regular
// optimization tracking at the same time.
return op == JSOP_CALL || op == JSOP_CALL_IGNORES_RV || op == JSOP_CALLITER || op == JSOP_NEW ||
op == JSOP_SUPERCALL || op == JSOP_EVAL || op == JSOP_STRICTEVAL;
}
AbortReasonOr<Ok>
IonBuilder::newArrayTryTemplateObject(bool* emitted, JSObject* templateObject, uint32_t length)
{
MOZ_ASSERT(*emitted == false);
if (!IsCallOpcode(JSOp(*pc)))
// TODO: Support tracking optimizations for inlining a call and regular
// optimization tracking at the same time. Currently just drop optimization
// tracking when that happens.
bool canTrackOptimization = !IsCallPC(pc);
if (canTrackOptimization)
trackOptimizationAttempt(TrackedStrategy::NewArray_TemplateObject);
if (!templateObject) {
if (!IsCallOpcode(JSOp(*pc)))
if (canTrackOptimization)
trackOptimizationOutcome(TrackedOutcome::NoTemplateObject);
return Ok();
}
@ -5797,7 +5793,7 @@ IonBuilder::newArrayTryTemplateObject(bool* emitted, JSObject* templateObject, u
if (templateObject->is<UnboxedArrayObject>()) {
MOZ_ASSERT(templateObject->as<UnboxedArrayObject>().capacity() >= length);
if (!templateObject->as<UnboxedArrayObject>().hasInlineElements()) {
if (!IsCallOpcode(JSOp(*pc)))
if (canTrackOptimization)
trackOptimizationOutcome(TrackedOutcome::TemplateObjectIsUnboxedWithoutInlineElements);
return Ok();
}
@ -5809,7 +5805,7 @@ IonBuilder::newArrayTryTemplateObject(bool* emitted, JSObject* templateObject, u
gc::GetGCKindSlots(templateObject->asTenured().getAllocKind()) - ObjectElements::VALUES_PER_HEADER;
if (length > arraySlots) {
if (!IsCallOpcode(JSOp(*pc)))
if (canTrackOptimization)
trackOptimizationOutcome(TrackedOutcome::LengthTooBig);
return Ok();
}
@ -5824,7 +5820,7 @@ IonBuilder::newArrayTryTemplateObject(bool* emitted, JSObject* templateObject, u
current->add(ins);
current->push(ins);
if (!IsCallOpcode(JSOp(*pc)))
if (canTrackOptimization)
trackOptimizationSuccess();
*emitted = true;
return Ok();
@ -5835,6 +5831,11 @@ IonBuilder::newArrayTrySharedStub(bool* emitted)
{
MOZ_ASSERT(*emitted == false);
// TODO: Support tracking optimizations for inlining a call and regular
// optimization tracking at the same time. Currently just drop optimization
// tracking when that happens.
bool canTrackOptimization = !IsCallPC(pc);
// Try to emit a shared stub cache.
if (JitOptions.disableSharedStubs)
@ -5843,7 +5844,7 @@ IonBuilder::newArrayTrySharedStub(bool* emitted)
if (*pc != JSOP_NEWINIT && *pc != JSOP_NEWARRAY)
return Ok();
if (!IsCallOpcode(JSOp(*pc)))
if (canTrackOptimization)
trackOptimizationAttempt(TrackedStrategy::NewArray_SharedCache);
MInstruction* stub = MNullarySharedStub::New(alloc());
@ -5856,7 +5857,7 @@ IonBuilder::newArrayTrySharedStub(bool* emitted)
current->add(unbox);
current->push(unbox);
if (!IsCallOpcode(JSOp(*pc)))
if (canTrackOptimization)
trackOptimizationSuccess();
*emitted = true;
@ -5868,8 +5869,13 @@ IonBuilder::newArrayTryVM(bool* emitted, JSObject* templateObject, uint32_t leng
{
MOZ_ASSERT(*emitted == false);
// TODO: Support tracking optimizations for inlining a call and regular
// optimization tracking at the same time. Currently just drop optimization
// tracking when that happens.
bool canTrackOptimization = !IsCallPC(pc);
// Emit a VM call.
if (!IsCallOpcode(JSOp(*pc)))
if (canTrackOptimization)
trackOptimizationAttempt(TrackedStrategy::NewArray_Call);
gc::InitialHeap heap = gc::DefaultHeap;
@ -5886,7 +5892,7 @@ IonBuilder::newArrayTryVM(bool* emitted, JSObject* templateObject, uint32_t leng
current->add(ins);
current->push(ins);
if (!IsCallOpcode(JSOp(*pc)))
if (canTrackOptimization)
trackOptimizationSuccess();
*emitted = true;
return Ok();
@ -5911,8 +5917,13 @@ IonBuilder::jsop_newarray(uint32_t length)
AbortReasonOr<Ok>
IonBuilder::jsop_newarray(JSObject* templateObject, uint32_t length)
{
// TODO: Support tracking optimizations for inlining a call and regular
// optimization tracking at the same time. Currently just drop optimization
// tracking when that happens.
bool canTrackOptimization = !IsCallPC(pc);
bool emitted = false;
if (!IsCallOpcode(JSOp(*pc)))
if (canTrackOptimization)
startTrackingOptimizations();
if (!forceInlineCaches()) {
@ -5959,16 +5970,21 @@ IonBuilder::newObjectTryTemplateObject(bool* emitted, JSObject* templateObject)
{
MOZ_ASSERT(*emitted == false);
if (!IsCallOpcode(JSOp(*pc)))
// TODO: Support tracking optimizations for inlining a call and regular
// optimization tracking at the same time. Currently just drop optimization
// tracking when that happens.
bool canTrackOptimization = !IsCallPC(pc);
if (canTrackOptimization)
trackOptimizationAttempt(TrackedStrategy::NewObject_TemplateObject);
if (!templateObject) {
if (!IsCallOpcode(JSOp(*pc)))
if (canTrackOptimization)
trackOptimizationOutcome(TrackedOutcome::NoTemplateObject);
return Ok();
}
if (templateObject->is<PlainObject>() && templateObject->as<PlainObject>().hasDynamicSlots()) {
if (!IsCallOpcode(JSOp(*pc)))
if (canTrackOptimization)
trackOptimizationOutcome(TrackedOutcome::TemplateObjectIsPlainObjectWithDynamicSlots);
return Ok();
}
@ -5991,7 +6007,7 @@ IonBuilder::newObjectTryTemplateObject(bool* emitted, JSObject* templateObject)
MOZ_TRY(resumeAfter(ins));
if (!IsCallOpcode(JSOp(*pc)))
if (canTrackOptimization)
trackOptimizationSuccess();
*emitted = true;
return Ok();
@ -6002,12 +6018,17 @@ IonBuilder::newObjectTrySharedStub(bool* emitted)
{
MOZ_ASSERT(*emitted == false);
// TODO: Support tracking optimizations for inlining a call and regular
// optimization tracking at the same time. Currently just drop optimization
// tracking when that happens.
bool canTrackOptimization = !IsCallPC(pc);
// Try to emit a shared stub cache.
if (JitOptions.disableSharedStubs)
return Ok();
if (!IsCallOpcode(JSOp(*pc)))
if (canTrackOptimization)
trackOptimizationAttempt(TrackedStrategy::NewObject_SharedCache);
MInstruction* stub = MNullarySharedStub::New(alloc());
@ -6020,7 +6041,7 @@ IonBuilder::newObjectTrySharedStub(bool* emitted)
current->add(unbox);
current->push(unbox);
if (!IsCallOpcode(JSOp(*pc)))
if (canTrackOptimization)
trackOptimizationSuccess();
*emitted = true;
return Ok();
@ -6032,8 +6053,7 @@ IonBuilder::newObjectTryVM(bool* emitted, JSObject* templateObject)
// Emit a VM call.
MOZ_ASSERT(JSOp(*pc) == JSOP_NEWOBJECT || JSOp(*pc) == JSOP_NEWINIT);
if (!IsCallOpcode(JSOp(*pc)))
trackOptimizationAttempt(TrackedStrategy::NewObject_Call);
trackOptimizationAttempt(TrackedStrategy::NewObject_Call);
gc::InitialHeap heap = gc::DefaultHeap;
MConstant* templateConst = MConstant::New(alloc(), NullValue());
@ -6052,8 +6072,7 @@ IonBuilder::newObjectTryVM(bool* emitted, JSObject* templateObject)
MOZ_TRY(resumeAfter(ins));
if (!IsCallOpcode(JSOp(*pc)))
trackOptimizationSuccess();
trackOptimizationSuccess();
*emitted = true;
return Ok();
}

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

@ -8,6 +8,7 @@
#include "mozilla/IntegerPrintfMacros.h"
#include "mozilla/SizePrintfMacros.h"
#include <cfloat>
#include <stdarg.h>
#include "jsprf.h"
@ -61,6 +62,10 @@ BEGIN_TEST(testPrintf)
CHECK(print_one("1.500000", "%f", 1.5f));
CHECK(print_one("1.5", "%g", 1.5));
// Regression test for bug#1350097. The bug was an assertion
// failure caused by printing a very long floating point value.
print_one("ignore", "%lf", DBL_MAX);
CHECK(print_one("2727", "%" PRIu32, (uint32_t) 2727));
CHECK(print_one("aa7", "%" PRIx32, (uint32_t) 2727));
CHECK(print_one("2727", "%" PRIu64, (uint64_t) 2727));

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

@ -191,6 +191,7 @@ StaticPresData::GetFontPrefsForLangHelper(nsIAtom *aLanguage,
// set the default variable font (the other fonts are seen as 'generic' fonts
// in GFX and will be queried there when hunting for alternative fonts)
if (eType == eDefaultFont_Variable) {
// XXX "font.name.variable."? There is no such pref...
MAKE_FONT_PREF_KEY(pref, "font.name.variable.", langGroup);
nsAdoptingString value = Preferences::GetString(pref.get());

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

@ -1803,7 +1803,7 @@ fails == 942672-1.html 942672-1.html
== 953334-win32-clipping.html 953334-win32-clipping.html
fuzzy-if(skiaContent,1,5) == 956513-1.svg 956513-1.svg
== 944291-1.html 944291-1.html
fails == 950436-1.html 950436-1.html
== 950436-1.html 950436-1.html
== 957770-1.svg 957770-1.svg
fails == 960277-1.html 960277-1.html
== 961887-1.html 961887-1.html

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

@ -0,0 +1,9 @@
<!DOCTYPE HTML><html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css">
body { margin: 50px; font-size: 72pt; }
#test { font-family: "Meiryo"; font-weight: bold; font-style: normal; }
</style>
</head>
<body><p id="test">魅力的な人</p></body>
</html>

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

@ -0,0 +1,9 @@
<!DOCTYPE HTML><html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css">
body { margin: 50px; font-size: 72pt; }
#test { font-family: "Meiryo"; font-weight: bold; font-style: italic; }
</style>
</head>
<body><p id="test">魅力的な人</p></body>
</html>

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

@ -0,0 +1,9 @@
<!DOCTYPE HTML><html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css">
body { margin: 50px; font-size: 72pt; }
#test { font-family: "Meiryo"; font-weight: normal; font-style: italic; }
</style>
</head>
<body><p id="test">魅力的な人</p></body>
</html>

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

@ -0,0 +1,9 @@
<!DOCTYPE HTML><html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css">
body { margin: 50px; font-size: 72pt; }
#test { font-family: "Meiryo"; font-style: oblique; }
</style>
</head>
<body><p id="test">魅力的な人</p></body>
</html>

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

@ -0,0 +1,9 @@
<!DOCTYPE HTML><html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css">
body { margin: 50px; font-size: 72pt; }
#test { font-family: "Meiryo"; font-weight: normal; font-style: normal; }
</style>
</head>
<body><p id="test">魅力的な人</p></body>
</html>

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

@ -0,0 +1,9 @@
<!DOCTYPE HTML><html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css">
body { margin: 50px; font-size: 72pt; }
#test { font-family: "メイリオ"; font-weight: bold; font-style: normal; }
</style>
</head>
<body><p id="test">魅力的な人</p></body>
</html>

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

@ -0,0 +1,9 @@
<!DOCTYPE HTML><html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css">
body { margin: 50px; font-size: 72pt; }
#test { font-family: "メイリオ"; font-weight: bold; font-style: italic; }
</style>
</head>
<body><p id="test">魅力的な人</p></body>
</html>

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

@ -0,0 +1,9 @@
<!DOCTYPE HTML><html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css">
body { margin: 50px; font-size: 72pt; }
#test { font-family: "メイリオ"; font-weight: normal; font-style: italic; }
</style>
</head>
<body><p id="test">魅力的な人</p></body>
</html>

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

@ -0,0 +1,9 @@
<!DOCTYPE HTML><html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css">
body { margin: 50px; font-size: 72pt; }
#test { font-family: "メイリオ"; font-style: oblique; }
</style>
</head>
<body><p id="test">魅力的な人</p></body>
</html>

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

@ -0,0 +1,9 @@
<!DOCTYPE HTML><html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css">
body { margin: 50px; font-size: 72pt; }
#test { font-family: "メイリオ"; font-weight: normal; font-style: normal; }
</style>
</head>
<body><p id="test">魅力的な人</p></body>
</html>

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

@ -184,3 +184,14 @@ HTTP(..) == reflow-sanity-delay-1-metrics.html reflow-sanity-1-ref.html
pref(layout.css.font-display.enabled,true) HTTP(..) == font-display-1.html font-display-1-ref.html # normal font load (~500ms)
pref(layout.css.font-display.enabled,true) fuzzy-if(OSX==1010,3,5) HTTP(..) == font-display-2.html font-display-2-ref.html # font load takes 4500ms
# Testing hack for Meiryo
== meiryo-en.html meiryo-ja.html
== meiryo-en-bold.html meiryo-ja-bold.html
== meiryo-en-italic.html meiryo-ja-italic.html
== meiryo-en-oblique.html meiryo-ja-oblique.html
== meiryo-en-bolditalic.html meiryo-ja-bolditalic.html
!= meiryo-en-bold.html meiryo-en.html
!= meiryo-en-italic.html meiryo-en.html
!= meiryo-en-oblique.html meiryo-en.html
!= meiryo-en-bolditalic.html meiryo-en.html
!= meiryo-en-bolditalic.html meiryo-en-bold.html

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

@ -101,7 +101,7 @@ default-preferences pref(layout.css.variables.enabled,true)
== variable-reference-33.html variable-reference-33.html
== variable-reference-34.html variable-reference-34.html
== variable-reference-35.html variable-reference-35.html
fails == variable-reference-36.html variable-reference-36.html
== variable-reference-36.html variable-reference-36.html
== variable-reference-37.html variable-reference-37.html
== variable-reference-38.html variable-reference-38.html
== variable-reference-39.html variable-reference-39.html

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

@ -31,7 +31,6 @@
#include "nsError.h"
#include "nsCSSParser.h"
#include "mozilla/css/Loader.h"
#include "nsICSSLoaderObserver.h"
#include "nsNameSpaceManager.h"
#include "nsXMLNameSpaceMap.h"
#include "nsCOMPtr.h"
@ -442,8 +441,7 @@ CSSStyleSheet::TraverseInner(nsCycleCollectionTraversalCallback &cb)
// QueryInterface implementation for CSSStyleSheet
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(CSSStyleSheet)
NS_INTERFACE_MAP_ENTRY(nsICSSLoaderObserver)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, StyleSheet)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMCSSStyleSheet)
if (aIID.Equals(NS_GET_IID(CSSStyleSheet)))
foundInterface = reinterpret_cast<nsISupports*>(this);
else

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

@ -19,7 +19,6 @@
#include "nscore.h"
#include "nsCOMPtr.h"
#include "nsAutoPtr.h"
#include "nsICSSLoaderObserver.h"
#include "nsTArrayForwardDeclare.h"
#include "nsString.h"
#include "mozilla/CORSMode.h"
@ -87,7 +86,6 @@ struct CSSStyleSheetInner : public StyleSheetInfo
class CSSStyleSheet final : public StyleSheet
, public nsICSSLoaderObserver
{
public:
typedef net::ReferrerPolicy ReferrerPolicy;

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

@ -1411,24 +1411,21 @@ nsresult
Loader::InsertChildSheet(StyleSheet* aSheet,
StyleSheet* aParentSheet,
ImportRule* aGeckoParentRule,
const RawServoImportRule* aServoParentRule)
const RawServoStyleSheet* aServoChildSheet)
{
LOG(("css::Loader::InsertChildSheet"));
MOZ_ASSERT(aSheet, "Nothing to insert");
MOZ_ASSERT(aParentSheet, "Need a parent to insert into");
MOZ_ASSERT_IF(aSheet->IsGecko(), aGeckoParentRule && !aServoParentRule);
MOZ_ASSERT_IF(aSheet->IsServo(), aServoParentRule && !aGeckoParentRule);
MOZ_ASSERT_IF(aSheet->IsGecko(), aGeckoParentRule && !aServoChildSheet);
MOZ_ASSERT_IF(aSheet->IsServo(), aServoChildSheet && !aGeckoParentRule);
if (aSheet->IsGecko()) {
// child sheets should always start out enabled, even if they got
// cloned off of top-level sheets which were disabled
aSheet->AsGecko()->SetEnabled(true);
aGeckoParentRule->SetSheet(aSheet->AsGecko()); // This sets the ownerRule on the sheet
} else {
// No matter what, consume the sheet, but we might not use it.
RefPtr<RawServoStyleSheet> sheet =
Servo_ImportRule_GetSheet(aServoParentRule).Consume();
if (!aSheet->AsServo()->RawSheet()) {
aSheet->AsServo()->SetSheetForImport(sheet);
aSheet->AsServo()->SetSheetForImport(aServoChildSheet);
}
}
aParentSheet->AppendStyleSheet(aSheet);
@ -2207,7 +2204,7 @@ Loader::LoadChildSheet(StyleSheet* aParentSheet,
nsIURI* aURL,
nsMediaList* aMedia,
ImportRule* aGeckoParentRule,
const RawServoImportRule* aServoParentRule,
const RawServoStyleSheet* aServoChildSheet,
LoaderReusableStyleSheets* aReusableSheets)
{
LOG(("css::Loader::LoadChildSheet"));
@ -2216,8 +2213,8 @@ Loader::LoadChildSheet(StyleSheet* aParentSheet,
// Servo doesn't support reusable sheets.
MOZ_ASSERT_IF(aReusableSheets, aParentSheet->IsGecko());
MOZ_ASSERT_IF(aParentSheet->IsGecko(), aGeckoParentRule && !aServoParentRule);
MOZ_ASSERT_IF(aParentSheet->IsServo(), aServoParentRule && !aGeckoParentRule);
MOZ_ASSERT_IF(aParentSheet->IsGecko(), aGeckoParentRule && !aServoChildSheet);
MOZ_ASSERT_IF(aParentSheet->IsServo(), aServoChildSheet && !aGeckoParentRule);
if (!mEnabled) {
LOG_WARN((" Not enabled"));
@ -2272,10 +2269,7 @@ Loader::LoadChildSheet(StyleSheet* aParentSheet,
LOG((" No parent load; must be CSSOM"));
// No parent load data, so the sheet will need to be notified when
// we finish, if it can be, if we do the load asynchronously.
// XXXheycam ServoStyleSheet doesn't implement nsICSSLoaderObserver yet.
MOZ_ASSERT(aParentSheet->IsGecko(),
"stylo: ServoStyleSheets don't support child sheet loading yet");
observer = aParentSheet->AsGecko();
observer = aParentSheet;
}
// Now that we know it's safe to load this (passes security check and not a
@ -2303,7 +2297,7 @@ Loader::LoadChildSheet(StyleSheet* aParentSheet,
}
rv = InsertChildSheet(sheet, aParentSheet, aGeckoParentRule,
aServoParentRule);
aServoChildSheet);
NS_ENSURE_SUCCESS(rv, rv);
if (state == eSheetComplete) {

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

@ -293,8 +293,8 @@ public:
* @param aGeckoParentRule the @import rule importing this child, when using
* Gecko's style system. This is used to properly
* order the child sheet list of aParentSheet.
* @param aServoParentRule the @import rule importing this child, when using
* Servo's style system.
* @param aServoChildSheet the child stylesheet of the @import rule, when
* using Servo's style system.
* @param aSavedSheets any saved style sheets which could be reused
* for this load
*/
@ -302,7 +302,7 @@ public:
nsIURI* aURL,
nsMediaList* aMedia,
ImportRule* aGeckoParentRule,
const RawServoImportRule* aServoParentRule,
const RawServoStyleSheet* aServoChildSheet,
LoaderReusableStyleSheets* aSavedSheets);
/**
@ -520,7 +520,7 @@ private:
nsresult InsertChildSheet(StyleSheet* aSheet,
StyleSheet* aParentSheet,
ImportRule* aGeckoParentRule,
const RawServoImportRule* aServoParentRule);
const RawServoStyleSheet* aServoChildSheet);
nsresult InternalLoadNonDocumentSheet(nsIURI* aURL,
bool aIsPreload,

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

@ -29,7 +29,6 @@ SERVO_BINDING_FUNC(Servo_StyleSheet_FromUTF8Bytes, RawServoStyleSheetStrong,
mozilla::ServoStyleSheet* gecko_stylesheet,
const nsACString* data,
mozilla::css::SheetParsingMode parsing_mode,
const nsACString* base_url,
RawGeckoURLExtraData* extra_data)
SERVO_BINDING_FUNC(Servo_ImportRule_GetSheet,
RawServoStyleSheetStrong,
@ -78,7 +77,9 @@ SERVO_BINDING_FUNC(Servo_CssRules_ListTypes, void,
SERVO_BINDING_FUNC(Servo_CssRules_InsertRule, nsresult,
ServoCssRulesBorrowed rules,
RawServoStyleSheetBorrowed sheet, const nsACString* rule,
uint32_t index, bool nested, uint16_t* rule_type)
uint32_t index, bool nested, mozilla::css::Loader* loader,
mozilla::ServoStyleSheet* gecko_stylesheet,
uint16_t* rule_type)
SERVO_BINDING_FUNC(Servo_CssRules_DeleteRule, nsresult,
ServoCssRulesBorrowed rules, uint32_t index)
@ -117,11 +118,9 @@ SERVO_BINDING_FUNC(Servo_NamespaceRule_GetURI, nsIAtom*,
SERVO_BINDING_FUNC(Servo_ParseProperty,
RawServoDeclarationBlockStrong,
const nsACString* property, const nsACString* value,
const nsACString* base,
RawGeckoURLExtraData* data)
SERVO_BINDING_FUNC(Servo_ParseEasing, bool,
const nsAString* easing,
const nsACString* base,
RawGeckoURLExtraData* data,
nsTimingFunctionBorrowedMut output)
SERVO_BINDING_FUNC(Servo_GetComputedKeyframeValues, void,
@ -157,7 +156,6 @@ SERVO_BINDING_FUNC(Servo_AnimationValue_DeepEqual, bool,
// Style attribute
SERVO_BINDING_FUNC(Servo_ParseStyleAttribute, RawServoDeclarationBlockStrong,
const nsACString* data,
const nsACString* base,
RawGeckoURLExtraData* extra_data)
SERVO_BINDING_FUNC(Servo_DeclarationBlock_CreateEmpty,
RawServoDeclarationBlockStrong)
@ -190,13 +188,11 @@ SERVO_BINDING_FUNC(Servo_DeclarationBlock_SetProperty, bool,
RawServoDeclarationBlockBorrowed declarations,
const nsACString* property,
const nsACString* value, bool is_important,
const nsACString* base,
RawGeckoURLExtraData* data)
SERVO_BINDING_FUNC(Servo_DeclarationBlock_SetPropertyById, bool,
RawServoDeclarationBlockBorrowed declarations,
nsCSSPropertyID property,
const nsACString* value, bool is_important,
const nsACString* base,
RawGeckoURLExtraData* data)
SERVO_BINDING_FUNC(Servo_DeclarationBlock_RemoveProperty, void,
RawServoDeclarationBlockBorrowed declarations,

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

@ -7,6 +7,7 @@
#include "mozilla/ServoBindings.h"
#include "ChildIterator.h"
#include "NullPrincipalURI.h"
#include "gfxFontFamilyList.h"
#include "nsAnimationManager.h"
#include "nsAttrValueInlines.h"
@ -1536,7 +1537,7 @@ Gecko_nsStyleFont_GetBaseSize(const nsStyleFont* aFont, RawGeckoPresContextBorro
void
Gecko_LoadStyleSheet(css::Loader* aLoader,
ServoStyleSheet* aParent,
RawServoImportRuleBorrowed aImportRule,
RawServoStyleSheetBorrowed aChildSheet,
RawGeckoURLExtraData* aBaseURLData,
const uint8_t* aURLString,
uint32_t aURLStringLength,
@ -1574,7 +1575,16 @@ Gecko_LoadStyleSheet(css::Loader* aLoader,
return;
}
aLoader->LoadChildSheet(aParent, uri, media, nullptr, aImportRule, nullptr);
aLoader->LoadChildSheet(aParent, uri, media, nullptr, aChildSheet, nullptr);
}
RawGeckoURLExtraData*
Gecko_URLExtraData_CreateDummy()
{
RefPtr<css::URLExtraData> data =
new css::URLExtraData(NullPrincipalURI::Create(), nullptr,
NullPrincipal::Create());
return data.forget().take();
}
const nsMediaFeature*

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

@ -111,13 +111,17 @@ RawGeckoElementBorrowedOrNull Gecko_GetNextSiblingElement(RawGeckoElementBorrowe
RawGeckoElementBorrowedOrNull Gecko_GetDocumentElement(RawGeckoDocumentBorrowed document);
void Gecko_LoadStyleSheet(mozilla::css::Loader* loader,
mozilla::ServoStyleSheet* parent,
RawServoImportRuleBorrowed import_rule,
RawServoStyleSheetBorrowed child_sheet,
RawGeckoURLExtraData* base_url_data,
const uint8_t* url_bytes,
uint32_t url_length,
const uint8_t* media_bytes,
uint32_t media_length);
// URLExtraData
// Create a new addrefed URLExtraData.
RawGeckoURLExtraData* Gecko_URLExtraData_CreateDummy();
// By default, Servo walks the DOM by traversing the siblings of the DOM-view
// first child. This generally works, but misses anonymous children, which we
// want to traverse during styling. To support these cases, we create an

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

@ -160,11 +160,18 @@ ServoCSSRuleList::DropReference()
nsresult
ServoCSSRuleList::InsertRule(const nsAString& aRule, uint32_t aIndex)
{
MOZ_ASSERT(mStyleSheet, "Caller must ensure that "
"the list is not unlinked from stylesheet");
NS_ConvertUTF16toUTF8 rule(aRule);
bool nested = !!mParentRule;
css::Loader* loader = nullptr;
if (nsIDocument* doc = mStyleSheet->GetAssociatedDocument()) {
loader = doc->CSSLoader();
}
uint16_t type;
nsresult rv = Servo_CssRules_InsertRule(mRawRules, mStyleSheet->RawSheet(),
&rule, aIndex, nested, &type);
&rule, aIndex, nested,
loader, mStyleSheet, &type);
if (!NS_FAILED(rv)) {
mRules.InsertElementAt(aIndex, type);
}
@ -185,6 +192,16 @@ ServoCSSRuleList::DeleteRule(uint32_t aIndex)
return rv;
}
uint16_t
ServoCSSRuleList::GetRuleType(uint32_t aIndex) const
{
uintptr_t rule = mRules[aIndex];
if (rule <= kMaxRuleType) {
return rule;
}
return CastToPtr(rule)->Type();
}
ServoCSSRuleList::~ServoCSSRuleList()
{
DropAllRules();

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

@ -42,6 +42,8 @@ public:
nsresult InsertRule(const nsAString& aRule, uint32_t aIndex);
nsresult DeleteRule(uint32_t aIndex);
uint16_t GetRuleType(uint32_t aIndex) const;
private:
virtual ~ServoCSSRuleList();

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

@ -16,11 +16,9 @@ ServoDeclarationBlock::FromCssText(const nsAString& aCssText,
css::URLExtraData* aExtraData)
{
NS_ConvertUTF16toUTF8 value(aCssText);
nsCString baseString;
// FIXME (bug 1343964): Figure out a better solution for sending the base uri to servo
aExtraData->BaseURI()->GetSpec(baseString);
RefPtr<RawServoDeclarationBlock>
raw = Servo_ParseStyleAttribute(&value, &baseString, aExtraData).Consume();
raw = Servo_ParseStyleAttribute(&value, aExtraData).Consume();
RefPtr<ServoDeclarationBlock> decl = new ServoDeclarationBlock(raw.forget());
return decl.forget();
}

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

@ -90,15 +90,11 @@ ServoStyleSheet::ParseSheet(css::Loader* aLoader,
RefPtr<css::URLExtraData> extraData =
new css::URLExtraData(aBaseURI, aSheetURI, aSheetPrincipal);
nsCString baseString;
nsresult rv = aBaseURI->GetSpec(baseString);
NS_ENSURE_SUCCESS(rv, rv);
NS_ConvertUTF16toUTF8 input(aInput);
if (!Inner()->mSheet) {
Inner()->mSheet =
Servo_StyleSheet_FromUTF8Bytes(aLoader, this, &input, mParsingMode,
&baseString, extraData).Consume();
Servo_StyleSheet_FromUTF8Bytes(aLoader, this, &input,
mParsingMode, extraData).Consume();
} else {
Servo_StyleSheet_ClearAndUpdate(Inner()->mSheet, aLoader,
this, &input, extraData);
@ -113,6 +109,31 @@ ServoStyleSheet::LoadFailed()
Inner()->mSheet = Servo_StyleSheet_Empty(mParsingMode).Consume();
}
// nsICSSLoaderObserver implementation
NS_IMETHODIMP
ServoStyleSheet::StyleSheetLoaded(StyleSheet* aSheet,
bool aWasAlternate,
nsresult aStatus)
{
MOZ_ASSERT(aSheet->IsServo(),
"why we were called back with a CSSStyleSheet?");
ServoStyleSheet* sheet = aSheet->AsServo();
if (sheet->GetParentSheet() == nullptr) {
return NS_OK; // ignore if sheet has been detached already
}
NS_ASSERTION(this == sheet->GetParentSheet(),
"We are being notified of a sheet load for a sheet that is not our child!");
if (mDocument && NS_SUCCEEDED(aStatus)) {
mozAutoDocUpdate updateBatch(mDocument, UPDATE_STYLE, true);
NS_WARNING("stylo: Import rule object not implemented");
mDocument->StyleRuleAdded(this, nullptr);
}
return NS_OK;
}
void
ServoStyleSheet::DropRuleList()
{
@ -167,9 +188,9 @@ ServoStyleSheet::InsertRuleInternal(const nsAString& aRule,
if (aRv.Failed()) {
return 0;
}
// XXX If the inserted rule is an import rule, we should only notify
// the document if its associated child stylesheet has been loaded.
if (mDocument) {
// XXX When we support @import rules, we should not notify here,
// but rather when the sheet the rule is importing is loaded.
// XXX We may not want to get the rule when stylesheet change event
// is not enabled.
mDocument->StyleRuleAdded(this, mRuleList->GetRule(aIndex));

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

@ -32,7 +32,7 @@ struct ServoStyleSheetInner : public StyleSheetInfo
ReferrerPolicy aReferrerPolicy,
const dom::SRIMetadata& aIntegrity);
RefPtr<RawServoStyleSheet> mSheet;
RefPtr<const RawServoStyleSheet> mSheet;
};
@ -66,10 +66,10 @@ public:
*/
void LoadFailed();
RawServoStyleSheet* RawSheet() const {
const RawServoStyleSheet* RawSheet() const {
return Inner()->mSheet;
}
void SetSheetForImport(RawServoStyleSheet* aSheet) {
void SetSheetForImport(const RawServoStyleSheet* aSheet) {
MOZ_ASSERT(!Inner()->mSheet);
Inner()->mSheet = aSheet;
}
@ -90,6 +90,10 @@ public:
nsIDocument* aCloneDocument,
nsINode* aCloneOwningNode) const final;
// nsICSSLoaderObserver interface
NS_IMETHOD StyleSheetLoaded(StyleSheet* aSheet, bool aWasAlternate,
nsresult aStatus) final;
protected:
virtual ~ServoStyleSheet();

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

@ -118,6 +118,7 @@ StyleSheet::TraverseInner(nsCycleCollectionTraversalCallback &cb)
// QueryInterface implementation for StyleSheet
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(StyleSheet)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsICSSLoaderObserver)
NS_INTERFACE_MAP_ENTRY(nsIDOMStyleSheet)
NS_INTERFACE_MAP_ENTRY(nsIDOMCSSStyleSheet)
NS_INTERFACE_MAP_END

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

@ -14,6 +14,7 @@
#include "mozilla/CORSMode.h"
#include "mozilla/ServoUtils.h"
#include "nsICSSLoaderObserver.h"
#include "nsIDOMCSSStyleSheet.h"
#include "nsWrapperCache.h"
@ -45,6 +46,7 @@ class Rule;
* Superclass for data common to CSSStyleSheet and ServoStyleSheet.
*/
class StyleSheet : public nsIDOMCSSStyleSheet
, public nsICSSLoaderObserver
, public nsWrapperCache
{
protected:
@ -56,7 +58,8 @@ protected:
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(StyleSheet)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(StyleSheet,
nsIDOMCSSStyleSheet)
void SetOwningNode(nsINode* aOwningNode)
{

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

@ -89,7 +89,7 @@ StyleSheet::GetParentObject() const
if (mOwningNode) {
return dom::ParentObject(mOwningNode);
}
return dom::ParentObject(GetParentSheet());
return dom::ParentObject(static_cast<nsIDOMCSSStyleSheet*>(mParent), mParent);
}
nsIPrincipal*

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

@ -308,13 +308,11 @@ nsDOMCSSDeclaration::ParsePropertyValue(const nsCSSPropertyID aPropID,
decl->AsGecko(), &changed, aIsImportant);
} else {
NS_ConvertUTF16toUTF8 value(aPropValue);
// FIXME (bug 1343964): Figure out a better solution for sending the base uri to servo
RefPtr<css::URLExtraData> data =
new css::URLExtraData(env.mBaseURI, env.mSheetURI, env.mPrincipal);
nsCString baseString;
// FIXME (bug 1343964): Figure out a better solution for sending the base uri to servo
env.mBaseURI->GetSpec(baseString);
changed = Servo_DeclarationBlock_SetPropertyById(
decl->AsServo()->Raw(), aPropID, &value, aIsImportant, &baseString, data);
decl->AsServo()->Raw(), aPropID, &value, aIsImportant, data);
}
if (!changed) {
// Parsing failed -- but we don't throw an exception for that.
@ -362,10 +360,8 @@ nsDOMCSSDeclaration::ParseCustomPropertyValue(const nsAString& aPropertyName,
NS_ConvertUTF16toUTF8 value(aPropValue);
RefPtr<css::URLExtraData> data =
new css::URLExtraData(env.mBaseURI, env.mSheetURI, env.mPrincipal);
nsCString baseString;
env.mBaseURI->GetSpec(baseString);
changed = Servo_DeclarationBlock_SetProperty(
decl->AsServo()->Raw(), &property, &value, aIsImportant, &baseString, data);
decl->AsServo()->Raw(), &property, &value, aIsImportant, data);
}
if (!changed) {
// Parsing failed -- but we don't throw an exception for that.

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

@ -118,9 +118,8 @@ to mochitest command.
* ... `'content`: various value as list-style-type in counter functions [13]
* test_default_computed_style.html: support of getDefaultComputedStyle [1]
* @font-face support bug 1290237
* test_descriptor_storage.html [1]
* test_descriptor_syntax_errors.html [1]
* test_font_face_parser.html `@font-face` [447]
* test_descriptor_storage.html [7]
* test_font_face_parser.html `@font-face` [51]
* @namespace support:
* test_namespace_rule.html [17]
* test_dont_use_document_colors.html: support of disabling document color [21]
@ -405,7 +404,7 @@ to mochitest command.
* test_units_length.html [5]
* test_units_time.html [1]
* insertRule / deleteRule don't work bug 1336863
* test_rule_insertion.html [7]
* test_rule_insertion.html [5]
* @-moz-document support
* test_rule_serialization.html [2]
* test_moz_document_rules.html [13]
@ -443,7 +442,6 @@ to mochitest command.
* test_flexbox_layout.html: resolved width doesn't match expectation [5]
* test_selectors.html `:nth-child`: &lt;an+b&gt; parsing difference [14]
* test_selectors_on_anonymous_content.html: xbl and :nth-child [1]
* test_variables.html `url`: url in custom property [1]
* test_parse_rule.html `rgb(0, 128, 0)`: color properties not getting computed [6]
## Ignore

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

@ -27,14 +27,14 @@ public class WebAppIndexer {
public static final String WEBAPP_CLASS = "org.mozilla.gecko.webapps.WebApps$WebApp";
private final String mPrefNumSavedEntries = "WebAppIndexer.numActivities";
private final String mPrefActivityIndex = "WebAppIndexer.index";
private final String mPrefActivityId = "WebAppIndexer.manifest";
private static final String PREF_NUM_SAVED_ENTRIES = "WebAppIndexer.numActivities";
private static final String PREF_ACTIVITY_INDEX = "WebAppIndexer.index";
private static final String PREF_ACTIVITY_ID = "WebAppIndexer.manifest";
private static final int MAX_ACTIVITIES = 10;
private static final int INVALID_INDEX = -1;
private ArrayList<ActivityEntry> mActivityList = new ArrayList<ActivityEntry>();
private ArrayList<ActivityEntry> mActivityList = new ArrayList<>();
private static class ActivityEntry {
public final int index;
@ -105,22 +105,32 @@ public class WebAppIndexer {
private void storeActivityList(Context context) {
final SharedPreferences prefs = GeckoSharedPrefs.forProfile(context);
final SharedPreferences.Editor editor = prefs.edit();
editor.clear();
editor.putInt(mPrefNumSavedEntries, mActivityList.size());
clearActivityListPrefs(prefs, editor);
editor.putInt(PREF_NUM_SAVED_ENTRIES, mActivityList.size());
for (int i = 0; i < mActivityList.size(); ++i) {
editor.putInt(mPrefActivityIndex + i, mActivityList.get(i).index);
editor.putString(mPrefActivityId + i, mActivityList.get(i).manifest);
editor.putInt(PREF_ACTIVITY_INDEX + i, mActivityList.get(i).index);
editor.putString(PREF_ACTIVITY_ID + i, mActivityList.get(i).manifest);
}
editor.apply();
}
private void clearActivityListPrefs(SharedPreferences prefs, SharedPreferences.Editor editor) {
int count = prefs.getInt(PREF_NUM_SAVED_ENTRIES, 0);
for (int i = 0; i < count; ++i) {
editor.remove(PREF_ACTIVITY_INDEX + i);
editor.remove(PREF_ACTIVITY_ID + i);
}
editor.remove(PREF_NUM_SAVED_ENTRIES);
}
@UiThread
private void loadActivityList(Context context) {
final SharedPreferences prefs = GeckoSharedPrefs.forProfile(context);
final int numSavedEntries = prefs.getInt(mPrefNumSavedEntries, 0);
final int numSavedEntries = prefs.getInt(PREF_NUM_SAVED_ENTRIES, 0);
for (int i = 0; i < numSavedEntries; ++i) {
int index = prefs.getInt(mPrefActivityIndex + i, i);
String manifest = prefs.getString(mPrefActivityId + i, null);
int index = prefs.getInt(PREF_ACTIVITY_INDEX + i, i);
String manifest = prefs.getString(PREF_ACTIVITY_ID + i, null);
ActivityEntry entry = new ActivityEntry(index, manifest);
mActivityList.add(entry);
}

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

@ -63,8 +63,6 @@ def test(mod, path, entity = None):
return "error"
# we're in mod == "mobile"
if re.match(r"searchplugins\/.+\.xml", path):
return "ignore"
if path == "chrome/region.properties":
# only region.properties exceptions remain
if (re.match(r"browser\.search\.order\.[1-9]", entity) or

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

@ -63,8 +63,6 @@ def test(mod, path, entity = None):
return "error"
# we're in mod == "mobile"
if re.match(r"searchplugins\/.+\.xml", path):
return "ignore"
if path == "chrome/region.properties":
# only region.properties exceptions remain
if (re.match(r"browser\.search\.order\.[1-9]", entity) or

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