Merge mozilla-central to mozilla-inbound

This commit is contained in:
Iris Hsiao 2017-05-02 11:10:52 +08:00
Родитель f7b2b2533f 1401934d7b
Коммит 2cf79ec292
31 изменённых файлов: 473 добавлений и 592 удалений

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

@ -22,6 +22,9 @@ with Files("tests/unit/test_distribution.js"):
with Files("safebrowsing/**"):
BUG_COMPONENT = ("Toolkit", "Safe Browsing")
with Files('controlcenter/**'):
BUG_COMPONENT = ('Firefox', 'General')
DIRS += [
'about',
@ -77,9 +80,3 @@ BROWSER_CHROME_MANIFESTS += [
XPCSHELL_TESTS_MANIFESTS += [
'tests/unit/xpcshell.ini'
]
with Files('safebrowsing/*'):
BUG_COMPONENT = ('Toolkit', 'Phishing Protection')
with Files('controlcenter/**'):
BUG_COMPONENT = ('Firefox', 'General')

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

@ -1110,8 +1110,13 @@ this.PlacesUIUtils = {
return this.leftPaneQueries;
},
// Get the folder id for the organizer left-pane folder.
get leftPaneFolderId() {
delete this.leftPaneFolderId;
return this.leftPaneFolderId = this.maybeRebuildLeftPane();
},
// Get the folder id for the organizer left-pane folder.
maybeRebuildLeftPane() {
let leftPaneRoot = -1;
let allBookmarksId;
@ -1163,8 +1168,8 @@ this.PlacesUIUtils = {
// Returns true if item really exists, false otherwise.
function itemExists(aItemId) {
try {
bs.getItemIndex(aItemId);
return true;
let index = bs.getItemIndex(aItemId);
return index > -1;
} catch (e) {
return false;
}
@ -1251,8 +1256,7 @@ this.PlacesUIUtils = {
safeRemoveItem(leftPaneRoot);
} else {
// Everything is fine, return the current left pane folder.
delete this.leftPaneFolderId;
return this.leftPaneFolderId = leftPaneRoot;
return leftPaneRoot;
}
}
@ -1345,8 +1349,7 @@ this.PlacesUIUtils = {
};
bs.runInBatchMode(callback, null);
delete this.leftPaneFolderId;
return this.leftPaneFolderId = leftPaneRoot;
return leftPaneRoot;
},
/**

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

@ -251,11 +251,7 @@ if test "$GNU_CC" -a "$GCC_USE_GNU_LD" -a -z "$DEVELOPER_OPTIONS"; then
fi
# bionic in Android < 4.1 doesn't support PIE
# On OSX, the linker defaults to building PIE programs when targetting OSX 10.7+,
# but not when targetting OSX < 10.7. OSX < 10.7 doesn't support running PIE
# programs, so as long as support for OSX 10.6 is kept, we can't build PIE.
# Even after dropping 10.6 support, MOZ_PIE would not be useful since it's the
# default (and clang says the -pie option is not used).
# On OSX, the linker defaults to building PIE programs when targeting OSX 10.7.
# On other Unix systems, some file managers (Nautilus) can't start PIE programs
if test -n "$gonkdir" && test "$ANDROID_VERSION" -ge 16; then
MOZ_PIE=1
@ -268,7 +264,7 @@ MOZ_ARG_ENABLE_BOOL(pie,
MOZ_PIE=1,
MOZ_PIE= )
if test "$GNU_CC" -a -n "$MOZ_PIE"; then
if test "$GNU_CC$CLANG_CC" -a -n "$MOZ_PIE"; then
AC_MSG_CHECKING([for PIE support])
_SAVE_LDFLAGS=$LDFLAGS
LDFLAGS="$LDFLAGS -pie"

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

@ -0,0 +1,79 @@
<!doctype html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1315874
-->
<head>
<meta charset="utf-8">
<title>Test SMIL does not trigger CSS Transitions (bug 1315874)</title>
</head>
<body>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=1315874">Mozilla Bug
1315874</a>
<svg>
<rect width="100%" height="100%"
style="fill: red; transition: fill 10s" id="rect">
<animate attributeName="fill" to="lime" dur="1s" fill="freeze">
</rect>
</svg>
<script type="text/javascript">
// Bring SimpleTest's function from opener.
if (opener) {
var is = opener.is.bind(opener);
var ok = opener.ok.bind(opener);
function finish() {
var o = opener;
self.close();
o.SimpleTest.finish();
}
}
window.addEventListener('load', runTests, false);
var rect = document.getElementById('rect');
var svg = document.getElementsByTagName('svg')[0];
is(getComputedStyle(rect).fill, 'rgb(255, 0, 0)',
'The initial color should be red.');
function runTests() {
waitForFrame().then(function() {
svg.setCurrentTime(1);
ok(getComputedStyle(rect).fill, 'rgb(0, 255, 0)',
'The end color should be lime.');
return waitForAnimationFrames(2);
}).then(function() {
var anim = document.getAnimations()[0];
ok(!anim, 'Transition should not be created by restyling for SMIL');
finish();
});
}
// Utility methods from testcommon.js
// For detail, see dom/animation/test/testcommon.js.
function waitForFrame() {
return new Promise(function(resolve, reject) {
requestAnimationFrame(function(time) {
resolve();
});
});
}
function waitForAnimationFrames(frameCount) {
return new Promise(function(resolve, reject) {
function handleFrame() {
if (--frameCount <= 0) {
resolve();
} else {
window.requestAnimationFrame(handleFrame);
}
}
window.requestAnimationFrame(handleFrame);
});
}
</script>
</pre>
</body>
</html>

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

@ -6,6 +6,7 @@ support-files =
db_smilCSSPaced.js
db_smilCSSPropertyList.js
db_smilMappedAttrList.js
file_smilWithTransition.html
smilAnimateMotionValueLists.js
smilExtDoc_helper.svg
smilTestUtils.js

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

@ -1,72 +1,18 @@
<!doctype html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1315874
-->
<meta charset=utf-8>
<head>
<meta charset="utf-8">
<title>Test SMIL does not trigger CSS Transitions (bug 1315874)</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=1315874">Mozilla Bug
1315874</a>
<svg>
<rect width="100%" height="100%"
style="fill: red; transition: fill 10s" id="rect">
<animate attributeName="fill" to="lime" dur="1s" fill="freeze">
</rect>
</svg>
<pre id="test">
<script type="text/javascript">
SimpleTest.waitForExplicitFinish();
window.addEventListener('load', runTests, false);
<script>
'use strict';
var rect = document.getElementById('rect');
var svg = document.getElementsByTagName('svg')[0];
is(getComputedStyle(rect).fill, 'rgb(255, 0, 0)',
'The initial color should be red.');
function runTests() {
waitForFrame().then(function() {
svg.setCurrentTime(1);
ok(getComputedStyle(rect).fill, 'rgb(0, 255, 0)',
'The end color should be lime.');
return waitForAnimationFrames(2);
}).then(function() {
var anim = document.getAnimations()[0];
ok(!anim, 'Transition should not be created by restyling for SMIL');
SimpleTest.finish();
});
}
// Utility methods from testcommon.js
// For detail, see dom/animation/test/testcommon.js.
function waitForFrame() {
return new Promise(function(resolve, reject) {
requestAnimationFrame(function(time) {
resolve();
});
});
}
function waitForAnimationFrames(frameCount) {
return new Promise(function(resolve, reject) {
function handleFrame() {
if (--frameCount <= 0) {
resolve();
} else {
window.requestAnimationFrame(handleFrame);
}
}
window.requestAnimationFrame(handleFrame);
});
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv(
{ "set": [["dom.animations-api.core.enabled", true]]},
function() {
window.open("file_smilWithTransition.html");
});
</script>
</pre>
</body>
</html>

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

@ -2883,9 +2883,10 @@ StyleAnimationValue::AddWeighted(nsCSSPropertyID aProperty,
case eUnit_Enumerated:
switch (aProperty) {
case eCSSProperty_font_stretch: {
// Animate just like eUnit_Integer.
int32_t result = floor(aCoeff1 * double(aValue1.GetIntValue()) +
aCoeff2 * double(aValue2.GetIntValue()));
// https://drafts.csswg.org/css-fonts-3/#font-stretch-animation
double interpolatedValue = aCoeff1 * double(aValue1.GetIntValue()) +
aCoeff2 * double(aValue2.GetIntValue());
int32_t result = floor(interpolatedValue + 0.5);
if (result < NS_STYLE_FONT_STRETCH_ULTRA_CONDENSED) {
result = NS_STYLE_FONT_STRETCH_ULTRA_CONDENSED;
} else if (result > NS_STYLE_FONT_STRETCH_ULTRA_EXPANDED) {
@ -2917,10 +2918,10 @@ StyleAnimationValue::AddWeighted(nsCSSPropertyID aProperty,
return true;
}
case eUnit_Integer: {
// http://dev.w3.org/csswg/css3-transitions/#animation-of-property-types-
// says we should use floor
int32_t result = floor(aCoeff1 * double(aValue1.GetIntValue()) +
aCoeff2 * double(aValue2.GetIntValue()));
// https://drafts.csswg.org/css-transitions/#animtype-integer
double interpolatedValue = aCoeff1 * double(aValue1.GetIntValue()) +
aCoeff2 * double(aValue2.GetIntValue());
int32_t result = floor(interpolatedValue + 0.5);
if (aProperty == eCSSProperty_font_weight) {
if (result < 100) {
result = 100;

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

@ -1836,7 +1836,7 @@ function test_integer_transition(prop) {
"integer-valued property " + prop + ": computed value before transition");
div.style.setProperty("transition-property", prop, "");
div.style.setProperty(prop, "-14", "");
is(cs.getPropertyValue(prop), "-1",
is(cs.getPropertyValue(prop), "0",
"integer-valued property " + prop + ": interpolation of integers");
check_distance(prop, "6", "1", "-14");
@ -1880,7 +1880,7 @@ function test_font_stretch(prop) {
"font-stretch property " + prop + ": computed value before transition");
div.style.setProperty("transition-property", prop, "");
div.style.setProperty(prop, "extra-condensed", "");
is(cs.getPropertyValue(prop), "normal",
is(cs.getPropertyValue(prop), "semi-expanded",
"font-stretch property " + prop + ": interpolation of font-stretches");
check_distance(prop, "expanded", "semi-expanded", "condensed");
@ -1964,7 +1964,7 @@ function test_pos_integer_or_auto_transition(prop) {
"integer-valued property " + prop + ": computed value before transition");
div.style.setProperty("transition-property", prop, "");
div.style.setProperty(prop, "11", "");
is(cs.getPropertyValue(prop), "5",
is(cs.getPropertyValue(prop), "6",
"integer-valued property " + prop + ": interpolation of integers");
check_distance(prop, "4", "6", "12");
div.style.setProperty(prop, "auto", "");

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

@ -264,17 +264,20 @@ static const char contentSandboxRules[] = R"(
; This process has blanket file read privileges
(allow file-read*)
; This process does not have blanket file read privileges
(if (string=? hasProfileDir "TRUE")
; we have a profile dir
(begin
(allow file-read* (require-all
(require-not (home-subpath "/Library"))
(require-not (subpath profileDir))))
(allow file-read*
(profile-subpath "/extensions")
(profile-subpath "/chrome")))
; we don't have a profile dir
(allow file-read* (require-not (home-subpath "/Library"))))))
(begin
; bug 1201935
(allow file-read* (home-subpath "/Library/Caches/TemporaryItems"))
(if (string=? hasProfileDir "TRUE")
; we have a profile dir
(begin
(allow file-read* (require-all
(require-not (home-subpath "/Library"))
(require-not (subpath profileDir))))
(allow file-read*
(profile-subpath "/extensions")
(profile-subpath "/chrome")))
; we don't have a profile dir
(allow file-read* (require-not (home-subpath "/Library")))))))
; level 3: global read access permitted, no global write access,
; no read access to the home directory,
@ -317,10 +320,6 @@ static const char contentSandboxRules[] = R"(
(iokit-user-client-class "NVDVDContextTesla")
(iokit-user-client-class "Gen6DVDContext"))
; bug 1201935
(allow file-read*
(home-subpath "/Library/Caches/TemporaryItems"))
; bug 1237847
(allow file-read*
(subpath appTempDir))

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

@ -248,6 +248,9 @@ function* testFileAccess() {
fileBrowser = gBrowser.getBrowserForTab(gBrowser.selectedTab);
}
// Current level
let level = prefs.getIntPref("security.sandbox.content.level");
// Directories/files to test accessing from content processes.
// For directories, we test whether a directory listing is allowed
// or blocked. For files, we test if we can read from the file.
@ -291,6 +294,30 @@ function* testFileAccess() {
});
}
if (isMac()) {
// If ~/Library/Caches/TemporaryItems exists, when level <= 2 we
// make sure it's readable. For level 3, we make sure it isn't.
let homeTempDir = GetHomeDir();
homeTempDir.appendRelativePath('Library/Caches/TemporaryItems');
if (homeTempDir.exists()) {
let shouldBeReadable, minLevel;
if (level >= minHomeReadSandboxLevel()) {
shouldBeReadable = false;
minLevel = minHomeReadSandboxLevel();
} else {
shouldBeReadable = true;
minLevel = 0;
}
tests.push({
desc: "home library cache temp dir",
ok: shouldBeReadable,
browser: webBrowser,
file: homeTempDir,
minLevel: minLevel,
});
}
}
let extensionsDir = GetProfileEntry("extensions");
if (extensionsDir.exists() && extensionsDir.isDirectory()) {
tests.push({
@ -331,7 +358,6 @@ function* testFileAccess() {
}
// remove tests not enabled by the current sandbox level
let level = prefs.getIntPref("security.sandbox.content.level");
tests = tests.filter((test) => { return (test.minLevel <= level); });
for (let test of tests) {

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

@ -501,3 +501,46 @@ function enableValidationPrefs() {
Svc.Prefs.set("engine.bookmarks.validation.maxRecords", -1);
Svc.Prefs.set("engine.bookmarks.validation.enabled", true);
}
function serverForEnginesWithKeys(users, engines, callback) {
// Generate and store a fake default key bundle to avoid resetting the client
// before the first sync.
let wbo = Service.collectionKeys.generateNewKeysWBO();
let modified = new_timestamp();
Service.collectionKeys.setContents(wbo.cleartext, modified);
let allEngines = [Service.clientsEngine].concat(engines);
let globalEngines = allEngines.reduce((entries, engine) => {
let { name, version, syncID } = engine;
entries[name] = { version, syncID };
return entries;
}, {});
let contents = allEngines.reduce((collections, engine) => {
collections[engine.name] = {};
return collections;
}, {
meta: {
global: {
syncID: Service.syncID,
storageVersion: STORAGE_VERSION,
engines: globalEngines,
},
},
crypto: {
keys: encryptPayload(wbo.cleartext),
},
});
return serverForUsers(users, contents, callback);
}
function serverForFoo(engine, callback) {
// The bookmarks engine *always* tracks changes, meaning we might try
// and sync due to the bookmarks we ourselves create! Worse, because we
// do an engine sync only, there's no locking - so we end up with multiple
// syncs running. Neuter that by making the threshold very large.
Service.scheduler.syncThreshold = 10000000;
return serverForEnginesWithKeys({"foo": "password"}, engine, callback);
}

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

@ -16,45 +16,6 @@ initTestLogging("Trace");
Service.engineManager.register(BookmarksEngine);
function serverForFoo(engine) {
// The bookmarks engine *always* tracks changes, meaning we might try
// and sync due to the bookmarks we ourselves create! Worse, because we
// do an engine sync only, there's no locking - so we end up with multiple
// syncs running. Neuter that by making the threshold very large.
Service.scheduler.syncThreshold = 10000000;
let clientsEngine = Service.clientsEngine;
return serverForUsers({"foo": "password"}, {
meta: {
global: {
syncID: Service.syncID,
storageVersion: STORAGE_VERSION,
engines: {
clients: {
version: clientsEngine.version,
syncID: clientsEngine.syncID,
},
bookmarks: {
version: engine.version,
syncID: engine.syncID,
},
},
},
},
crypto: {
keys: encryptPayload({
id: "keys",
// Generate a fake default key bundle to avoid resetting the client
// before the first sync.
default: [
Svc.Crypto.generateRandomKey(),
Svc.Crypto.generateRandomKey(),
],
}),
},
bookmarks: {}
});
}
// A stored reference to the collection won't be valid after disabling.
function getBookmarkWBO(server, guid) {
let coll = server.user("foo").collection("bookmarks");

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

@ -25,24 +25,11 @@ store._log.level = Log.Level.Trace;
engine._log.level = Log.Level.Trace;
async function setup() {
let server = serverForUsers({"foo": "password"}, {
meta: {global: {engines: {bookmarks: {version: engine.version,
syncID: engine.syncID}}}},
bookmarks: {},
});
generateNewKeys(Service.collectionKeys);
let server = serverForFoo(engine);
await SyncTestingInfrastructure(server);
let collection = server.user("foo").collection("bookmarks");
// The bookmarks engine *always* tracks changes, meaning we might try
// and sync due to the bookmarks we ourselves create! Worse, because we
// do an engine sync only, there's no locking - so we end up with multiple
// syncs running. Neuter that by making the threshold very large.
Service.scheduler.syncThreshold = 10000000;
Svc.Obs.notify("weave:engine:start-tracking"); // We skip usual startup...
return { server, collection };

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

@ -282,20 +282,6 @@ add_task(async function bad_record_allIDs() {
await promiseStopServer(server);
});
function serverForFoo(engine) {
// The bookmarks engine *always* tracks changes, meaning we might try
// and sync due to the bookmarks we ourselves create! Worse, because we
// do an engine sync only, there's no locking - so we end up with multiple
// syncs running. Neuter that by making the threshold very large.
Service.scheduler.syncThreshold = 10000000;
return serverForUsers({"foo": "password"}, {
meta: {global: {engines: {bookmarks: {version: engine.version,
syncID: engine.syncID}}}},
bookmarks: {}
});
}
add_task(async function test_processIncoming_error_orderChildren() {
_("Ensure that _orderChildren() is called even when _processIncoming() throws an error.");

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

@ -89,26 +89,7 @@ add_task(async function test_bookmark_repair_integration() {
_("Ensure that a validation error triggers a repair request.");
let contents = {
meta: {
global: {
engines: {
clients: {
version: clientsEngine.version,
syncID: clientsEngine.syncID,
},
bookmarks: {
version: bookmarksEngine.version,
syncID: bookmarksEngine.syncID,
},
}
}
},
clients: {},
bookmarks: {},
crypto: {},
};
let server = serverForUsers({"foo": "password"}, contents);
let server = serverForFoo(bookmarksEngine);
await SyncTestingInfrastructure(server);
let user = server.user("foo");
@ -329,26 +310,7 @@ add_task(async function test_repair_client_missing() {
_("Ensure that a record missing from the client only will get re-downloaded from the server");
let contents = {
meta: {
global: {
engines: {
clients: {
version: clientsEngine.version,
syncID: clientsEngine.syncID,
},
bookmarks: {
version: bookmarksEngine.version,
syncID: bookmarksEngine.syncID,
},
}
}
},
clients: {},
bookmarks: {},
crypto: {},
};
let server = serverForUsers({"foo": "password"}, contents);
let server = serverForFoo(bookmarksEngine);
await SyncTestingInfrastructure(server);
let user = server.user("foo");
@ -420,26 +382,7 @@ add_task(async function test_repair_server_missing() {
_("Ensure that a record missing from the server only will get re-upload from the client");
let contents = {
meta: {
global: {
engines: {
clients: {
version: clientsEngine.version,
syncID: clientsEngine.syncID,
},
bookmarks: {
version: bookmarksEngine.version,
syncID: bookmarksEngine.syncID,
},
}
}
},
clients: {},
bookmarks: {},
crypto: {},
};
let server = serverForUsers({"foo": "password"}, contents);
let server = serverForFoo(bookmarksEngine);
await SyncTestingInfrastructure(server);
let user = server.user("foo");
@ -504,26 +447,7 @@ add_task(async function test_repair_server_deleted() {
_("Ensure that a record marked as deleted on the server but present on the client will get deleted on the client");
let contents = {
meta: {
global: {
engines: {
clients: {
version: clientsEngine.version,
syncID: clientsEngine.syncID,
},
bookmarks: {
version: bookmarksEngine.version,
syncID: bookmarksEngine.syncID,
},
}
}
},
clients: {},
bookmarks: {},
crypto: {},
};
let server = serverForUsers({"foo": "password"}, contents);
let server = serverForFoo(bookmarksEngine);
await SyncTestingInfrastructure(server);
let user = server.user("foo");

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

@ -34,39 +34,9 @@ function getServerBookmarks(server) {
}
async function setup() {
let clientsEngine = Service.clientsEngine;
let bookmarksEngine = Service.engineManager.get("bookmarks");
let server = serverForUsers({"foo": "password"}, {
meta: {
global: {
syncID: Service.syncID,
storageVersion: STORAGE_VERSION,
engines: {
clients: {
version: clientsEngine.version,
syncID: clientsEngine.syncID,
},
bookmarks: {
version: bookmarksEngine.version,
syncID: bookmarksEngine.syncID,
},
},
},
},
crypto: {
keys: encryptPayload({
id: "keys",
// Generate a fake default key bundle to avoid resetting the client
// before the first sync.
default: [
Svc.Crypto.generateRandomKey(),
Svc.Crypto.generateRandomKey(),
],
}),
},
});
let server = serverForFoo(bookmarksEngine);
await SyncTestingInfrastructure(server);
// Disable validation so that we don't try to automatically repair the server

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

@ -46,14 +46,6 @@ function clearBookmarks() {
PlacesUtils.bookmarks.removeFolderChildren(PlacesUtils.bookmarks.unfiledBookmarksFolder);
}
function serverForFoo(engineData) {
return serverForUsers({"foo": "password"}, {
meta: {global: {engines: {bookmarks: {version: engineData.version,
syncID: engineData.syncID}}}},
bookmarks: {}
});
}
// Verify that Places smart bookmarks have their annotation uploaded and
// handled locally.
add_task(async function test_annotation_uploaded() {

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

@ -138,6 +138,165 @@ async function insertBookmarksToMigrate() {
await PlacesUtils.bookmarks.remove(exampleBmk.guid);
}
// `PlacesUtils.annotations.setItemAnnotation` prevents us from setting
// annotations on nonexistent items, so this test helper writes to the DB
// directly.
function setAnnoUnchecked(itemId, name, value, type) {
return PlacesUtils.withConnectionWrapper(
"test_bookmark_tracker: setItemAnnoUnchecked", async function(db) {
await db.executeCached(`
INSERT OR IGNORE INTO moz_anno_attributes (name)
VALUES (:name)`,
{ name });
let annoIds = await db.executeCached(`
SELECT a.id, a.dateAdded
FROM moz_items_annos a WHERE a.item_id = :itemId`,
{ itemId });
let annoId;
let dateAdded;
let lastModified = PlacesUtils.toPRTime(Date.now());
if (annoIds.length) {
annoId = annoIds[0].getResultByName("id");
dateAdded = annoIds[0].getResultByName("dateAdded");
} else {
annoId = null;
dateAdded = lastModified;
}
await db.executeCached(`
INSERT OR REPLACE INTO moz_items_annos (id, item_id, anno_attribute_id,
content, flags, expiration, type, dateAdded, lastModified)
VALUES (:annoId, :itemId, (SELECT id FROM moz_anno_attributes
WHERE name = :name),
:value, 0, :expiration, :type, :dateAdded, :lastModified)`,
{ annoId, itemId, name, value, type,
expiration: PlacesUtils.annotations.EXPIRE_NEVER,
dateAdded, lastModified });
}
);
}
add_task(async function test_leftPaneFolder() {
_("Ensure we never track left pane roots");
try {
await startTracking();
// Creates the organizer queries as a side effect.
let leftPaneId = PlacesUIUtils.maybeRebuildLeftPane();
_(`Left pane root ID: ${leftPaneId}`);
{
let changes = await tracker.promiseChangedIDs();
deepEqual(changes, {}, "New left pane queries should not be tracked");
do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE);
}
_("Reset synced bookmarks to simulate a disconnect");
await PlacesSyncUtils.bookmarks.reset();
{
let changes = await tracker.promiseChangedIDs();
deepEqual(Object.keys(changes).sort(), ["menu", "mobile", "toolbar", "unfiled"],
"Left pane queries should not be tracked after reset");
do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE);
await PlacesTestUtils.markBookmarksAsSynced();
}
// The following tests corrupt the left pane queries in different ways.
// `PlacesUIUtils.maybeRebuildLeftPane` will rebuild the entire root, but
// none of those changes should be tracked by Sync.
_("Annotate unrelated folder as left pane root");
{
let folder = await PlacesUtils.bookmarks.insert({
parentGuid: PlacesUtils.bookmarks.rootGuid,
type: PlacesUtils.bookmarks.TYPE_FOLDER,
title: "Fake left pane root",
});
let folderId = await PlacesUtils.promiseItemId(folder.guid);
await setAnnoUnchecked(folderId, PlacesUIUtils.ORGANIZER_FOLDER_ANNO, 0,
PlacesUtils.annotations.TYPE_INT32);
leftPaneId = PlacesUIUtils.maybeRebuildLeftPane();
_(`Left pane root ID after deleting unrelated folder: ${leftPaneId}`);
let changes = await tracker.promiseChangedIDs();
deepEqual(changes, {},
"Should not track left pane items after deleting unrelated folder");
}
_("Corrupt organizer left pane version");
{
await setAnnoUnchecked(leftPaneId, PlacesUIUtils.ORGANIZER_FOLDER_ANNO,
-1, PlacesUtils.annotations.TYPE_INT32);
leftPaneId = PlacesUIUtils.maybeRebuildLeftPane();
_(`Left pane root ID after restoring version: ${leftPaneId}`);
let changes = await tracker.promiseChangedIDs();
deepEqual(changes, {},
"Should not track left pane items after restoring version");
}
_("Set left pane anno on nonexistent item");
{
await setAnnoUnchecked(999, PlacesUIUtils.ORGANIZER_QUERY_ANNO,
"Tags", PlacesUtils.annotations.TYPE_STRING);
leftPaneId = PlacesUIUtils.maybeRebuildLeftPane();
_(`Left pane root ID after detecting nonexistent item: ${leftPaneId}`);
let changes = await tracker.promiseChangedIDs();
deepEqual(changes, {},
"Should not track left pane items after detecting nonexistent item");
}
_("Move query out of left pane root");
{
let queryId = await PlacesUIUtils.leftPaneQueries.Downloads;
let queryGuid = await PlacesUtils.promiseItemGuid(queryId);
await PlacesUtils.bookmarks.update({
guid: queryGuid,
parentGuid: PlacesUtils.bookmarks.rootGuid,
index: PlacesUtils.bookmarks.DEFAULT_INDEX,
});
leftPaneId = PlacesUIUtils.maybeRebuildLeftPane();
_(`Left pane root ID after restoring moved query: ${leftPaneId}`);
let changes = await tracker.promiseChangedIDs();
deepEqual(changes, {},
"Should not track left pane items after restoring moved query");
}
_("Add duplicate query");
{
let leftPaneGuid = await PlacesUtils.promiseItemGuid(leftPaneId);
let query = await PlacesUtils.bookmarks.insert({
parentGuid: leftPaneGuid,
url: `place:folder=TAGS`,
});
let queryId = await PlacesUtils.promiseItemId(query.guid);
await setAnnoUnchecked(queryId, PlacesUIUtils.ORGANIZER_QUERY_ANNO,
"Tags", PlacesUtils.annotations.TYPE_STRING);
leftPaneId = PlacesUIUtils.maybeRebuildLeftPane();
_(`Left pane root ID after removing dupe query: ${leftPaneId}`);
let changes = await tracker.promiseChangedIDs();
deepEqual(changes, {},
"Should not track left pane items after removing dupe query");
}
} finally {
_("Clean up.");
await cleanup();
}
});
add_task(async function test_tracking() {
_("Test starting and stopping the tracker");
@ -1526,11 +1685,6 @@ add_task(async function test_onItemDeleted_tree() {
}
});
async function ensureMobileQuery() {
tracker._ensureMobileQuery();
await PlacesTestUtils.promiseAsyncUpdates();
}
add_task(async function test_mobile_query() {
_("Ensure we correctly create the mobile query");
@ -1540,7 +1694,6 @@ add_task(async function test_mobile_query() {
// Creates the organizer queries as a side effect.
let leftPaneId = PlacesUIUtils.leftPaneFolderId;
_(`Left pane root ID: ${leftPaneId}`);
await PlacesTestUtils.promiseAsyncUpdates();
let allBookmarksGuids = await fetchGuidsWithAnno("PlacesOrganizer/OrganizerQuery",
"AllBookmarks");
@ -1548,7 +1701,7 @@ add_task(async function test_mobile_query() {
let allBookmarkGuid = allBookmarksGuids[0];
_("Try creating query after organizer is ready");
await ensureMobileQuery();
tracker._ensureMobileQuery();
let queryGuids = await fetchGuidsWithAnno("PlacesOrganizer/OrganizerQuery",
"MobileBookmarks");
equal(queryGuids.length, 0, "Should not create query without any mobile bookmarks");
@ -1558,7 +1711,7 @@ add_task(async function test_mobile_query() {
parentGuid: PlacesUtils.bookmarks.mobileGuid,
url: "https://mozilla.org",
});
await ensureMobileQuery();
tracker._ensureMobileQuery();
queryGuids = await fetchGuidsWithAnno("PlacesOrganizer/OrganizerQuery",
"MobileBookmarks");
equal(queryGuids.length, 1, "Should create query once mobile bookmarks exist");
@ -1579,7 +1732,7 @@ add_task(async function test_mobile_query() {
guid: queryGuid,
title: "renamed query",
});
await ensureMobileQuery();
tracker._ensureMobileQuery();
let rootInfo = await PlacesUtils.bookmarks.fetch(PlacesUtils.bookmarks.mobileGuid);
equal(rootInfo.title, "Mobile Bookmarks", "Should fix root title");
queryInfo = await PlacesUtils.bookmarks.fetch(queryGuid);
@ -1590,14 +1743,13 @@ add_task(async function test_mobile_query() {
guid: queryGuid,
url: "place:folder=BOOKMARKS_MENU",
});
await ensureMobileQuery();
tracker._ensureMobileQuery();
queryInfo = await PlacesUtils.bookmarks.fetch(queryGuid);
equal(queryInfo.url.href, `place:folder=${PlacesUtils.mobileFolderId}`,
"Should fix query URL to point to mobile root");
_("We shouldn't track the query or the left pane root");
await verifyTrackedItems([mozBmk.guid, "mobile"]);
do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 5);
} finally {
_("Clean up.");
await cleanup();

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

@ -58,12 +58,6 @@ function cleanup() {
add_task(async function test_bad_hmac() {
_("Ensure that Clients engine deletes corrupt records.");
let contents = {
meta: {global: {engines: {clients: {version: engine.version,
syncID: engine.syncID}}}},
clients: {},
crypto: {}
};
let deletedCollections = [];
let deletedItems = [];
let callback = {
@ -75,7 +69,7 @@ add_task(async function test_bad_hmac() {
deletedCollections.push(coll);
}
}
let server = serverForUsers({"foo": "password"}, contents, callback);
let server = serverForFoo(engine, callback);
let user = server.user("foo");
function check_clients_count(expectedCount) {
@ -212,13 +206,7 @@ add_task(async function test_full_sync() {
_("Ensure that Clients engine fetches all records for each sync.");
let now = Date.now() / 1000;
let contents = {
meta: {global: {engines: {clients: {version: engine.version,
syncID: engine.syncID}}}},
clients: {},
crypto: {}
};
let server = serverForUsers({"foo": "password"}, contents);
let server = serverForFoo(engine);
let user = server.user("foo");
await SyncTestingInfrastructure(server);
@ -283,13 +271,7 @@ add_task(async function test_full_sync() {
add_task(async function test_sync() {
_("Ensure that Clients engine uploads a new client record once a week.");
let contents = {
meta: {global: {engines: {clients: {version: engine.version,
syncID: engine.syncID}}}},
clients: {},
crypto: {}
};
let server = serverForUsers({"foo": "password"}, contents);
let server = serverForFoo(engine);
let user = server.user("foo");
await SyncTestingInfrastructure(server);
@ -369,13 +351,7 @@ add_task(async function test_last_modified() {
_("Ensure that remote records have a sane serverLastModified attribute.");
let now = Date.now() / 1000;
let contents = {
meta: {global: {engines: {clients: {version: engine.version,
syncID: engine.syncID}}}},
clients: {},
crypto: {}
};
let server = serverForUsers({"foo": "password"}, contents);
let server = serverForFoo(engine);
let user = server.user("foo");
await SyncTestingInfrastructure(server);
@ -590,13 +566,7 @@ add_task(async function test_filter_duplicate_names() {
_("Ensure that we exclude clients with identical names that haven't synced in a week.");
let now = Date.now() / 1000;
let contents = {
meta: {global: {engines: {clients: {version: engine.version,
syncID: engine.syncID}}}},
clients: {},
crypto: {}
};
let server = serverForUsers({"foo": "password"}, contents);
let server = serverForFoo(engine);
let user = server.user("foo");
await SyncTestingInfrastructure(server);
@ -747,13 +717,7 @@ add_task(async function test_command_sync() {
engine._store.wipe();
generateNewKeys(Service.collectionKeys);
let contents = {
meta: {global: {engines: {clients: {version: engine.version,
syncID: engine.syncID}}}},
clients: {},
crypto: {}
};
let server = serverForUsers({"foo": "password"}, contents);
let server = serverForFoo(engine);
await SyncTestingInfrastructure(server);
let user = server.user("foo");
@ -824,13 +788,7 @@ add_task(async function test_clients_not_in_fxa_list() {
engine._store.wipe();
generateNewKeys(Service.collectionKeys);
let contents = {
meta: {global: {engines: {clients: {version: engine.version,
syncID: engine.syncID}}}},
clients: {},
crypto: {}
};
let server = serverForUsers({"foo": "password"}, contents);
let server = serverForFoo(engine);
await SyncTestingInfrastructure(server);
let user = server.user("foo");
@ -1006,13 +964,7 @@ add_task(async function test_merge_commands() {
_("Verifies local commands for remote clients are merged with the server's");
let now = Date.now() / 1000;
let contents = {
meta: {global: {engines: {clients: {version: engine.version,
syncID: engine.syncID}}}},
clients: {},
crypto: {}
};
let server = serverForUsers({"foo": "password"}, contents);
let server = serverForFoo(engine);
await SyncTestingInfrastructure(server);
generateNewKeys(Service.collectionKeys);
@ -1082,13 +1034,7 @@ add_task(async function test_duplicate_remote_commands() {
_("Verifies local commands for remote clients are sent only once (bug 1289287)");
let now = Date.now() / 1000;
let contents = {
meta: {global: {engines: {clients: {version: engine.version,
syncID: engine.syncID}}}},
clients: {},
crypto: {}
};
let server = serverForUsers({"foo": "password"}, contents);
let server = serverForFoo(engine);
await SyncTestingInfrastructure(server);
generateNewKeys(Service.collectionKeys);
@ -1147,13 +1093,7 @@ add_task(async function test_upload_after_reboot() {
_("Multiple downloads, reboot, then upload (bug 1289287)");
let now = Date.now() / 1000;
let contents = {
meta: {global: {engines: {clients: {version: engine.version,
syncID: engine.syncID}}}},
clients: {},
crypto: {}
};
let server = serverForUsers({"foo": "password"}, contents);
let server = serverForFoo(engine);
await SyncTestingInfrastructure(server);
generateNewKeys(Service.collectionKeys);
@ -1235,13 +1175,7 @@ add_task(async function test_keep_cleared_commands_after_reboot() {
_("Download commands, fail upload, reboot, then apply new commands (bug 1289287)");
let now = Date.now() / 1000;
let contents = {
meta: {global: {engines: {clients: {version: engine.version,
syncID: engine.syncID}}}},
clients: {},
crypto: {}
};
let server = serverForUsers({"foo": "password"}, contents);
let server = serverForFoo(engine);
await SyncTestingInfrastructure(server);
generateNewKeys(Service.collectionKeys);
@ -1359,13 +1293,7 @@ add_task(async function test_deleted_commands() {
_("Verifies commands for a deleted client are discarded");
let now = Date.now() / 1000;
let contents = {
meta: {global: {engines: {clients: {version: engine.version,
syncID: engine.syncID}}}},
clients: {},
crypto: {}
};
let server = serverForUsers({"foo": "password"}, contents);
let server = serverForFoo(engine);
await SyncTestingInfrastructure(server);
generateNewKeys(Service.collectionKeys);
@ -1423,13 +1351,7 @@ add_task(async function test_send_uri_ack() {
_("Ensure a sent URI is deleted when the client syncs");
let now = Date.now() / 1000;
let contents = {
meta: {global: {engines: {clients: {version: engine.version,
syncID: engine.syncID}}}},
clients: {},
crypto: {}
};
let server = serverForUsers({"foo": "password"}, contents);
let server = serverForFoo(engine);
await SyncTestingInfrastructure(server);
generateNewKeys(Service.collectionKeys);
@ -1486,13 +1408,7 @@ add_task(async function test_command_sync() {
engine._store.wipe();
generateNewKeys(Service.collectionKeys);
let contents = {
meta: {global: {engines: {clients: {version: engine.version,
syncID: engine.syncID}}}},
clients: {},
crypto: {}
};
let server = serverForUsers({"foo": "password"}, contents);
let server = serverForFoo(engine);
await SyncTestingInfrastructure(server);
let collection = server.getCollection("foo", "clients");
@ -1557,13 +1473,7 @@ add_task(async function ensureSameFlowIDs() {
try {
// Setup 2 clients, send them a command, and ensure we get to events
// written, both with the same flowID.
let contents = {
meta: {global: {engines: {clients: {version: engine.version,
syncID: engine.syncID}}}},
clients: {},
crypto: {}
};
let server = serverForUsers({"foo": "password"}, contents);
let server = serverForFoo(engine);
await SyncTestingInfrastructure(server);
let remoteId = Utils.makeGUID();

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

@ -8,51 +8,16 @@ const LoginInfo = Components.Constructor(
const PropertyBag = Components.Constructor(
"@mozilla.org/hash-property-bag;1", Ci.nsIWritablePropertyBag);
function serverForEngine(engine) {
let clientsEngine = Service.clientsEngine;
return serverForUsers({"foo": "password"}, {
meta: {
global: {
syncID: Service.syncID,
storageVersion: STORAGE_VERSION,
engines: {
clients: {
version: clientsEngine.version,
syncID: clientsEngine.syncID,
},
[engine.name]: {
version: engine.version,
syncID: engine.syncID,
},
},
},
},
crypto: {
keys: encryptPayload({
id: "keys",
// Generate a fake default key bundle to avoid resetting the client
// before the first sync.
default: [
Svc.Crypto.generateRandomKey(),
Svc.Crypto.generateRandomKey(),
],
}),
},
[engine.name]: {},
});
}
add_task(async function test_password_engine() {
_("Basic password sync test");
let engine = Service.engineManager.get("passwords");
let store = engine._store;
let server = serverForEngine(engine);
let server = serverForFoo(engine);
await SyncTestingInfrastructure(server);
let collection = server.user("foo").collection("passwords");
generateNewKeys(Service.collectionKeys);
enableValidationPrefs();
_("Add new login to upload during first sync");

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

@ -100,11 +100,7 @@ add_task(async function test_basic() {
add_task(async function test_processIncoming_error() {
let engine = new BookmarksEngine(Service);
let store = engine._store;
let server = serverForUsers({"foo": "password"}, {
meta: {global: {engines: {bookmarks: {version: engine.version,
syncID: engine.syncID}}}},
bookmarks: {}
});
let server = serverForFoo(engine);
await SyncTestingInfrastructure(server);
let collection = server.user("foo").collection("bookmarks");
try {
@ -154,11 +150,7 @@ add_task(async function test_processIncoming_error() {
add_task(async function test_uploading() {
let engine = new BookmarksEngine(Service);
let store = engine._store;
let server = serverForUsers({"foo": "password"}, {
meta: {global: {engines: {bookmarks: {version: engine.version,
syncID: engine.syncID}}}},
bookmarks: {}
});
let server = serverForFoo(engine);
await SyncTestingInfrastructure(server);
let parent = PlacesUtils.toolbarFolderId;
@ -338,11 +330,7 @@ add_task(async function test_generic_engine_fail() {
Service.engineManager.register(SteamEngine);
let engine = Service.engineManager.get("steam");
engine.enabled = true;
let server = serverForUsers({"foo": "password"}, {
meta: {global: {engines: {steam: {version: engine.version,
syncID: engine.syncID}}}},
steam: {}
});
let server = serverForFoo(engine);
await SyncTestingInfrastructure(server);
let e = new Error("generic failure message")
engine._errToThrow = e;
@ -368,11 +356,7 @@ add_task(async function test_engine_fail_ioerror() {
Service.engineManager.register(SteamEngine);
let engine = Service.engineManager.get("steam");
engine.enabled = true;
let server = serverForUsers({"foo": "password"}, {
meta: {global: {engines: {steam: {version: engine.version,
syncID: engine.syncID}}}},
steam: {}
});
let server = serverForFoo(engine);
await SyncTestingInfrastructure(server);
// create an IOError to re-throw as part of Sync.
try {
@ -410,12 +394,9 @@ add_task(async function test_initial_sync_engines() {
let engines = {};
// These are the only ones who actually have things to sync at startup.
let engineNames = ["clients", "bookmarks", "prefs", "tabs"];
let conf = { meta: { global: { engines } } };
for (let e of engineNames) {
engines[e] = { version: engine.version, syncID: engine.syncID };
conf[e] = {};
}
let server = serverForUsers({"foo": "password"}, conf);
let server = serverForEnginesWithKeys({"foo": "password"}, ["bookmarks", "prefs", "tabs"].map(name =>
Service.engineManager.get(name)
));
await SyncTestingInfrastructure(server);
try {
_(`test_initial_sync_engines: Steam tracker contents: ${
@ -448,11 +429,7 @@ add_task(async function test_nserror() {
Service.engineManager.register(SteamEngine);
let engine = Service.engineManager.get("steam");
engine.enabled = true;
let server = serverForUsers({"foo": "password"}, {
meta: {global: {engines: {steam: {version: engine.version,
syncID: engine.syncID}}}},
steam: {}
});
let server = serverForFoo(engine);
await SyncTestingInfrastructure(server);
engine._errToThrow = Components.Exception("NS_ERROR_UNKNOWN_HOST", Cr.NS_ERROR_UNKNOWN_HOST);
try {
@ -527,10 +504,7 @@ add_task(async function test_no_foreign_engines_in_error_ping() {
Service.engineManager.register(BogusEngine);
let engine = Service.engineManager.get("bogus");
engine.enabled = true;
let server = serverForUsers({"foo": "password"}, {
meta: {global: {engines: {bogus: {version: engine.version, syncID: engine.syncID}}}},
steam: {}
});
let server = serverForFoo(engine);
engine._errToThrow = new Error("Oh no!");
await SyncTestingInfrastructure(server);
try {
@ -549,11 +523,7 @@ add_task(async function test_sql_error() {
Service.engineManager.register(SteamEngine);
let engine = Service.engineManager.get("steam");
engine.enabled = true;
let server = serverForUsers({"foo": "password"}, {
meta: {global: {engines: {steam: {version: engine.version,
syncID: engine.syncID}}}},
steam: {}
});
let server = serverForFoo(engine);
await SyncTestingInfrastructure(server);
engine._sync = function() {
// Just grab a DB connection and issue a bogus SQL statement synchronously.
@ -578,10 +548,7 @@ add_task(async function test_no_foreign_engines_in_success_ping() {
Service.engineManager.register(BogusEngine);
let engine = Service.engineManager.get("bogus");
engine.enabled = true;
let server = serverForUsers({"foo": "password"}, {
meta: {global: {engines: {bogus: {version: engine.version, syncID: engine.syncID}}}},
steam: {}
});
let server = serverForFoo(engine);
await SyncTestingInfrastructure(server);
try {
@ -599,10 +566,7 @@ add_task(async function test_events() {
Service.engineManager.register(BogusEngine);
let engine = Service.engineManager.get("bogus");
engine.enabled = true;
let server = serverForUsers({"foo": "password"}, {
meta: {global: {engines: {bogus: {version: engine.version, syncID: engine.syncID}}}},
steam: {}
});
let server = serverForFoo(engine);
await SyncTestingInfrastructure(server);
try {
@ -646,10 +610,7 @@ add_task(async function test_invalid_events() {
Service.engineManager.register(BogusEngine);
let engine = Service.engineManager.get("bogus");
engine.enabled = true;
let server = serverForUsers({"foo": "password"}, {
meta: {global: {engines: {bogus: {version: engine.version, syncID: engine.syncID}}}},
steam: {}
});
let server = serverForFoo(engine);
async function checkNotRecorded(...args) {
Service.recordTelemetryEvent.call(args);
@ -695,10 +656,7 @@ add_task(async function test_no_ping_for_self_hosters() {
Service.engineManager.register(BogusEngine);
let engine = Service.engineManager.get("bogus");
engine.enabled = true;
let server = serverForUsers({"foo": "password"}, {
meta: {global: {engines: {bogus: {version: engine.version, syncID: engine.syncID}}}},
steam: {}
});
let server = serverForFoo(engine);
await SyncTestingInfrastructure(server);
try {

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

@ -169,27 +169,6 @@ impl<Impl: SelectorImpl> SelectorInner<Impl> {
}
}
/// Creates a clone of this selector with everything to the left of
/// (and including) the rightmost ancestor combinator removed. So
/// the selector |span foo > bar + baz| will become |bar + baz|.
/// This is used for revalidation selectors in servo.
///
/// The bloom filter hashes are copied, even though they correspond to
/// parts of the selector that have been stripped out, because they are
/// still useful for fast-rejecting the reduced selectors.
pub fn slice_to_first_ancestor_combinator(&self) -> Self {
let maybe_pos = self.complex.iter_raw()
.position(|s| s.as_combinator()
.map_or(false, |c| c.is_ancestor()));
match maybe_pos {
None => self.clone(),
Some(index) => SelectorInner {
complex: self.complex.slice_to(index),
ancestor_hashes: self.ancestor_hashes.clone(),
},
}
}
/// Creates a SelectorInner from a Vec of Components. Used in tests.
pub fn from_vec(vec: Vec<Component<Impl>>) -> Self {
let complex = ComplexSelector::from_vec(vec);

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

@ -27,7 +27,8 @@ use selectors::Element;
use selectors::bloom::BloomFilter;
use selectors::matching::{AFFECTED_BY_STYLE_ATTRIBUTE, AFFECTED_BY_PRESENTATIONAL_HINTS};
use selectors::matching::{ElementSelectorFlags, StyleRelations, matches_selector};
use selectors::parser::{Component, Selector, SelectorInner, SelectorMethods, LocalName as LocalNameSelector};
use selectors::parser::{Combinator, Component, Selector, SelectorInner, SelectorIter};
use selectors::parser::{SelectorMethods, LocalName as LocalNameSelector};
use selectors::visitor::SelectorVisitor;
use shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards};
use sink::Push;
@ -375,10 +376,7 @@ impl Stylist {
#[inline]
fn note_for_revalidation(&mut self, selector: &Selector<SelectorImpl>) {
if needs_revalidation(selector) {
// For revalidation, we can skip everything left of the first ancestor
// combinator.
let revalidation_sel = selector.inner.slice_to_first_ancestor_combinator();
self.selectors_for_cache_revalidation.push(revalidation_sel);
self.selectors_for_cache_revalidation.push(selector.inner.clone());
}
}
@ -923,18 +921,47 @@ impl Drop for Stylist {
/// Visitor determine whether a selector requires cache revalidation.
///
/// Note that we just check simple selectors and eagerly return when the first
/// need for revalidation is found, so we don't need to store state on the visitor.
/// need for revalidation is found, so we don't need to store state on the
/// visitor.
///
/// Also, note that it's important to check the whole selector, due to cousins
/// sharing arbitrarily deep in the DOM, not just the rightmost part of it
/// (unfortunately, though).
///
/// With cousin sharing, we not only need to care about selectors in stuff like
/// foo:first-child, but also about selectors like p:first-child foo, since the
/// two parents may have shared style, and in that case we can test cousins
/// whose matching depends on the selector up in the chain.
///
/// TODO(emilio): We can optimize when matching only siblings to only match the
/// rightmost selector until a descendant combinator is found, I guess, and in
/// general when we're sharing at depth `n`, to the `n + 1` sequences of
/// descendant combinators.
///
/// I don't think that in presence of the bloom filter it's worth it, though.
struct RevalidationVisitor;
impl SelectorVisitor for RevalidationVisitor {
type Impl = SelectorImpl;
/// Check whether a rightmost sequence of simple selectors containing this
/// simple selector to be explicitly matched against both the style sharing
/// cache entry and the candidate.
fn visit_complex_selector(&mut self,
_: SelectorIter<SelectorImpl>,
combinator: Option<Combinator>) -> bool {
let is_sibling_combinator =
combinator.map_or(false, |c| c.is_sibling());
!is_sibling_combinator
}
/// Check whether sequence of simple selectors containing this simple
/// selector to be explicitly matched against both the style sharing cache
/// entry and the candidate.
///
/// We use this for selectors that can have different matching behavior between
/// siblings that are otherwise identical as far as the cache is concerned.
/// We use this for selectors that can have different matching behavior
/// between siblings that are otherwise identical as far as the cache is
/// concerned.
fn visit_simple_selector(&mut self, s: &Component<SelectorImpl>) -> bool {
match *s {
Component::AttrExists(_) |
@ -970,23 +997,7 @@ impl SelectorVisitor for RevalidationVisitor {
/// Returns true if the given selector needs cache revalidation.
pub fn needs_revalidation(selector: &Selector<SelectorImpl>) -> bool {
let mut visitor = RevalidationVisitor;
// We only need to consider the rightmost sequence of simple selectors, so
// we can stop at the first combinator. This is because:
// * If it's an ancestor combinator, we can ignore everything to the left
// because matching won't differ between siblings.
// * If it's a sibling combinator, then we know we need revalidation.
let mut iter = selector.inner.complex.iter();
for ss in &mut iter {
if !ss.visit(&mut visitor) {
return true;
}
}
// If none of the simple selectors in the rightmost sequence required
// revalidation, we need revalidation if and only if the combinator is a
// sibling combinator.
iter.next_sequence().map_or(false, |c| c.is_sibling())
!selector.visit(&mut visitor)
}
/// Map that contains the CSS rules for a specific PseudoElement

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

@ -4,7 +4,6 @@
#![allow(non_camel_case_types)]
#![feature(box_syntax)]
#![feature(core_intrinsics)]
#![feature(link_args)]
#[macro_use]

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

@ -12,9 +12,7 @@ macro_rules! stub(
#[allow(non_snake_case)]
pub extern "C" fn $name() {
println!("CEF stub function called: {}", stringify!($name));
unsafe {
::std::intrinsics::abort()
}
::std::process::abort()
}
)
);

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

@ -15,7 +15,7 @@
//!
//! [glutin]: https://github.com/tomaka/glutin
#![feature(start, core_intrinsics)]
#![feature(start)]
#[cfg(target_os = "android")]
extern crate android_injected_glue;
@ -58,7 +58,7 @@ pub mod platform {
fn install_crash_handler() {
use backtrace::Backtrace;
use sig::ffi::Sig;
use std::intrinsics::abort;
use std::process::abort;
use std::thread;
fn handler(_sig: i32) {
@ -67,9 +67,7 @@ fn install_crash_handler() {
.map(|n| format!(" for thread \"{}\"", n))
.unwrap_or("".to_owned());
println!("Stack trace{}\n{:?}", name, Backtrace::new());
unsafe {
abort();
}
abort();
}
signal!(Sig::SEGV, handler); // handle segfaults

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

@ -109,13 +109,11 @@ fn test_revalidation_selectors() {
"span + div",
"span ~ div",
// Revalidation selectors that will get sliced.
"td > h1[dir]",
"td > span + h1[dir]",
"table td > span + div ~ h1[dir]",
// Selectors in the ancestor chain (needed for cousin sharing).
"p:first-child span",
]).into_iter()
.filter(|s| needs_revalidation(&s))
.map(|s| s.inner.slice_to_first_ancestor_combinator().complex)
.map(|s| s.inner.complex)
.collect::<Vec<_>>();
let reference = parse_selectors(&[
@ -147,10 +145,8 @@ fn test_revalidation_selectors() {
"span + div",
"span ~ div",
// Revalidation selectors that got sliced.
"h1[dir]",
"span + h1[dir]",
"span + div ~ h1[dir]",
// Selectors in the ancestor chain (needed for cousin sharing).
"p:first-child span",
]).into_iter()
.map(|s| s.inner.complex)
.collect::<Vec<_>>();

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

@ -27,6 +27,7 @@
#include "prio.h"
#include "prprf.h"
#include "mozilla/Maybe.h"
#include "mozilla/Printf.h"
#include "mozilla/UniquePtr.h"
using namespace JS;
@ -64,7 +65,7 @@ TestStartupCache::TestStartupCache()
mSCFile->AppendNative(NS_LITERAL_CSTRING("test-startupcache.tmp"));
nsAutoCString path;
mSCFile->GetNativePath(path);
char* env = PR_smprintf("MOZ_STARTUP_CACHE=%s", path.get());
char* env = mozilla::Smprintf("MOZ_STARTUP_CACHE=%s", path.get()).release();
PR_SetEnv(env);
// We intentionally leak `env` here because it is required by PR_SetEnv
MOZ_LSAN_INTENTIONALLY_LEAK_OBJECT(env);

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

@ -314,7 +314,7 @@ EnvHasValue(const char *name)
static void
SaveWordToEnv(const char *name, const nsACString & word)
{
char *expr = PR_smprintf("%s=%s", name, PromiseFlatCString(word).get());
char *expr = Smprintf("%s=%s", name, PromiseFlatCString(word).get()).release();
if (expr)
PR_SetEnv(expr);
// We intentionally leak |expr| here since it is required by PR_SetEnv.
@ -2810,7 +2810,7 @@ static void SaveStateForAppInitiatedRestart()
for (auto & savedVar : gSavedVars) {
const char *s = PR_GetEnv(savedVar.name);
if (s)
savedVar.value = PR_smprintf("%s=%s", savedVar.name, s);
savedVar.value = Smprintf("%s=%s", savedVar.name, s).release();
}
}
@ -4415,7 +4415,8 @@ XREMain::XRE_mainRun()
char appFile[MAX_PATH];
if (GetEnvironmentVariableA("XUL_APP_FILE", appFile, sizeof(appFile))) {
SmprintfPointer saved = mozilla::Smprintf("XUL_APP_FILE=%s", appFile);
PR_SetEnv(saved.get());
// We intentionally leak the string here since it is required by PR_SetEnv.
PR_SetEnv(saved.release());
}
#endif

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

@ -24,6 +24,7 @@
#include "mozilla/Preferences.h"
#include "nsPrintfCString.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/Printf.h"
#ifdef XP_MACOSX
#include "nsILocalFileMac.h"
@ -406,18 +407,15 @@ AppendToLibPath(const char *pathToAppend)
{
char *pathValue = getenv(LD_LIBRARY_PATH_ENVVAR_NAME);
if (nullptr == pathValue || '\0' == *pathValue) {
char *s = PR_smprintf("%s=%s", LD_LIBRARY_PATH_ENVVAR_NAME, pathToAppend);
// Leak the string because that is required by PR_SetEnv.
char *s = Smprintf("%s=%s", LD_LIBRARY_PATH_ENVVAR_NAME, pathToAppend).release();
PR_SetEnv(s);
} else if (!strstr(pathValue, pathToAppend)) {
char *s = PR_smprintf("%s=%s" PATH_SEPARATOR "%s",
LD_LIBRARY_PATH_ENVVAR_NAME, pathToAppend, pathValue);
// Leak the string because that is required by PR_SetEnv.
char *s = Smprintf("%s=%s" PATH_SEPARATOR "%s",
LD_LIBRARY_PATH_ENVVAR_NAME, pathToAppend, pathValue).release();
PR_SetEnv(s);
}
// The memory used by PR_SetEnv is not copied to the environment on all
// platform, it can be used by reference directly. So we purposely do not
// call PR_smprintf_free on s. Subsequent calls to PR_SetEnv will free
// the old memory first.
}
#endif

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

@ -14,6 +14,8 @@
#include "nsMemory.h"
#include "nsString.h"
#include "nsCRTGlue.h"
#include "mozilla/IntegerPrintfMacros.h"
#include "mozilla/Printf.h"
/***************************************************************************/
// Helpers for static convert functions...
@ -746,7 +748,7 @@ nsDiscriminatedUnion::ConvertToID(nsID* aResult) const
nsresult
nsDiscriminatedUnion::ToString(nsACString& aOutString) const
{
char* ptr;
mozilla::SmprintfPointer pptr;
switch (mType) {
// all the stuff we don't handle...
@ -778,16 +780,17 @@ nsDiscriminatedUnion::ToString(nsACString& aOutString) const
// nsID has its own text formatter.
case nsIDataType::VTYPE_ID:
ptr = u.mIDValue.ToString();
case nsIDataType::VTYPE_ID: {
char* ptr = u.mIDValue.ToString();
if (!ptr) {
return NS_ERROR_OUT_OF_MEMORY;
}
aOutString.Assign(ptr);
free(ptr);
return NS_OK;
}
// Can't use PR_smprintf for floats, since it's locale-dependent
// Can't use Smprintf for floats, since it's locale-dependent
#define CASE__APPENDFLOAT_NUMBER(type_, member_) \
case nsIDataType::type_ : \
{ \
@ -802,22 +805,24 @@ nsDiscriminatedUnion::ToString(nsACString& aOutString) const
#undef CASE__APPENDFLOAT_NUMBER
// the rest can be PR_smprintf'd and use common code.
// the rest can be Smprintf'd and use common code.
#define CASE__SMPRINTF_NUMBER(type_, format_, cast_, member_) \
case nsIDataType::type_: \
ptr = PR_smprintf( format_ , (cast_) u.member_); \
static_assert(sizeof(cast_) >= sizeof(u.member_), \
"size of type should be at least as big as member"); \
pptr = mozilla::Smprintf( format_ , (cast_) u.member_); \
break;
CASE__SMPRINTF_NUMBER(VTYPE_INT8, "%d", int, mInt8Value)
CASE__SMPRINTF_NUMBER(VTYPE_INT16, "%d", int, mInt16Value)
CASE__SMPRINTF_NUMBER(VTYPE_INT32, "%d", int, mInt32Value)
CASE__SMPRINTF_NUMBER(VTYPE_INT64, "%lld", int64_t, mInt64Value)
CASE__SMPRINTF_NUMBER(VTYPE_INT64, "%" PRId64, int64_t, mInt64Value)
CASE__SMPRINTF_NUMBER(VTYPE_UINT8, "%u", unsigned, mUint8Value)
CASE__SMPRINTF_NUMBER(VTYPE_UINT16, "%u", unsigned, mUint16Value)
CASE__SMPRINTF_NUMBER(VTYPE_UINT32, "%u", unsigned, mUint32Value)
CASE__SMPRINTF_NUMBER(VTYPE_UINT64, "%llu", int64_t, mUint64Value)
CASE__SMPRINTF_NUMBER(VTYPE_UINT64, "%" PRIu64, int64_t, mUint64Value)
// XXX Would we rather print "true" / "false" ?
CASE__SMPRINTF_NUMBER(VTYPE_BOOL, "%d", int, mBoolValue)
@ -827,11 +832,10 @@ nsDiscriminatedUnion::ToString(nsACString& aOutString) const
#undef CASE__SMPRINTF_NUMBER
}
if (!ptr) {
if (!pptr) {
return NS_ERROR_OUT_OF_MEMORY;
}
aOutString.Assign(ptr);
PR_smprintf_free(ptr);
aOutString.Assign(pptr.get());
return NS_OK;
}