Merge autoland to mozilla-central. a=merge

This commit is contained in:
Dorel Luca 2018-03-02 00:05:07 +02:00
Родитель 84c76716c7 90a5e0e595
Коммит 109ad47bbf
73 изменённых файлов: 1192 добавлений и 1078 удалений

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

@ -1472,7 +1472,7 @@ nsAccessibilityService::CreateAccessibleByType(nsIContent* aContent,
{
nsAutoString role;
nsCoreUtils::XBLBindingRole(aContent, role);
if (role.IsEmpty() || role.EqualsLiteral("none"))
if (role.IsEmpty())
return nullptr;
RefPtr<Accessible> accessible;
@ -1487,9 +1487,6 @@ nsAccessibilityService::CreateAccessibleByType(nsIContent* aContent,
} else if (role.EqualsLiteral("xul:link")) {
accessible = new XULLinkAccessible(aContent, aDoc);
} else if(role.EqualsLiteral("xul:pane")) {
accessible = new EnumRoleAccessible<roles::PANE>(aContent, aDoc);
} else if (role.EqualsLiteral("xul:panel")) {
if (aContent->IsElement() &&
aContent->AsElement()->AttrValueIs(kNameSpaceID_None,

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

@ -381,7 +381,7 @@ var FeedHandler = {
// http://foo.com/index.rdf -> feed://foo.com/index.rdf
// other urls: prepend feed: scheme, e.g.
// https://foo.com/index.rdf -> feed:https://foo.com/index.rdf
let feedURI = NetUtil.newURI(aSpec);
let feedURI = Services.io.newURI(aSpec);
if (feedURI.schemeIs("http")) {
feedURI = feedURI.mutate()
.setScheme("feed")

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

@ -481,7 +481,7 @@ var PlacesCommandHook = {
let parentGuid = parentId == PlacesUtils.bookmarksMenuFolderId ?
PlacesUtils.bookmarks.menuGuid :
await PlacesUtils.promiseItemGuid(parentId);
let defaultInsertionPoint = new InsertionPoint({ parentId, parentGuid });
let defaultInsertionPoint = new PlacesInsertionPoint({ parentId, parentGuid });
PlacesUIUtils.showBookmarkDialog({ action: "add",
type: "bookmark",
uri: makeURI(url),
@ -557,7 +557,7 @@ var PlacesCommandHook = {
* A short description of the feed. Optional.
*/
async addLiveBookmark(url, feedTitle, feedSubtitle) {
let toolbarIP = new InsertionPoint({
let toolbarIP = new PlacesInsertionPoint({
parentId: PlacesUtils.toolbarFolderId,
parentGuid: PlacesUtils.bookmarks.toolbarGuid
});
@ -993,7 +993,7 @@ var PlacesMenuDNDHandler = {
* The DragOver event.
*/
onDragOver: function PMDH_onDragOver(event) {
let ip = new InsertionPoint({
let ip = new PlacesInsertionPoint({
parentId: PlacesUtils.bookmarksMenuFolderId,
parentGuid: PlacesUtils.bookmarks.menuGuid
});
@ -1010,7 +1010,7 @@ var PlacesMenuDNDHandler = {
*/
onDrop: function PMDH_onDrop(event) {
// Put the item at the end of bookmark menu.
let ip = new InsertionPoint({
let ip = new PlacesInsertionPoint({
parentId: PlacesUtils.bookmarksMenuFolderId,
parentGuid: PlacesUtils.bookmarks.menuGuid
});

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

@ -34,6 +34,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
LightweightThemeManager: "resource://gre/modules/LightweightThemeManager.jsm",
Log: "resource://gre/modules/Log.jsm",
LoginManagerParent: "resource://gre/modules/LoginManagerParent.jsm",
NetUtil: "resource://gre/modules/NetUtil.jsm",
NewTabUtils: "resource://gre/modules/NewTabUtils.jsm",
OpenInTabsUtils: "resource:///modules/OpenInTabsUtils.jsm",
PageActions: "resource:///modules/PageActions.jsm",

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

@ -16,6 +16,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
WebNavigationFrames: "resource://gre/modules/WebNavigationFrames.jsm",
ContextualIdentityService: "resource://gre/modules/ContextualIdentityService.jsm",
DevToolsShim: "chrome://devtools-shim/content/DevToolsShim.jsm",
NetUtil: "resource://gre/modules/NetUtil.jsm",
});
var gContextMenuContentData = null;

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

@ -69,6 +69,72 @@ let whitelist = [
intermittent: true,
errorMessage: /Property contained reference to invalid variable.*color/i,
isFromDevTools: true},
// These are CSS custom properties that we found a definition of but
// no reference to.
// Bug 1441837
{propName: "--in-content-category-text-active",
isFromDevTools: false},
// Bug 1441844
{propName: "--chrome-nav-bar-separator-color",
isFromDevTools: false},
// Bug 1441855
{propName: "--chrome-nav-buttons-background",
isFromDevTools: false},
// Bug 1441855
{propName: "--chrome-nav-buttons-hover-background",
isFromDevTools: false},
// Bug 1441857
{propName: "--muteButton-width",
isFromDevTools: false},
// Bug 1441857
{propName: "--closedCaptionButton-width",
isFromDevTools: false},
// Bug 1441857
{propName: "--fullscreenButton-width",
isFromDevTools: false},
// Bug 1441857
{propName: "--durationSpan-width",
isFromDevTools: false},
// Bug 1441857
{propName: "--durationSpan-width-long",
isFromDevTools: false},
// Bug 1441857
{propName: "--positionDurationBox-width",
isFromDevTools: false},
// Bug 1441857
{propName: "--positionDurationBox-width-long",
isFromDevTools: false},
// Bug 1441860
{propName: "--rule-flex-toggle-color",
isFromDevTools: true},
// Bug 1441929
{propName: "--theme-search-overlays-semitransparent",
isFromDevTools: true},
// Bug 1441878
{propName: "--theme-codemirror-gutter-background",
isFromDevTools: true},
// Bug 1441879
{propName: "--arrow-width",
isFromDevTools: true},
// Bug 1442300
{propName: "--in-content-category-background",
isFromDevTools: false},
// Bug 1442314
{propName: "--separator-border-image",
isFromDevTools: true},
// Used on Linux
{propName: "--in-content-box-background-odd",
platforms: ["win", "macosx"],
isFromDevTools: false},
// These properties *are* actually referenced. Need to find why
// their reference isn't getting counted.
{propName: "--bezier-diagonal-color",
isFromDevTools: true},
{propName: "--bezier-grid-color",
isFromDevTools: true},
];
if (!Services.prefs.getBoolPref("full-screen-api.unprefix.enabled")) {
@ -194,6 +260,7 @@ function messageIsCSSError(msg) {
}
let imageURIsToReferencesMap = new Map();
let customPropsToReferencesMap = new Map();
function processCSSRules(sheet) {
for (let rule of sheet.cssRules) {
@ -208,10 +275,11 @@ function processCSSRules(sheet) {
// Note: CSSStyleRule.cssText always has double quotes around URLs even
// when the original CSS file didn't.
let urls = rule.cssText.match(/url\("[^"]*"\)/g);
if (!urls)
let props = rule.cssText.match(/(var\()?(--[\w\-]+)/g);
if (!urls && !props)
continue;
for (let url of urls) {
for (let url of (urls || [])) {
// Remove the url(" prefix and the ") suffix.
url = url.replace(/url\("(.*)"\)/, "$1");
if (url.startsWith("data:"))
@ -229,6 +297,16 @@ function processCSSRules(sheet) {
imageURIsToReferencesMap.get(url).add(baseUrl);
}
}
for (let prop of (props || [])) {
if (prop.startsWith("var(")) {
prop = prop.substring(4);
let prevValue = customPropsToReferencesMap.get(prop) || 0;
customPropsToReferencesMap.set(prop, prevValue + 1);
} else if (!customPropsToReferencesMap.has(prop)) {
customPropsToReferencesMap.set(prop, undefined);
}
}
}
}
@ -354,6 +432,26 @@ add_task(async function checkAllTheCSS() {
}
}
// Check if all the properties that are defined are referenced.
for (let [prop, refCount] of customPropsToReferencesMap) {
if (!refCount) {
let ignored = false;
for (let item of whitelist) {
if (item.propName == prop &&
isDevtools == item.isFromDevTools) {
item.used = true;
if (!item.platforms || item.platforms.includes(AppConstants.platform)) {
ignored = true;
}
break;
}
}
if (!ignored) {
ok(false, "custom property `" + prop + "` is not referenced");
}
}
}
let messages = Services.console.getMessageArray();
// Count errors (the test output will list actual issues for us, as well
// as the ok(false) in messageIsCSSError.
@ -362,8 +460,12 @@ add_task(async function checkAllTheCSS() {
// Confirm that all whitelist rules have been used.
for (let item of whitelist) {
if (!item.used && isDevtools == item.isFromDevTools && !item.intermittent) {
if (!item.used &&
(!item.platforms || item.platforms.includes(AppConstants.platform)) &&
isDevtools == item.isFromDevTools &&
!item.intermittent) {
ok(false, "Unused whitelist item. " +
(item.propName ? " propName: " + item.propName : "") +
(item.sourceName ? " sourceName: " + item.sourceName : "") +
(item.errorMessage ? " errorMessage: " + item.errorMessage : ""));
}
@ -388,4 +490,5 @@ add_task(async function checkAllTheCSS() {
hiddenFrame.destroy();
hiddenFrame = null;
imageURIsToReferencesMap = null;
customPropsToReferencesMap = null;
});

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

@ -256,61 +256,6 @@ var PlacesUIUtils = {
return bundle.GetStringFromName(key);
},
/**
* Constructs a Places Transaction for the drop or paste of a blob of data
* into a container.
*
* @param aData
* The unwrapped data blob of dropped or pasted data.
* @param aNewParentGuid
* GUID of the container the data was dropped or pasted into.
* @param aIndex
* The index within the container the item was dropped or pasted at.
* @param aCopy
* The drag action was copy, so don't move folders or links.
*
* @return a Places Transaction that can be transacted for performing the
* move/insert command.
*/
getTransactionForData(aData, aNewParentGuid, aIndex, aCopy) {
if (!this.SUPPORTED_FLAVORS.includes(aData.type))
throw new Error(`Unsupported '${aData.type}' data type`);
if ("itemGuid" in aData && "instanceId" in aData &&
aData.instanceId == PlacesUtils.instanceId) {
if (!this.PLACES_FLAVORS.includes(aData.type))
throw new Error(`itemGuid unexpectedly set on ${aData.type} data`);
let info = { guid: aData.itemGuid,
newParentGuid: aNewParentGuid,
newIndex: aIndex };
if (aCopy) {
info.excludingAnnotation = "Places/SmartBookmark";
return PlacesTransactions.Copy(info);
}
return PlacesTransactions.Move(info);
}
// Since it's cheap and harmless, we allow the paste of separators and
// bookmarks from builds that use legacy transactions (i.e. when itemGuid
// was not set on PLACES_FLAVORS data). Containers are a different story,
// and thus disallowed.
if (aData.type == PlacesUtils.TYPE_X_MOZ_PLACE_CONTAINER)
throw new Error("Can't copy a container from a legacy-transactions build");
if (aData.type == PlacesUtils.TYPE_X_MOZ_PLACE_SEPARATOR) {
return PlacesTransactions.NewSeparator({ parentGuid: aNewParentGuid,
index: aIndex });
}
let title = aData.type != PlacesUtils.TYPE_UNICODE ? aData.title
: aData.uri;
return PlacesTransactions.NewBookmark({ url: Services.io.newURI(aData.uri),
title,
parentGuid: aNewParentGuid,
index: aIndex });
},
/**
* Shows the bookmark dialog corresponding to the specified info.
*
@ -404,6 +349,77 @@ var PlacesUIUtils = {
return null;
},
/**
* Returns the active PlacesController for a given command.
*
* @param win The window containing the affected view
* @param command The command
* @return a PlacesController
*/
getControllerForCommand(win, command) {
// A context menu may be built for non-focusable views. Thus, we first try
// to look for a view associated with document.popupNode
let popupNode;
try {
popupNode = win.document.popupNode;
} catch (e) {
// The document went away (bug 797307).
return null;
}
if (popupNode) {
let view = this.getViewForNode(popupNode);
if (view && view._contextMenuShown)
return view.controllers.getControllerForCommand(command);
}
// When we're not building a context menu, only focusable views
// are possible. Thus, we can safely use the command dispatcher.
let controller = win.top.document.commandDispatcher
.getControllerForCommand(command);
return controller || null;
},
/**
* Update all the Places commands for the given window.
*
* @param win The window to update.
*/
updateCommands(win) {
// Get the controller for one of the places commands.
let controller = this.getControllerForCommand(win, "placesCmd_open");
for (let command of [
"placesCmd_open",
"placesCmd_open:window",
"placesCmd_open:privatewindow",
"placesCmd_open:tab",
"placesCmd_new:folder",
"placesCmd_new:bookmark",
"placesCmd_new:separator",
"placesCmd_show:info",
"placesCmd_reload",
"placesCmd_sortBy:name",
"placesCmd_cut",
"placesCmd_copy",
"placesCmd_paste",
"placesCmd_delete",
]) {
win.goSetCommandEnabled(command,
controller && controller.isCommandEnabled(command));
}
},
/**
* Executes the given command on the currently active controller.
*
* @param win The window containing the affected view
* @param command The command to execute
*/
doCommand(win, command) {
let controller = this.getControllerForCommand(win, command);
if (controller && controller.isCommandEnabled(command))
controller.doCommand(command);
},
/**
* By calling this before visiting an URL, the visit will be associated to a
* TRANSITION_TYPED transition (if there is no a referrer).
@ -1176,19 +1192,135 @@ var PlacesUIUtils = {
}
}
},
/**
* Constructs a Places Transaction for the drop or paste of a blob of data
* into a container.
*
* @param aData
* The unwrapped data blob of dropped or pasted data.
* @param aNewParentGuid
* GUID of the container the data was dropped or pasted into.
* @param aIndex
* The index within the container the item was dropped or pasted at.
* @param aCopy
* The drag action was copy, so don't move folders or links.
*
* @return a Places Transaction that can be transacted for performing the
* move/insert command.
*/
getTransactionForData(aData, aNewParentGuid, aIndex, aCopy) {
if (!this.SUPPORTED_FLAVORS.includes(aData.type))
throw new Error(`Unsupported '${aData.type}' data type`);
if ("itemGuid" in aData && "instanceId" in aData &&
aData.instanceId == PlacesUtils.instanceId) {
if (!this.PLACES_FLAVORS.includes(aData.type))
throw new Error(`itemGuid unexpectedly set on ${aData.type} data`);
let info = { guid: aData.itemGuid,
newParentGuid: aNewParentGuid,
newIndex: aIndex };
if (aCopy) {
info.excludingAnnotation = "Places/SmartBookmark";
return PlacesTransactions.Copy(info);
}
return PlacesTransactions.Move(info);
}
// Since it's cheap and harmless, we allow the paste of separators and
// bookmarks from builds that use legacy transactions (i.e. when itemGuid
// was not set on PLACES_FLAVORS data). Containers are a different story,
// and thus disallowed.
if (aData.type == PlacesUtils.TYPE_X_MOZ_PLACE_CONTAINER)
throw new Error("Can't copy a container from a legacy-transactions build");
if (aData.type == PlacesUtils.TYPE_X_MOZ_PLACE_SEPARATOR) {
return PlacesTransactions.NewSeparator({ parentGuid: aNewParentGuid,
index: aIndex });
}
let title = aData.type != PlacesUtils.TYPE_UNICODE ? aData.title
: aData.uri;
return PlacesTransactions.NewBookmark({ url: Services.io.newURI(aData.uri),
title,
parentGuid: aNewParentGuid,
index: aIndex });
},
/**
* Processes a set of transfer items that have been dropped or pasted.
* Batching will be applied where necessary.
*
* @param {Array} items A list of unwrapped nodes to process.
* @param {Object} insertionPoint The requested point for insertion.
* @param {Boolean} doCopy Set to true to copy the items, false will move them
* if possible.
* @paramt {Object} view The view that should be used for batching.
* @return {Array} Returns an empty array when the insertion point is a tag, else
* returns an array of copied or moved guids.
*/
async handleTransferItems(items, insertionPoint, doCopy, view) {
let transactions;
let itemsCount;
if (insertionPoint.isTag) {
let urls = items.filter(item => "uri" in item).map(item => item.uri);
itemsCount = urls.length;
transactions = [PlacesTransactions.Tag({ urls, tag: insertionPoint.tagName })];
} else {
let insertionIndex = await insertionPoint.getIndex();
itemsCount = items.length;
transactions = await getTransactionsForTransferItems(
items, insertionIndex, insertionPoint.guid, doCopy);
}
// Check if we actually have something to add, if we don't it probably wasn't
// valid, or it was moving to the same location, so just ignore it.
if (!transactions.length) {
return [];
}
let guidsToSelect = [];
let resultForBatching = getResultForBatching(view);
// If we're inserting into a tag, we don't get the guid, so we'll just
// pass the transactions direct to the batch function.
let batchingItem = transactions;
if (!insertionPoint.isTag) {
// If we're not a tag, then we need to get the ids of the items to select.
batchingItem = async () => {
for (let transaction of transactions) {
let guid = await transaction.transact();
if (guid) {
guidsToSelect.push(guid);
}
}
};
}
await this.batchUpdatesForNode(resultForBatching, itemsCount, async () => {
await PlacesTransactions.batch(batchingItem);
});
return guidsToSelect;
},
};
PlacesUIUtils.PLACES_FLAVORS = [PlacesUtils.TYPE_X_MOZ_PLACE_CONTAINER,
PlacesUtils.TYPE_X_MOZ_PLACE_SEPARATOR,
PlacesUtils.TYPE_X_MOZ_PLACE];
PlacesUIUtils.URI_FLAVORS = [PlacesUtils.TYPE_X_MOZ_URL,
TAB_DROP_TYPE,
PlacesUtils.TYPE_UNICODE],
PlacesUIUtils.SUPPORTED_FLAVORS = [...PlacesUIUtils.PLACES_FLAVORS,
...PlacesUIUtils.URI_FLAVORS];
// These are lazy getters to avoid importing PlacesUtils immediately.
XPCOMUtils.defineLazyGetter(PlacesUIUtils, "PLACES_FLAVORS", () => {
return [PlacesUtils.TYPE_X_MOZ_PLACE_CONTAINER,
PlacesUtils.TYPE_X_MOZ_PLACE_SEPARATOR,
PlacesUtils.TYPE_X_MOZ_PLACE];
});
XPCOMUtils.defineLazyGetter(PlacesUIUtils, "URI_FLAVORS", () => {
return [PlacesUtils.TYPE_X_MOZ_URL,
TAB_DROP_TYPE,
PlacesUtils.TYPE_UNICODE];
});
XPCOMUtils.defineLazyGetter(PlacesUIUtils, "SUPPORTED_FLAVORS", () => {
return [...PlacesUIUtils.PLACES_FLAVORS,
...PlacesUIUtils.URI_FLAVORS];
});
XPCOMUtils.defineLazyGetter(PlacesUIUtils, "ellipsis", function() {
return Services.prefs.getComplexValue("intl.ellipsis",
@ -1201,3 +1333,117 @@ XPCOMUtils.defineLazyPreferenceGetter(PlacesUIUtils, "loadBookmarksInTabs",
PREF_LOAD_BOOKMARKS_IN_TABS, false);
XPCOMUtils.defineLazyPreferenceGetter(PlacesUIUtils, "openInTabClosesMenu",
"browser.bookmarks.openInTabClosesMenu", false);
/**
* Determines if an unwrapped node can be moved.
*
* @param unwrappedNode
* A node unwrapped by PlacesUtils.unwrapNodes().
* @return True if the node can be moved, false otherwise.
*/
function canMoveUnwrappedNode(unwrappedNode) {
if ((unwrappedNode.concreteGuid && PlacesUtils.isRootItem(unwrappedNode.concreteGuid)) ||
unwrappedNode.id <= 0 || PlacesUtils.isRootItem(unwrappedNode.id)) {
return false;
}
let parentGuid = unwrappedNode.parentGuid;
// If there's no parent Guid, this was likely a virtual query that returns
// bookmarks, such as a tags query.
if (!parentGuid ||
parentGuid == PlacesUtils.bookmarks.rootGuid) {
return false;
}
// leftPaneFolderId and allBookmarksFolderId are lazy getters running
// at least a synchronous DB query. Therefore we don't want to invoke
// them first, especially because isCommandEnabled may be called way
// before the left pane folder is even necessary.
if (typeof Object.getOwnPropertyDescriptor(PlacesUIUtils, "leftPaneFolderId").get != "function" &&
(unwrappedNode.parent == PlacesUIUtils.leftPaneFolderId)) {
return false;
}
return true;
}
/**
* This gets the most appropriate item for using for batching. In the case of multiple
* views being related, the method returns the most expensive result to batch.
* For example, if it detects the left-hand library pane, then it will look for
* and return the reference to the right-hand pane.
*
* @param {Object} viewOrElement The item to check.
* @return {Object} Will return the best result node to batch, or null
* if one could not be found.
*/
function getResultForBatching(viewOrElement) {
if (viewOrElement && viewOrElement instanceof Ci.nsIDOMElement &&
viewOrElement.id === "placesList") {
// Note: fall back to the existing item if we can't find the right-hane pane.
viewOrElement = viewOrElement.ownerDocument.getElementById("placeContent") || viewOrElement;
}
if (viewOrElement && viewOrElement.result) {
return viewOrElement.result;
}
return null;
}
/**
* Processes a set of transfer items and returns transactions to insert or
* move them.
*
* @param {Array} items A list of unwrapped nodes to get transactions for.
* @param {Integer} insertionIndex The requested index for insertion.
* @param {String} insertionParentGuid The guid of the parent folder to insert
* or move the items to.
* @param {Boolean} doCopy Set to true to copy the items, false will move them
* if possible.
* @return {Array} Returns an array of created PlacesTransactions.
*/
async function getTransactionsForTransferItems(items, insertionIndex,
insertionParentGuid, doCopy) {
let transactions = [];
let index = insertionIndex;
for (let item of items) {
if (index != -1 && item.itemGuid) {
// Note: we use the parent from the existing bookmark as the sidebar
// gives us an unwrapped.parent that is actually a query and not the real
// parent.
let existingBookmark = await PlacesUtils.bookmarks.fetch(item.itemGuid);
// If we're dropping on the same folder, then we may need to adjust
// the index to insert at the correct place.
if (existingBookmark && insertionParentGuid == existingBookmark.parentGuid) {
if (index > existingBookmark.index) {
// If we're dragging down, we need to go one lower to insert at
// the real point as moving the element changes the index of
// everything below by 1.
index--;
} else if (index == existingBookmark.index) {
// This isn't moving so we skip it.
continue;
}
}
}
// If this is not a copy, check for safety that we can move the
// source, otherwise report an error and fallback to a copy.
if (!doCopy && !canMoveUnwrappedNode(item)) {
Cu.reportError("Tried to move an unmovable Places " +
"node, reverting to a copy operation.");
doCopy = true;
}
transactions.push(
PlacesUIUtils.getTransactionForData(item,
insertionParentGuid,
index,
doCopy));
if (index != -1 && item.itemGuid) {
index++;
}
}
return transactions;
}

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

@ -161,7 +161,7 @@ var BookmarkPropertiesPanel = {
this._defaultInsertionPoint = dialogInfo.defaultInsertionPoint;
} else {
this._defaultInsertionPoint =
new InsertionPoint({
new PlacesInsertionPoint({
parentId: PlacesUtils.bookmarksMenuFolderId,
parentGuid: PlacesUtils.bookmarks.menuGuid
});

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

@ -217,10 +217,10 @@ PlacesViewBase.prototype = {
}
}
if (PlacesControllerDragHelper.disallowInsertion(container, this))
if (this.controller.disallowInsertion(container))
return null;
return new InsertionPoint({
return new PlacesInsertionPoint({
parentId: PlacesUtils.getConcreteItemId(container),
parentGuid: PlacesUtils.getConcreteItemGuid(container),
index, orientation, tagName
@ -1519,7 +1519,7 @@ PlacesToolbar.prototype = {
: (aEvent.clientX < eltRect.left + threshold)) {
// Drop before this folder.
dropPoint.ip =
new InsertionPoint({
new PlacesInsertionPoint({
parentId: PlacesUtils.getConcreteItemId(this._resultNode),
parentGuid: PlacesUtils.getConcreteItemGuid(this._resultNode),
index: eltIndex,
@ -1532,7 +1532,7 @@ PlacesToolbar.prototype = {
let tagName = PlacesUtils.nodeIsTagQuery(elt._placesNode) ?
elt._placesNode.title : null;
dropPoint.ip =
new InsertionPoint({
new PlacesInsertionPoint({
parentId: PlacesUtils.getConcreteItemId(elt._placesNode),
parentGuid: PlacesUtils.getConcreteItemGuid(elt._placesNode),
tagName
@ -1546,7 +1546,7 @@ PlacesToolbar.prototype = {
-1 : eltIndex + 1;
dropPoint.ip =
new InsertionPoint({
new PlacesInsertionPoint({
parentId: PlacesUtils.getConcreteItemId(this._resultNode),
parentGuid: PlacesUtils.getConcreteItemGuid(this._resultNode),
index: beforeIndex,
@ -1562,7 +1562,7 @@ PlacesToolbar.prototype = {
: (aEvent.clientX < eltRect.left + threshold)) {
// Drop before this bookmark.
dropPoint.ip =
new InsertionPoint({
new PlacesInsertionPoint({
parentId: PlacesUtils.getConcreteItemId(this._resultNode),
parentGuid: PlacesUtils.getConcreteItemGuid(this._resultNode),
index: eltIndex,
@ -1575,7 +1575,7 @@ PlacesToolbar.prototype = {
eltIndex == this._rootElt.childNodes.length - 1 ?
-1 : eltIndex + 1;
dropPoint.ip =
new InsertionPoint({
new PlacesInsertionPoint({
parentId: PlacesUtils.getConcreteItemId(this._resultNode),
parentGuid: PlacesUtils.getConcreteItemGuid(this._resultNode),
index: beforeIndex,
@ -1588,7 +1588,7 @@ PlacesToolbar.prototype = {
// We are most likely dragging on the empty area of the
// toolbar, we should drop after the last node.
dropPoint.ip =
new InsertionPoint({
new PlacesInsertionPoint({
parentId: PlacesUtils.getConcreteItemId(this._resultNode),
parentGuid: PlacesUtils.getConcreteItemGuid(this._resultNode),
orientation: Ci.nsITreeView.DROP_BEFORE

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

@ -3,13 +3,6 @@
* 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/. */
ChromeUtils.defineModuleGetter(this, "ForgetAboutSite",
"resource://gre/modules/ForgetAboutSite.jsm");
ChromeUtils.defineModuleGetter(this, "NetUtil",
"resource://gre/modules/NetUtil.jsm");
ChromeUtils.defineModuleGetter(this, "PrivateBrowsingUtils",
"resource://gre/modules/PrivateBrowsingUtils.jsm");
/**
* Represents an insertion point within a container where we can insert
* items.
@ -30,11 +23,11 @@ ChromeUtils.defineModuleGetter(this, "PrivateBrowsingUtils",
* - dropNearNode
* When defined index will be calculated based on this node
*/
function InsertionPoint({ parentId, parentGuid,
index = PlacesUtils.bookmarks.DEFAULT_INDEX,
orientation = Ci.nsITreeView.DROP_ON,
tagName = null,
dropNearNode = null }) {
function PlacesInsertionPoint({ parentId, parentGuid,
index = PlacesUtils.bookmarks.DEFAULT_INDEX,
orientation = Ci.nsITreeView.DROP_ON,
tagName = null,
dropNearNode = null }) {
this.itemId = parentId;
this.guid = parentGuid;
this._index = index;
@ -43,7 +36,7 @@ function InsertionPoint({ parentId, parentGuid,
this.dropNearNode = dropNearNode;
}
InsertionPoint.prototype = {
PlacesInsertionPoint.prototype = {
set index(val) {
return this._index = val;
},
@ -230,7 +223,7 @@ PlacesController.prototype = {
var queries = this._view.selectedNode.getQueries();
host = queries[0].domain;
} else
host = NetUtil.newURI(this._view.selectedNode.uri).host;
host = Services.io.newURI(this._view.selectedNode.uri).host;
ForgetAboutSite.removeDataFromDomain(host)
.catch(Cu.reportError);
break;
@ -275,7 +268,7 @@ PlacesController.prototype = {
"keyword",
"location",
"loadInSidebar" ],
uri: NetUtil.newURI(node.uri),
uri: Services.io.newURI(node.uri),
title: node.title
}, window.top);
break;
@ -428,7 +421,7 @@ PlacesController.prototype = {
break;
case Ci.nsINavHistoryResultNode.RESULT_TYPE_URI:
nodeData.link = true;
uri = NetUtil.newURI(node.uri);
uri = Services.io.newURI(node.uri);
if (PlacesUtils.nodeIsBookmark(node)) {
nodeData.bookmark = true;
var parentNode = node.parent;
@ -1213,7 +1206,7 @@ PlacesController.prototype = {
}
let doCopy = action == "copy";
let itemsToSelect = await handleTransferItems(items, ip, doCopy, this._view);
let itemsToSelect = await PlacesUIUtils.handleTransferItems(items, ip, doCopy, this._view);
// Cut/past operations are not repeatable, so clear the clipboard.
if (action == "cut") {
@ -1256,7 +1249,41 @@ PlacesController.prototype = {
*/
getCachedLivemarkInfo: function PC_getCachedLivemarkInfo(aNode) {
return this._cachedLivemarkInfoObjects.get(aNode, null);
}
},
/**
* Checks if we can insert into a container.
* @param container
* The container were we are want to drop
*/
disallowInsertion(container) {
NS_ASSERT(container, "empty container");
// Allow dropping into Tag containers and editable folders.
return !PlacesUtils.nodeIsTagQuery(container) &&
(!PlacesUtils.nodeIsFolder(container) ||
PlacesUIUtils.isFolderReadOnly(container, this._view));
},
/**
* Determines if a node can be moved.
*
* @param aNode
* A nsINavHistoryResultNode node.
* @return True if the node can be moved, false otherwise.
*/
canMoveNode(node) {
// Only bookmark items are movable.
if (node.itemId == -1)
return false;
// Once tags and bookmarked are divorced, the tag-query check should be
// removed.
let parentNode = node.parent;
return parentNode != null &&
PlacesUtils.nodeIsFolder(parentNode) &&
!PlacesUIUtils.isFolderReadOnly(parentNode, this._view) &&
!PlacesUtils.nodeIsTagQuery(parentNode);
},
};
/**
@ -1378,62 +1405,6 @@ var PlacesControllerDragHelper = {
return true;
},
/**
* Determines if an unwrapped node can be moved.
*
* @param unwrappedNode
* A node unwrapped by PlacesUtils.unwrapNodes().
* @return True if the node can be moved, false otherwise.
*/
canMoveUnwrappedNode(unwrappedNode) {
if ((unwrappedNode.concreteGuid && PlacesUtils.isRootItem(unwrappedNode.concreteGuid)) ||
unwrappedNode.id <= 0 || PlacesUtils.isRootItem(unwrappedNode.id)) {
return false;
}
let parentGuid = unwrappedNode.parentGuid;
// If there's no parent Guid, this was likely a virtual query that returns
// bookmarks, such as a tags query.
if (!parentGuid ||
parentGuid == PlacesUtils.bookmarks.rootGuid) {
return false;
}
// leftPaneFolderId and allBookmarksFolderId are lazy getters running
// at least a synchronous DB query. Therefore we don't want to invoke
// them first, especially because isCommandEnabled may be called way
// before the left pane folder is even necessary.
if (typeof Object.getOwnPropertyDescriptor(PlacesUIUtils, "leftPaneFolderId").get != "function" &&
(unwrappedNode.parent == PlacesUIUtils.leftPaneFolderId)) {
return false;
}
return true;
},
/**
* Determines if a node can be moved.
*
* @param aNode
* A nsINavHistoryResultNode node.
* @param aView
* The view originating the request
* @param [optional] aDOMNode
* A XUL DOM node.
* @return True if the node can be moved, false otherwise.
*/
canMoveNode(aNode, aView) {
// Only bookmark items are movable.
if (aNode.itemId == -1)
return false;
// Once tags and bookmarked are divorced, the tag-query check should be
// removed.
let parentNode = aNode.parent;
return parentNode != null &&
PlacesUtils.nodeIsFolder(parentNode) &&
!PlacesUIUtils.isFolderReadOnly(parentNode, aView) &&
!PlacesUtils.nodeIsTagQuery(parentNode);
},
/**
* Handles the drop of one or more items onto a view.
*
@ -1486,221 +1457,10 @@ var PlacesControllerDragHelper = {
}
}
await handleTransferItems(nodes, insertionPoint, doCopy, view);
await PlacesUIUtils.handleTransferItems(nodes, insertionPoint, doCopy, view);
},
/**
* Checks if we can insert into a container.
* @param aContainer
* The container were we are want to drop
* @param aView
* The view generating the request
*/
disallowInsertion(aContainer, aView) {
NS_ASSERT(aContainer, "empty container");
// Allow dropping into Tag containers and editable folders.
return !PlacesUtils.nodeIsTagQuery(aContainer) &&
(!PlacesUtils.nodeIsFolder(aContainer) ||
PlacesUIUtils.isFolderReadOnly(aContainer, aView));
}
};
XPCOMUtils.defineLazyServiceGetter(PlacesControllerDragHelper, "dragService",
"@mozilla.org/widget/dragservice;1",
"nsIDragService");
function goUpdatePlacesCommands() {
// Get the controller for one of the places commands.
var placesController = doGetPlacesControllerForCommand("placesCmd_open");
function updatePlacesCommand(aCommand) {
goSetCommandEnabled(aCommand, placesController &&
placesController.isCommandEnabled(aCommand));
}
updatePlacesCommand("placesCmd_open");
updatePlacesCommand("placesCmd_open:window");
updatePlacesCommand("placesCmd_open:privatewindow");
updatePlacesCommand("placesCmd_open:tab");
updatePlacesCommand("placesCmd_new:folder");
updatePlacesCommand("placesCmd_new:bookmark");
updatePlacesCommand("placesCmd_new:separator");
updatePlacesCommand("placesCmd_show:info");
updatePlacesCommand("placesCmd_reload");
updatePlacesCommand("placesCmd_sortBy:name");
updatePlacesCommand("placesCmd_cut");
updatePlacesCommand("placesCmd_copy");
updatePlacesCommand("placesCmd_paste");
updatePlacesCommand("placesCmd_delete");
}
function doGetPlacesControllerForCommand(aCommand) {
// A context menu may be built for non-focusable views. Thus, we first try
// to look for a view associated with document.popupNode
let popupNode;
try {
popupNode = document.popupNode;
} catch (e) {
// The document went away (bug 797307).
return null;
}
if (popupNode) {
let view = PlacesUIUtils.getViewForNode(popupNode);
if (view && view._contextMenuShown)
return view.controllers.getControllerForCommand(aCommand);
}
// When we're not building a context menu, only focusable views
// are possible. Thus, we can safely use the command dispatcher.
let controller = top.document.commandDispatcher
.getControllerForCommand(aCommand);
if (controller)
return controller;
return null;
}
function goDoPlacesCommand(aCommand) {
let controller = doGetPlacesControllerForCommand(aCommand);
if (controller && controller.isCommandEnabled(aCommand))
controller.doCommand(aCommand);
}
/**
* This gets the most appropriate item for using for batching. In the case of multiple
* views being related, the method returns the most expensive result to batch.
* For example, if it detects the left-hand library pane, then it will look for
* and return the reference to the right-hand pane.
*
* @param {Object} viewOrElement The item to check.
* @return {Object} Will return the best result node to batch, or null
* if one could not be found.
*/
function getResultForBatching(viewOrElement) {
if (viewOrElement && viewOrElement instanceof Ci.nsIDOMElement &&
viewOrElement.id === "placesList") {
// Note: fall back to the existing item if we can't find the right-hane pane.
viewOrElement = document.getElementById("placeContent") || viewOrElement;
}
if (viewOrElement && viewOrElement.result) {
return viewOrElement.result;
}
return null;
}
/**
* Processes a set of transfer items that have been dropped or pasted.
* Batching will be applied where necessary.
*
* @param {Array} items A list of unwrapped nodes to process.
* @param {Object} insertionPoint The requested point for insertion.
* @param {Boolean} doCopy Set to true to copy the items, false will move them
* if possible.
* @return {Array} Returns an empty array when the insertion point is a tag, else
* returns an array of copied or moved guids.
*/
async function handleTransferItems(items, insertionPoint, doCopy, view) {
let transactions;
let itemsCount;
if (insertionPoint.isTag) {
let urls = items.filter(item => "uri" in item).map(item => item.uri);
itemsCount = urls.length;
transactions = [PlacesTransactions.Tag({ urls, tag: insertionPoint.tagName })];
} else {
let insertionIndex = await insertionPoint.getIndex();
itemsCount = items.length;
transactions = await getTransactionsForTransferItems(
items, insertionIndex, insertionPoint.guid, doCopy);
}
// Check if we actually have something to add, if we don't it probably wasn't
// valid, or it was moving to the same location, so just ignore it.
if (!transactions.length) {
return [];
}
let guidsToSelect = [];
let resultForBatching = getResultForBatching(view);
// If we're inserting into a tag, we don't get the guid, so we'll just
// pass the transactions direct to the batch function.
let batchingItem = transactions;
if (!insertionPoint.isTag) {
// If we're not a tag, then we need to get the ids of the items to select.
batchingItem = async () => {
for (let transaction of transactions) {
let guid = await transaction.transact();
if (guid) {
guidsToSelect.push(guid);
}
}
};
}
await PlacesUIUtils.batchUpdatesForNode(resultForBatching, itemsCount, async () => {
await PlacesTransactions.batch(batchingItem);
});
return guidsToSelect;
}
/**
* Processes a set of transfer items and returns transactions to insert or
* move them.
*
* @param {Array} items A list of unwrapped nodes to get transactions for.
* @param {Integer} insertionIndex The requested index for insertion.
* @param {String} insertionParentGuid The guid of the parent folder to insert
* or move the items to.
* @param {Boolean} doCopy Set to true to copy the items, false will move them
* if possible.
* @return {Array} Returns an array of created PlacesTransactions.
*/
async function getTransactionsForTransferItems(items, insertionIndex,
insertionParentGuid, doCopy) {
let transactions = [];
let index = insertionIndex;
for (let item of items) {
if (index != -1 && item.itemGuid) {
// Note: we use the parent from the existing bookmark as the sidebar
// gives us an unwrapped.parent that is actually a query and not the real
// parent.
let existingBookmark = await PlacesUtils.bookmarks.fetch(item.itemGuid);
// If we're dropping on the same folder, then we may need to adjust
// the index to insert at the correct place.
if (existingBookmark && insertionParentGuid == existingBookmark.parentGuid) {
if (index > existingBookmark.index) {
// If we're dragging down, we need to go one lower to insert at
// the real point as moving the element changes the index of
// everything below by 1.
index--;
} else if (index == existingBookmark.index) {
// This isn't moving so we skip it.
continue;
}
}
}
// If this is not a copy, check for safety that we can move the
// source, otherwise report an error and fallback to a copy.
if (!doCopy && !PlacesControllerDragHelper.canMoveUnwrappedNode(item)) {
Cu.reportError("Tried to move an unmovable Places " +
"node, reverting to a copy operation.");
doCopy = true;
}
transactions.push(
PlacesUIUtils.getTransactionForData(item,
insertionParentGuid,
index,
doCopy));
if (index != -1 && item.itemGuid) {
index++;
}
}
return transactions;
}

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

@ -39,7 +39,7 @@ var gEditItemOverlay = {
// so we'll need to fetch it later.
}
let isURI = node && PlacesUtils.nodeIsURI(node);
let uri = isURI ? NetUtil.newURI(node.uri) : null;
let uri = isURI ? Services.io.newURI(node.uri) : null;
let title = node ? node.title : null;
let isBookmark = isItem && isURI;
let bulkTagging = !node;
@ -932,7 +932,7 @@ var gEditItemOverlay = {
// default to the bookmarks menu folder
if (!ip) {
ip = new InsertionPoint({
ip = new PlacesInsertionPoint({
parentId: PlacesUtils.bookmarksMenuFolderId,
parentGuid: PlacesUtils.bookmarks.menuGuid
});
@ -1072,7 +1072,7 @@ var gEditItemOverlay = {
switch (aProperty) {
case "uri":
let newURI = NetUtil.newURI(aValue);
let newURI = Services.ui.newURI(aValue);
if (!newURI.equals(this._paneInfo.uri)) {
this._paneInfo.uri = newURI;
if (this._paneInfo.visibleRows.has("locationRow"))

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

@ -90,7 +90,7 @@
if (!elt._placesNode) {
// If we are dragging over a non places node drop at the end.
dropPoint.ip = new InsertionPoint({
dropPoint.ip = new PlacesInsertionPoint({
parentId: PlacesUtils.getConcreteItemId(resultNode),
parentGuid: PlacesUtils.getConcreteItemGuid(resultNode)
});
@ -113,7 +113,7 @@
// This is a folder or a tag container.
if (eventY - eltY < eltHeight * 0.20) {
// If mouse is in the top part of the element, drop above folder.
dropPoint.ip = new InsertionPoint({
dropPoint.ip = new PlacesInsertionPoint({
parentId: PlacesUtils.getConcreteItemId(resultNode),
parentGuid: PlacesUtils.getConcreteItemGuid(resultNode),
orientation: Ci.nsITreeView.DROP_BEFORE,
@ -123,7 +123,7 @@
return dropPoint;
} else if (eventY - eltY < eltHeight * 0.80) {
// If mouse is in the middle of the element, drop inside folder.
dropPoint.ip = new InsertionPoint({
dropPoint.ip = new PlacesInsertionPoint({
parentId: PlacesUtils.getConcreteItemId(elt._placesNode),
parentGuid: PlacesUtils.getConcreteItemGuid(elt._placesNode),
tagName
@ -134,7 +134,7 @@
} else if (eventY - eltY <= eltHeight / 2) {
// This is a non-folder node or a readonly folder.
// If the mouse is above the middle, drop above this item.
dropPoint.ip = new InsertionPoint({
dropPoint.ip = new PlacesInsertionPoint({
parentId: PlacesUtils.getConcreteItemId(resultNode),
parentGuid: PlacesUtils.getConcreteItemGuid(resultNode),
orientation: Ci.nsITreeView.DROP_BEFORE,
@ -145,7 +145,7 @@
}
// Drop below the item.
dropPoint.ip = new InsertionPoint({
dropPoint.ip = new PlacesInsertionPoint({
parentId: PlacesUtils.getConcreteItemId(resultNode),
parentGuid: PlacesUtils.getConcreteItemGuid(resultNode),
orientation: Ci.nsITreeView.DROP_AFTER,
@ -350,7 +350,7 @@
// Force a copy action if parent node is a query or we are dragging a
// not-removable node.
if (!PlacesControllerDragHelper.canMoveNode(draggedElt, this._rootView))
if (!this._rootView.controller.canMoveNode(draggedElt))
event.dataTransfer.effectAllowed = "copyLink";
// Activate the view and cache the dragged element.

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

@ -25,11 +25,15 @@
"PlacesUIUtils", "resource:///modules/PlacesUIUtils.jsm");
ChromeUtils.defineModuleGetter(window,
"PlacesTransactions", "resource://gre/modules/PlacesTransactions.jsm");
ChromeUtils.defineModuleGetter(window,
"ForgetAboutSite", "resource://gre/modules/ForgetAboutSite.jsm");
XPCOMUtils.defineLazyScriptGetter(window, "PlacesTreeView",
"chrome://browser/content/places/treeView.js");
XPCOMUtils.defineLazyScriptGetter(window,
["PlacesInsertionPoint", "PlacesController", "PlacesControllerDragHelper"],
"chrome://browser/content/places/controller.js");
]]></script>
<script type="application/javascript"
src="chrome://browser/content/places/controller.js"/>
<!-- Bookmarks and history tooltip -->
<tooltip id="bhTooltip" noautohide="true"
@ -43,45 +47,45 @@
<commandset id="placesCommands"
commandupdater="true"
events="focus,sort,places"
oncommandupdate="goUpdatePlacesCommands();">
oncommandupdate="PlacesUIUtils.updateCommands(window);">
<command id="placesCmd_open"
oncommand="goDoPlacesCommand('placesCmd_open');"/>
oncommand="PlacesUIUtils.doCommand(window, 'placesCmd_open');"/>
<command id="placesCmd_open:window"
oncommand="goDoPlacesCommand('placesCmd_open:window');"/>
oncommand="PlacesUIUtils.doCommand(window, 'placesCmd_open:window');"/>
<command id="placesCmd_open:privatewindow"
oncommand="goDoPlacesCommand('placesCmd_open:privatewindow');"/>
oncommand="PlacesUIUtils.doCommand(window, 'placesCmd_open:privatewindow');"/>
<command id="placesCmd_open:tab"
oncommand="goDoPlacesCommand('placesCmd_open:tab');"/>
oncommand="PlacesUIUtils.doCommand(window, 'placesCmd_open:tab');"/>
<command id="placesCmd_new:bookmark"
oncommand="goDoPlacesCommand('placesCmd_new:bookmark');"/>
oncommand="PlacesUIUtils.doCommand(window, 'placesCmd_new:bookmark');"/>
<command id="placesCmd_new:folder"
oncommand="goDoPlacesCommand('placesCmd_new:folder');"/>
oncommand="PlacesUIUtils.doCommand(window, 'placesCmd_new:folder');"/>
<command id="placesCmd_new:separator"
oncommand="goDoPlacesCommand('placesCmd_new:separator');"/>
oncommand="PlacesUIUtils.doCommand(window, 'placesCmd_new:separator');"/>
<command id="placesCmd_show:info"
oncommand="goDoPlacesCommand('placesCmd_show:info');"/>
oncommand="PlacesUIUtils.doCommand(window, 'placesCmd_show:info');"/>
<command id="placesCmd_rename"
oncommand="goDoPlacesCommand('placesCmd_show:info');"
oncommand="PlacesUIUtils.doCommand(window, 'placesCmd_show:info');"
observes="placesCmd_show:info"/>
<command id="placesCmd_reload"
oncommand="goDoPlacesCommand('placesCmd_reload');"/>
oncommand="PlacesUIUtils.doCommand(window, 'placesCmd_reload');"/>
<command id="placesCmd_sortBy:name"
oncommand="goDoPlacesCommand('placesCmd_sortBy:name');"/>
oncommand="PlacesUIUtils.doCommand(window, 'placesCmd_sortBy:name');"/>
<command id="placesCmd_deleteDataHost"
oncommand="goDoPlacesCommand('placesCmd_deleteDataHost');"/>
oncommand="PlacesUIUtils.doCommand(window, 'placesCmd_deleteDataHost');"/>
<command id="placesCmd_createBookmark"
oncommand="goDoPlacesCommand('placesCmd_createBookmark');"/>
oncommand="PlacesUIUtils.doCommand(window, 'placesCmd_createBookmark');"/>
<!-- Special versions of cut/copy/paste/delete which check for an open context menu. -->
<command id="placesCmd_cut"
oncommand="goDoPlacesCommand('placesCmd_cut');"/>
oncommand="PlacesUIUtils.doCommand(window, 'placesCmd_cut');"/>
<command id="placesCmd_copy"
oncommand="goDoPlacesCommand('placesCmd_copy');"/>
oncommand="PlacesUIUtils.doCommand(window, 'placesCmd_copy');"/>
<command id="placesCmd_paste"
oncommand="goDoPlacesCommand('placesCmd_paste');"/>
oncommand="PlacesUIUtils.doCommand(window, 'placesCmd_paste');"/>
<command id="placesCmd_delete"
oncommand="goDoPlacesCommand('placesCmd_delete');"/>
oncommand="PlacesUIUtils.doCommand(window, 'placesCmd_delete');"/>
</commandset>
<menupopup id="placesContext"

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

@ -507,7 +507,7 @@
// Avoid the potentially expensive call to getChildIndex
// if we know this container doesn't allow insertion
if (PlacesControllerDragHelper.disallowInsertion(container, this))
if (this.controller.disallowInsertion(container))
return null;
var queryOptions = PlacesUtils.asQuery(result.root).queryOptions;
@ -530,7 +530,7 @@
}
}
if (PlacesControllerDragHelper.disallowInsertion(container, this))
if (this.controller.disallowInsertion(container))
return null;
// TODO (Bug 1160193): properly support dropping on a tag root.
@ -541,7 +541,7 @@
return null;
}
return new InsertionPoint({
return new PlacesInsertionPoint({
parentId: PlacesUtils.getConcreteItemId(container),
parentGuid: PlacesUtils.getConcreteItemGuid(container),
index, orientation, tagName, dropNearNode
@ -762,7 +762,7 @@
// If this node is child of a readonly container (e.g. a livemark)
// or cannot be moved, we must force a copy.
if (!PlacesControllerDragHelper.canMoveNode(node, this)) {
if (!this.controller.canMoveNode(node)) {
event.dataTransfer.effectAllowed = "copyLink";
break;
}

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

@ -1436,7 +1436,7 @@ PlacesTreeView.prototype = {
// Avoid the potentially expensive call to getChildIndex
// if we know this container doesn't allow insertion.
if (PlacesControllerDragHelper.disallowInsertion(container, this._tree.element))
if (this._controller.disallowInsertion(container))
return null;
let queryOptions = PlacesUtils.asQuery(this._result.root).queryOptions;
@ -1459,7 +1459,7 @@ PlacesTreeView.prototype = {
}
}
if (PlacesControllerDragHelper.disallowInsertion(container, this._tree.element))
if (this._controller.disallowInsertion(container))
return null;
// TODO (Bug 1160193): properly support dropping on a tag root.
@ -1470,7 +1470,7 @@ PlacesTreeView.prototype = {
return null;
}
return new InsertionPoint({
return new PlacesInsertionPoint({
parentId: PlacesUtils.getConcreteItemId(container),
parentGuid: PlacesUtils.getConcreteItemGuid(container),
index, orientation, tagName, dropNearNode

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

@ -28,7 +28,7 @@ add_task(async function() {
Assert.equal(tree.selectedNode.bookmarkGuid, folder.guid,
"Selected the expected node");
Assert.equal(tree.selectedNode.type, 6, "node is a folder");
Assert.ok(PlacesControllerDragHelper.canMoveNode(tree.selectedNode, tree),
Assert.ok(tree.controller.canMoveNode(tree.selectedNode),
"can move regular folder node");
info("Test a folder shortcut");
@ -43,7 +43,7 @@ add_task(async function() {
Assert.equal(tree.selectedNode.type, 9, "node is a folder shortcut");
Assert.equal(PlacesUtils.getConcreteItemGuid(tree.selectedNode),
folder.guid, "shortcut node guid and concrete guid match");
Assert.ok(PlacesControllerDragHelper.canMoveNode(tree.selectedNode, tree),
Assert.ok(tree.controller.canMoveNode(tree.selectedNode),
"can move folder shortcut node");
info("Test a query");
@ -63,7 +63,7 @@ add_task(async function() {
tree.selectItems([query.guid]);
Assert.equal(tree.selectedNode.bookmarkGuid, query.guid,
"Selected the expected node");
Assert.ok(PlacesControllerDragHelper.canMoveNode(tree.selectedNode, tree),
Assert.ok(tree.controller.canMoveNode(tree.selectedNode),
"can move query node");
@ -79,7 +79,7 @@ add_task(async function() {
PlacesUtils.asQuery(tree.selectedNode).containerOpen = true;
Assert.equal(tree.selectedNode.childCount, 1, "has tags");
let tagNode = tree.selectedNode.getChild(0);
Assert.ok(!PlacesControllerDragHelper.canMoveNode(tagNode, tree),
Assert.ok(!tree.controller.canMoveNode(tagNode),
"should not be able to move tag container node");
tree.selectedNode.containerOpen = false;
@ -92,7 +92,7 @@ add_task(async function() {
for (let guid of roots) {
tree.selectItems([guid]);
Assert.ok(!PlacesControllerDragHelper.canMoveNode(tree.selectedNode, tree),
Assert.ok(!tree.controller.canMoveNode(tree.selectedNode),
"shouldn't be able to move default shortcuts to roots");
let id = await PlacesUtils.promiseItemId(guid);
let s = await PlacesUtils.bookmarks.insert({
@ -103,7 +103,7 @@ add_task(async function() {
tree.selectItems([s.guid]);
Assert.equal(tree.selectedNode.bookmarkGuid, s.guid,
"Selected the expected node");
Assert.ok(PlacesControllerDragHelper.canMoveNode(tree.selectedNode, tree),
Assert.ok(tree.controller.canMoveNode(tree.selectedNode),
"should be able to move user-created shortcuts to roots");
}
});

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

@ -34,7 +34,7 @@ add_task(async function test() {
let tree = sidebar.contentDocument.getElementById("bookmarks-view");
tree.focus();
let controller = doGetPlacesControllerForCommand("placesCmd_copy");
let controller = PlacesUIUtils.getControllerForCommand(window, "placesCmd_copy");
let treeController = tree.controllers
.getControllerForCommand("placesCmd_copy");
ok(controller == treeController, "tree controller was returned");
@ -45,7 +45,7 @@ add_task(async function test() {
EventUtils.synthesizeMouse(toolbarItems.childNodes[0],
4, 4, { type: "contextmenu", button: 2 },
window);
controller = doGetPlacesControllerForCommand("placesCmd_copy");
controller = PlacesUIUtils.getControllerForCommand(window, "placesCmd_copy");
let toolbarController = document.getElementById("PlacesToolbar")
.controllers
.getControllerForCommand("placesCmd_copy");
@ -55,7 +55,7 @@ add_task(async function test() {
// Now that the context menu is closed, try to get the tree controller again.
tree.focus();
controller = doGetPlacesControllerForCommand("placesCmd_copy");
controller = PlacesUIUtils.getControllerForCommand(window, "placesCmd_copy");
ok(controller == treeController, "tree controller was returned");
if (wasCollapsed) {

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

@ -76,7 +76,7 @@ async function run_drag_test(startBookmarkIndex, insertionIndex, newParentGuid,
// Simulating a drag-drop with a tree view turns out to be really difficult
// as you can't get a node for the source/target. Hence, we fake the
// insertion point and drag data and call the function direct.
let ip = new InsertionPoint({
let ip = new PlacesInsertionPoint({
parentId: await PlacesUtils.promiseItemId(PlacesUtils.bookmarks.unfiledGuid),
parentGuid: newParentGuid,
index: insertionIndex,

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

@ -69,7 +69,7 @@ async function simulateDrop(selectTargets, sourceBm, dropEffect, targetGuid,
Assert.equal(dataTransfer.dropEffect, dropEffect);
let ip = new InsertionPoint({
let ip = new PlacesInsertionPoint({
parentId: await PlacesUtils.promiseItemId(targetGuid),
parentGuid: targetGuid,
index: 0,

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

@ -56,7 +56,7 @@ async function run_drag_test(startBookmarkIndex, newParentGuid) {
// Simulating a drag-drop with a tree view turns out to be really difficult
// as you can't get a node for the source/target. Hence, we fake the
// insertion point and drag data and call the function direct.
let ip = new InsertionPoint({
let ip = new PlacesInsertionPoint({
isTag: true,
tagName: TAG_NAME,
orientation: Ci.nsITreeView.DROP_ON

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

@ -25,38 +25,38 @@ add_task(async function test_date_container() {
let PO = library.PlacesOrganizer;
PO.selectLeftPaneBuiltIn("History");
isnot(PO._places.selectedNode, null, "We correctly selected History");
Assert.notEqual(PO._places.selectedNode, null, "We correctly selected History");
// Check that both delete and cut commands are disabled, cause this is
// a child of the left pane folder.
ok(PO._places.controller.isCommandEnabled("cmd_copy"),
"Copy command is enabled");
ok(!PO._places.controller.isCommandEnabled("cmd_cut"),
"Cut command is disabled");
ok(!PO._places.controller.isCommandEnabled("cmd_delete"),
"Delete command is disabled");
Assert.ok(PO._places.controller.isCommandEnabled("cmd_copy"),
"Copy command is enabled");
Assert.ok(!PO._places.controller.isCommandEnabled("cmd_cut"),
"Cut command is disabled");
Assert.ok(!PO._places.controller.isCommandEnabled("cmd_delete"),
"Delete command is disabled");
let historyNode = PlacesUtils.asContainer(PO._places.selectedNode);
historyNode.containerOpen = true;
// Check that we have a child container. It is "Today" container.
is(historyNode.childCount, 1, "History node has one child");
Assert.equal(historyNode.childCount, 1, "History node has one child");
let todayNode = historyNode.getChild(0);
let todayNodeExpectedTitle = PlacesUtils.getString("finduri-AgeInDays-is-0");
is(todayNode.title, todayNodeExpectedTitle,
"History child is the expected container");
Assert.equal(todayNode.title, todayNodeExpectedTitle,
"History child is the expected container");
// Select "Today" container.
PO._places.selectNode(todayNode);
is(PO._places.selectedNode, todayNode,
"We correctly selected Today container");
Assert.equal(PO._places.selectedNode, todayNode,
"We correctly selected Today container");
// Check that delete command is enabled but cut command is disabled, cause
// this is an history item.
ok(PO._places.controller.isCommandEnabled("cmd_copy"),
"Copy command is enabled");
ok(!PO._places.controller.isCommandEnabled("cmd_cut"),
"Cut command is disabled");
ok(PO._places.controller.isCommandEnabled("cmd_delete"),
"Delete command is enabled");
Assert.ok(PO._places.controller.isCommandEnabled("cmd_copy"),
"Copy command is enabled");
Assert.ok(!PO._places.controller.isCommandEnabled("cmd_cut"),
"Cut command is disabled");
Assert.ok(PO._places.controller.isCommandEnabled("cmd_delete"),
"Delete command is enabled");
// Execute the delete command and check visit has been removed.
let promiseURIRemoved = PlacesTestUtils.waitForNotification(
@ -65,11 +65,11 @@ add_task(async function test_date_container() {
await promiseURIRemoved;
// Test live update of "History" query.
is(historyNode.childCount, 0, "History node has no more children");
Assert.equal(historyNode.childCount, 0, "History node has no more children");
historyNode.containerOpen = false;
ok(!(await PlacesUtils.history.hasVisits(TEST_URI)), "Visit has been removed");
Assert.ok(!(await PlacesUtils.history.hasVisits(TEST_URI)), "Visit has been removed");
library.close();
});
@ -82,19 +82,19 @@ add_task(async function test_query_on_toolbar() {
let PO = library.PlacesOrganizer;
PO.selectLeftPaneBuiltIn("BookmarksToolbar");
isnot(PO._places.selectedNode, null, "We have a valid selection");
is(PlacesUtils.getConcreteItemId(PO._places.selectedNode),
PlacesUtils.toolbarFolderId,
"We have correctly selected bookmarks toolbar node.");
Assert.notEqual(PO._places.selectedNode, null, "We have a valid selection");
Assert.equal(PlacesUtils.getConcreteItemId(PO._places.selectedNode),
PlacesUtils.toolbarFolderId,
"We have correctly selected bookmarks toolbar node.");
// Check that both cut and delete commands are disabled, cause this is a child
// of the All Bookmarks special query.
ok(PO._places.controller.isCommandEnabled("cmd_copy"),
"Copy command is enabled");
ok(!PO._places.controller.isCommandEnabled("cmd_cut"),
"Cut command is disabled");
ok(!PO._places.controller.isCommandEnabled("cmd_delete"),
"Delete command is disabled");
Assert.ok(PO._places.controller.isCommandEnabled("cmd_copy"),
"Copy command is enabled");
Assert.ok(!PO._places.controller.isCommandEnabled("cmd_cut"),
"Cut command is disabled");
Assert.ok(!PO._places.controller.isCommandEnabled("cmd_delete"),
"Delete command is disabled");
let toolbarNode = PlacesUtils.asContainer(PO._places.selectedNode);
toolbarNode.containerOpen = true;
@ -107,21 +107,21 @@ add_task(async function test_query_on_toolbar() {
index: 0 });
// Get first child and check it is the just inserted query.
ok(toolbarNode.childCount > 0, "Toolbar node has children");
Assert.ok(toolbarNode.childCount > 0, "Toolbar node has children");
let queryNode = toolbarNode.getChild(0);
is(queryNode.title, "special_query", "Query node is correctly selected");
Assert.equal(queryNode.title, "special_query", "Query node is correctly selected");
// Select query node.
PO._places.selectNode(queryNode);
is(PO._places.selectedNode, queryNode, "We correctly selected query node");
Assert.equal(PO._places.selectedNode, queryNode, "We correctly selected query node");
// Check that both cut and delete commands are enabled.
ok(PO._places.controller.isCommandEnabled("cmd_copy"),
"Copy command is enabled");
ok(PO._places.controller.isCommandEnabled("cmd_cut"),
"Cut command is enabled");
ok(PO._places.controller.isCommandEnabled("cmd_delete"),
"Delete command is enabled");
Assert.ok(PO._places.controller.isCommandEnabled("cmd_copy"),
"Copy command is enabled");
Assert.ok(PO._places.controller.isCommandEnabled("cmd_cut"),
"Cut command is enabled");
Assert.ok(PO._places.controller.isCommandEnabled("cmd_delete"),
"Delete command is enabled");
// Execute the delete command and check bookmark has been removed.
let promiseItemRemoved = PlacesTestUtils.waitForNotification(
@ -129,7 +129,7 @@ add_task(async function test_query_on_toolbar() {
PO._places.controller.doCommand("cmd_delete");
await promiseItemRemoved;
is((await PlacesUtils.bookmarks.fetch(query.guid)), null,
Assert.equal((await PlacesUtils.bookmarks.fetch(query.guid)), null,
"Query node bookmark has been correctly removed");
toolbarNode.containerOpen = false;
@ -151,25 +151,25 @@ add_task(async function test_search_contents() {
let PO = library.PlacesOrganizer;
PO.selectLeftPaneBuiltIn("BookmarksToolbar");
isnot(PO._places.selectedNode, null, "We have a valid selection");
is(PlacesUtils.getConcreteItemId(PO._places.selectedNode),
PlacesUtils.toolbarFolderId,
"We have correctly selected bookmarks toolbar node.");
Assert.notEqual(PO._places.selectedNode, null, "We have a valid selection");
Assert.equal(PlacesUtils.getConcreteItemId(PO._places.selectedNode),
PlacesUtils.toolbarFolderId,
"We have correctly selected bookmarks toolbar node.");
let searchBox = library.document.getElementById("searchFilter");
searchBox.value = "example";
library.PlacesSearchBox.search(searchBox.value);
let bookmarkNode = library.ContentTree.view.selectedNode;
is(bookmarkNode.uri, "http://example.com/", "Found the expected bookmark");
Assert.equal(bookmarkNode.uri, "http://example.com/", "Found the expected bookmark");
// Check that both cut and delete commands are enabled.
ok(library.ContentTree.view.controller.isCommandEnabled("cmd_copy"),
"Copy command is enabled");
ok(library.ContentTree.view.controller.isCommandEnabled("cmd_cut"),
"Cut command is enabled");
ok(library.ContentTree.view.controller.isCommandEnabled("cmd_delete"),
"Delete command is enabled");
Assert.ok(library.ContentTree.view.controller.isCommandEnabled("cmd_copy"),
"Copy command is enabled");
Assert.ok(library.ContentTree.view.controller.isCommandEnabled("cmd_cut"),
"Cut command is enabled");
Assert.ok(library.ContentTree.view.controller.isCommandEnabled("cmd_delete"),
"Delete command is enabled");
library.close();
});
@ -190,44 +190,44 @@ add_task(async function test_tags() {
PO.selectLeftPaneBuiltIn("Tags");
let tagsNode = PO._places.selectedNode;
isnot(tagsNode, null, "We have a valid selection");
Assert.notEqual(tagsNode, null, "We have a valid selection");
let tagsTitle = PlacesUtils.getString("TagsFolderTitle");
is(tagsNode.title, tagsTitle,
"Tags has been properly selected");
Assert.equal(tagsNode.title, tagsTitle,
"Tags has been properly selected");
// Check that both cut and delete commands are disabled.
ok(PO._places.controller.isCommandEnabled("cmd_copy"),
"Copy command is enabled");
ok(!PO._places.controller.isCommandEnabled("cmd_cut"),
"Cut command is disabled");
ok(!PO._places.controller.isCommandEnabled("cmd_delete"),
"Delete command is disabled");
Assert.ok(PO._places.controller.isCommandEnabled("cmd_copy"),
"Copy command is enabled");
Assert.ok(!PO._places.controller.isCommandEnabled("cmd_cut"),
"Cut command is disabled");
Assert.ok(!PO._places.controller.isCommandEnabled("cmd_delete"),
"Delete command is disabled");
// Now select the tag.
PlacesUtils.asContainer(tagsNode).containerOpen = true;
let tag = tagsNode.getChild(0);
PO._places.selectNode(tag);
is(PO._places.selectedNode.title, "test",
"The created tag has been properly selected");
Assert.equal(PO._places.selectedNode.title, "test",
"The created tag has been properly selected");
// Check that cut is disabled but delete is enabled.
ok(PO._places.controller.isCommandEnabled("cmd_copy"),
"Copy command is enabled");
ok(!PO._places.controller.isCommandEnabled("cmd_cut"),
"Cut command is disabled");
ok(PO._places.controller.isCommandEnabled("cmd_delete"),
"Delete command is enabled");
Assert.ok(PO._places.controller.isCommandEnabled("cmd_copy"),
"Copy command is enabled");
Assert.ok(!PO._places.controller.isCommandEnabled("cmd_cut"),
"Cut command is disabled");
Assert.ok(PO._places.controller.isCommandEnabled("cmd_delete"),
"Delete command is enabled");
let bookmarkNode = library.ContentTree.view.selectedNode;
is(bookmarkNode.uri, "http://example.com/", "Found the expected bookmark");
Assert.equal(bookmarkNode.uri, "http://example.com/", "Found the expected bookmark");
// Check that both cut and delete commands are enabled.
ok(library.ContentTree.view.controller.isCommandEnabled("cmd_copy"),
"Copy command is enabled");
ok(!library.ContentTree.view.controller.isCommandEnabled("cmd_cut"),
"Cut command is disabled");
ok(library.ContentTree.view.controller.isCommandEnabled("cmd_delete"),
"Delete command is enabled");
Assert.ok(library.ContentTree.view.controller.isCommandEnabled("cmd_copy"),
"Copy command is enabled");
Assert.ok(!library.ContentTree.view.controller.isCommandEnabled("cmd_cut"),
"Cut command is disabled");
Assert.ok(library.ContentTree.view.controller.isCommandEnabled("cmd_delete"),
"Delete command is enabled");
tagsNode.containerOpen = false;

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

@ -174,7 +174,6 @@ skip-if = true # Bug 1437843
skip-if = true # Bug 1437844
[browser_console_context_menu_entries.js]
[browser_console_dead_objects.js]
skip-if = true # Bug 1437845
[browser_console_error_source_click.js]
[browser_console_filters.js]
[browser_console_nsiconsolemessage.js]

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

@ -3,93 +3,41 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/* import-globals-from head.js */
// Check that Dead Objects do not break the Web/Browser Consoles.
// See bug 883649.
// This test does:
// - opens a new tab,
// - opens the Browser Console,
// - stores a reference to the content document of the tab on the chrome
// window object,
// - closes the tab,
// - tries to use the object that was pointing to the now-defunct content
// document. This is the dead object.
//
// This test:
// - Opens the Browser Console.
// - Creates a sandbox.
// - Stores a reference to the sandbox on the chrome window object.
// - Nukes the sandbox
// - Tries to use the sandbox. This is the dead object.
"use strict";
const TEST_URI = "data:text/html;charset=utf8,<p>dead objects!";
add_task(async function () {
let hud = await HUDService.toggleBrowserConsole();
ok(hud, "browser console opened");
function test() {
let hud = null;
let jsterm = hud.jsterm;
registerCleanupFunction(() => {
Services.prefs.clearUserPref("devtools.chrome.enabled");
});
// Add the reference to the nuked sandbox.
await jsterm.execute("window.nukedSandbox = Cu.Sandbox(null);" +
"Cu.nukeSandbox(nukedSandbox);");
Task.spawn(runner).then(finishTest);
await jsterm.execute("nukedSandbox");
await waitFor(() => findMessage(hud, "DeadObject", ".objectTitle"));
function* runner() {
Services.prefs.setBoolPref("devtools.chrome.enabled", true);
yield loadTab(TEST_URI);
let browser = gBrowser.selectedBrowser;
let winID = browser.outerWindowID;
jsterm.execute("nukedSandbox.hello");
let msg = await waitFor(() => findMessage(hud, "can't access dead object"));
info("open the browser console");
// Check that the link contains an anchor. We can't click on the link because
// clicking links from tests attempts to access an external URL and crashes
// Firefox.
let anchor = msg.querySelector("a");
is(anchor.textContent, "[Learn More]", "Link text is correct");
hud = yield HUDService.toggleBrowserConsole();
ok(hud, "browser console opened");
let jsterm = hud.jsterm;
jsterm.clearOutput();
// Add the reference to the content document.
yield jsterm.execute("Cu = Components.utils;" +
"Cu.import('resource://gre/modules/Services.jsm');" +
"chromeWindow = Services.wm.getMostRecentWindow('" +
"navigator:browser');" +
"foobarzTezt = chromeWindow.content.document;" +
"delete chromeWindow");
gBrowser.removeCurrentTab();
yield TestUtils.topicObserved("outer-window-nuked", (subject, data) => {
let id = subject.QueryInterface(Ci.nsISupportsPRUint64).data;
return id == winID;
});
let msg = yield jsterm.execute("foobarzTezt");
isnot(hud.outputNode.textContent.indexOf("DeadObject"), -1,
"dead object found");
jsterm.setInputValue("foobarzTezt");
for (let c of ".hello") {
EventUtils.synthesizeKey(c, {}, hud.iframeWindow);
}
yield jsterm.execute();
isnot(hud.outputNode.textContent.indexOf("can't access dead object"), -1,
"'cannot access dead object' message found");
// Click the second execute output.
let clickable = msg.querySelector("a");
ok(clickable, "clickable object found");
isnot(clickable.textContent.indexOf("DeadObject"), -1,
"message text check");
msg.scrollIntoView();
executeSoon(() => {
EventUtils.synthesizeMouseAtCenter(clickable, {}, hud.iframeWindow);
});
yield jsterm.once("variablesview-fetched");
ok(true, "variables view fetched");
msg = yield jsterm.execute("delete window.foobarzTezt; 2013-26");
isnot(msg.textContent.indexOf("1987"), -1, "result message found");
}
}
await jsterm.execute("delete window.nukedSandbox; 2013-26");
await waitFor(() => findMessage(hud, "1987"));
});

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

@ -2544,14 +2544,7 @@ Console::MonotonicTimer(JSContext* aCx, MethodName aMethodName,
}
if (NS_IsMainThread()) {
double duration = (TimeStamp::Now() - mCreationTimeStamp).ToMilliseconds();
// Round down to the nearest 5us, because if the timer is too accurate
// people can do nasty timing attacks with it. See similar code in the
// worker Performance implementation.
const double maxResolutionMs = 0.005;
*aTimeStamp = nsRFPService::ReduceTimePrecisionAsMSecs(
floor(duration / maxResolutionMs) * maxResolutionMs);
*aTimeStamp = (TimeStamp::Now() - mCreationTimeStamp).ToMilliseconds();
return true;
}

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

@ -447,7 +447,7 @@ MP3TrackDemuxer::FindFirstFrame()
" Length()=%" PRIu64,
candidateFrame.mStart, candidateFrame.Length());
while (candidateFrame.Length() && numSuccFrames < MIN_SUCCESSIVE_FRAMES) {
while (candidateFrame.Length()) {
mParser.EndFrameSession();
mOffset = currentFrame.mEnd;
const MediaByteRange prevFrame = currentFrame;
@ -473,16 +473,26 @@ MP3TrackDemuxer::FindFirstFrame()
MP3LOGV("FindFirst() new candidate frame: mOffset=%" PRIu64
" Length()=%" PRIu64,
candidateFrame.mStart, candidateFrame.Length());
} else if (numSuccFrames >= MIN_SUCCESSIVE_FRAMES) {
MP3LOG("FindFirst() accepting candidate frame: "
"successiveFrames=%d", numSuccFrames);
mFrameLock = true;
return candidateFrame;
} else if (prevFrame.mStart == mParser.ID3Header().TotalTagSize() &&
currentFrame.mEnd == StreamLength()) {
// We accept streams with only two frames if both frames are valid. This
// is to handle very short files and provide parity with Chrome. See
// bug 1432195 for more information. This will not handle short files
// with a trailing tag, but as of writing we lack infrastructure to
// handle such tags.
MP3LOG("FindFirst() accepting candidate frame for short stream: "
"successiveFrames=%d", numSuccFrames);
mFrameLock = true;
return candidateFrame;
}
}
if (numSuccFrames >= MIN_SUCCESSIVE_FRAMES) {
MP3LOG("FindFirst() accepting candidate frame: "
"successiveFrames=%d", numSuccFrames);
mFrameLock = true;
} else {
MP3LOG("FindFirst() no suitable first frame found");
}
MP3LOG("FindFirst() no suitable first frame found");
return candidateFrame;
}

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

@ -29,10 +29,12 @@ IsWhitelistedH264Codec(const nsAString& aCodec)
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd797815%28v=vs.85%29.aspx
// "The Media Foundation H.264 video decoder is a Media Foundation Transform
// that supports decoding of Baseline, Main, and High profiles, up to level
// 5.1.". We also report that we can play Extended profile, as there are
// 5.1.". We extend the limit to level 5.2, relying on the decoder to handle
// any potential errors, the level limit being rather arbitrary.
// We also report that we can play Extended profile, as there are
// bitstreams that are Extended compliant that are also Baseline compliant.
return level >= H264_LEVEL_1 &&
level <= H264_LEVEL_5_1 &&
level <= H264_LEVEL_5_2 &&
(profile == H264_PROFILE_BASE ||
profile == H264_PROFILE_MAIN ||
profile == H264_PROFILE_EXTENDED ||

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

@ -14,7 +14,6 @@
#include "WebRenderTypes.h"
#include "webrender_ffi.h"
#include <iostream>
#include <unordered_map>
#ifdef XP_MACOSX

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

@ -17,7 +17,6 @@
#include "FrameLayerBuilder.h"
#include "nsPrintfCString.h"
#include <iostream>
#include <stdio.h>
using namespace mozilla;
@ -267,7 +266,7 @@ PrintDisplayItemToStdout(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem)
{
std::stringstream stream;
PrintDisplayItemTo(aBuilder, aItem, stream, 0, true, false);
std::cout << stream.str() << std::endl;
puts(stream.str().c_str());
}
void
@ -275,7 +274,7 @@ PrintDisplayListToStdout(nsDisplayListBuilder* aBuilder, const nsDisplayList& aL
{
std::stringstream stream;
PrintDisplayListTo(aBuilder, aList, stream, 0, false);
std::cout << stream.str() << std::endl;
puts(stream.str().c_str());
}
#ifdef MOZ_DUMP_PAINTING

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

@ -4,7 +4,6 @@
#include "WebrtcGmpVideoCodec.h"
#include <iostream>
#include <vector>
#include "mozilla/CheckedInt.h"

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

@ -33,7 +33,6 @@
#ifndef WEBRTCGMPVIDEOCODEC_H_
#define WEBRTCGMPVIDEOCODEC_H_
#include <iostream>
#include <queue>
#include <string>

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

@ -3,7 +3,6 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <cstdio>
#include <iostream>
#include <queue>
#include "CSFLog.h"

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

@ -82,6 +82,10 @@ class CentOSFedoraBootstrapper(StyloInstall, BaseBootstrapper):
'python-dbus',
]
self.mobile_android_packages += [
'ncurses-compat-libs',
]
def install_system_packages(self):
self.dnf_groupinstall(*self.group_packages)
self.dnf_install(*self.packages)

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

@ -8,7 +8,6 @@
#define security_sandbox_loggingCallbacks_h__
#include <sstream>
#include <iostream>
#include "mozilla/Logging.h"
#include "mozilla/Preferences.h"

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

@ -727,7 +727,9 @@ BufferedBookmarksEngine.prototype = {
let buf = await this._store.ensureOpenMirror();
let recordsToUpload = await buf.apply({
remoteTimeSeconds: Resource.serverTime,
weakUpload: [...this._needWeakUpload.keys()],
});
this._needWeakUpload.clear();
this._modified.replace(recordsToUpload);
},
@ -736,9 +738,6 @@ BufferedBookmarksEngine.prototype = {
},
async _createRecord(id) {
if (this._needWeakUpload.has(id)) {
return this._store.createRecord(id, this.name);
}
let change = this._modified.changes[id];
if (!change) {
this._log.error("Creating record for item ${id} not in strong " +

49
servo/Cargo.lock сгенерированный
Просмотреть файл

@ -90,14 +90,14 @@ dependencies = [
[[package]]
name = "azure"
version = "0.27.0"
source = "git+https://github.com/servo/rust-azure#46a9c9c6279ba46354b48f6fc849ee20624cbf90"
version = "0.28.0"
source = "git+https://github.com/servo/rust-azure#29f0c063ad366b5364e06af26d3e9d1ee588e3b2"
dependencies = [
"cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
"servo-freetype-sys 4.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"servo-skia 0.30000012.0 (registry+https://github.com/rust-lang/crates.io-index)",
"servo-skia 0.30000013.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -270,7 +270,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
name = "canvas"
version = "0.0.1"
dependencies = [
"azure 0.27.0 (git+https://github.com/servo/rust-azure)",
"azure 0.28.0 (git+https://github.com/servo/rust-azure)",
"canvas_traits 0.0.1",
"compositing 0.0.1",
"cssparser 0.23.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -757,6 +757,15 @@ dependencies = [
"dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "dwmapi-sys"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "dwrote"
version = "0.4.2"
@ -2634,7 +2643,7 @@ dependencies = [
"osmesa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"script_traits 0.0.1",
"servo-egl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"servo-glutin 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)",
"servo-glutin 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
"servo_config 0.0.1",
"servo_geometry 0.0.1",
"servo_url 0.0.1",
@ -2684,7 +2693,7 @@ dependencies = [
[[package]]
name = "servo-glutin"
version = "0.14.2"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"android_glue 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2692,20 +2701,25 @@ dependencies = [
"cocoa 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
"core-foundation 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"core-graphics 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
"dwmapi-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gl_generator 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"image 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)",
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
"objc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"osmesa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"shared_library 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"shell32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"x11-dl 2.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "servo-skia"
version = "0.30000012.0"
version = "0.30000013.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cgl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2719,7 +2733,7 @@ dependencies = [
"servo-egl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"servo-fontconfig-sys 4.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"servo-freetype-sys 4.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"servo-glutin 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)",
"servo-glutin 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
"x11 2.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -2840,6 +2854,15 @@ dependencies = [
"libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "shell32-sys"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "sig"
version = "0.1.1"
@ -3585,7 +3608,7 @@ dependencies = [
"checksum atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fb2dcb6e6d35f20276943cc04bb98e538b348d525a04ac79c10021561d202f21"
"checksum atty 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "21e50800ec991574876040fff8ee46b136a53e985286fbe6a3bdfe6421b78860"
"checksum audio-video-metadata 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "71536082079f5ba92c274fba7c2dcd4e2f9d5c13ce6d7f8fe9acbbb258916d18"
"checksum azure 0.27.0 (git+https://github.com/servo/rust-azure)" = "<none>"
"checksum azure 0.28.0 (git+https://github.com/servo/rust-azure)" = "<none>"
"checksum backtrace 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "72f9b4182546f4b04ebc4ab7f84948953a118bd6021a1b6a6c909e3e94f6be76"
"checksum backtrace-sys 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3a0d842ea781ce92be2bf78a9b38883948542749640b8378b3b2f03d1fd9f1ff"
"checksum base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96434f987501f0ed4eb336a411e0631ecd1afa11574fe148587adc4ff96143c9"
@ -3639,6 +3662,7 @@ dependencies = [
"checksum device 0.0.1 (git+https://github.com/servo/devices)" = "<none>"
"checksum dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "80c8b71fd71146990a9742fc06dcbbde19161a267e0ad4e572c35162f4578c90"
"checksum dtoa-short 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fe6f727b406462fd57c95fed84d1b0dbfb5f0136fcac005adba9ea0367c05cc8"
"checksum dwmapi-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b44b6442aeab12e609aee505bd1066bdfd36b79c3fe5aad604aae91537623e76"
"checksum dwrote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b26e30aaa6bf31ec830db15fec14ed04f0f2ecfcc486ecfce88c55d3389b237f"
"checksum either 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18785c1ba806c258137c937e44ada9ee7e69a37e3c72077542cd2f069d78562a"
"checksum encoding_rs 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f5215aabf22b83153be3ee44dfe3f940214541b2ce13d419c55e7a115c8c51a9"
@ -3790,11 +3814,12 @@ dependencies = [
"checksum servo-fontconfig 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "93f799b649b4a2bf362398910eca35240704c7e765e780349b2bb1070d892262"
"checksum servo-fontconfig-sys 4.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "38b494f03009ee81914b0e7d387ad7c145cafcd69747c2ec89b0e17bb94f303a"
"checksum servo-freetype-sys 4.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9232032c2e85118c0282c6562c84cab12316e655491ba0a5d1905b2320060d1b"
"checksum servo-glutin 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cf265a35f2d23d3ed2fae943fda4b6dda861c86b25c1c99f9ca77a37cfa6ee7c"
"checksum servo-skia 0.30000012.0 (registry+https://github.com/rust-lang/crates.io-index)" = "80980e6eb854c06e8e45fa3cfbd439bf4223a6840f38c3caec34efa39cf9405e"
"checksum servo-glutin 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a36b9398e9cade5b1e3011d841d9d98d4e86a538a1b639db62100d86134c10f6"
"checksum servo-skia 0.30000013.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1be5e09cb97ea135d1223fa226f8880f124aed2fa887bf5acf10ef16ad94e072"
"checksum servo-websocket 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efde78dfcf2178d5a11e1e2268e0d8df0627dfe2724546db8585d6678e1af150"
"checksum sha1 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cc30b1e1e8c40c121ca33b86c23308a090d19974ef001b4bf6e61fd1a0fb095c"
"checksum shared_library 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fb04126b6fcfd2710fb5b6d18f4207b6c535f2850a7e1a43bcd526d44f30a79a"
"checksum shell32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9ee04b46101f57121c9da2b151988283b6beb79b34f5bb29a58ee48cb695122c"
"checksum sig 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c6649e43c1a1e68d29ed56d0dc3b5b6cf3b901da77cf107c4066b9e3da036df5"
"checksum signpost 0.1.0 (git+https://github.com/pcwalton/signpost.git)" = "<none>"
"checksum simd 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a94d14a2ae1f1f110937de5fb69e494372560181c7e1739a097fcc2cee37ba0"

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

@ -76,16 +76,6 @@ fn generate_properties() {
.arg(&script)
.arg(product)
.arg("style-crate")
.envs(if std::mem::size_of::<Option<bool>>() == 1 {
// FIXME: remove this envs() call
// and make unconditional code that depends on RUSTC_HAS_PR45225
// once Firefox requires Rust 1.23+
// https://github.com/rust-lang/rust/pull/45225
vec![("RUSTC_HAS_PR45225", "1")]
} else {
vec![]
})
.status()
.unwrap();
if !status.success() {

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

@ -32,8 +32,7 @@ def main():
properties = data.PropertiesData(product=product)
template = os.path.join(BASE, "properties.mako.rs")
rust = render(template, product=product, data=properties, __file__=template,
RUSTC_HAS_PR45225=os.environ.get("RUSTC_HAS_PR45225"))
rust = render(template, product=product, data=properties, __file__=template)
if output == "style-crate":
write(os.environ["OUT_DIR"], "properties.rs", rust)
if product == "gecko":

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

@ -66,9 +66,9 @@ ${helpers.predefined_type(
"stroke-width", "SVGWidth",
"::values::computed::NonNegativeLength::new(1.).into()",
products="gecko",
boxed=not RUSTC_HAS_PR45225,
animation_value_type="::values::computed::SVGWidth",
spec="https://www.w3.org/TR/SVG2/painting.html#StrokeWidth")}
spec="https://www.w3.org/TR/SVG2/painting.html#StrokeWidth",
)}
${helpers.single_keyword("stroke-linecap", "butt round square",
products="gecko", animation_value_type="discrete",
@ -101,9 +101,9 @@ ${helpers.predefined_type(
"stroke-dashoffset", "SVGLength",
"Au(0).into()",
products="gecko",
boxed=not RUSTC_HAS_PR45225,
animation_value_type="ComputedValue",
spec="https://www.w3.org/TR/SVG2/painting.html#StrokeDashing")}
spec="https://www.w3.org/TR/SVG2/painting.html#StrokeDashing",
)}
// Section 14 - Clipping, Masking and Compositing
${helpers.single_keyword("clip-rule", "nonzero evenodd",

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

@ -47,7 +47,6 @@ ${helpers.predefined_type(
"generics::pointing::CaretColor::Auto",
spec="https://drafts.csswg.org/css-ui/#caret-color",
animation_value_type="AnimatedCaretColor",
boxed=not RUSTC_HAS_PR45225,
ignored_when_colors_disabled=True,
products="gecko",
)}

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

@ -1 +1 @@
1.23.0
1.24.0

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

@ -35,7 +35,7 @@ log = "0.3.5"
msg = {path = "../../components/msg"}
net_traits = {path = "../../components/net_traits"}
script_traits = {path = "../../components/script_traits"}
servo-glutin = "0.14"
servo-glutin = "0.15"
servo_geometry = {path = "../../components/geometry"}
servo_config = {path = "../../components/config"}
servo_url = {path = "../../components/url"}

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

@ -535,6 +535,7 @@ Connection::Connection(Service *aService,
, mAsyncExecutionThreadShuttingDown(false)
, mConnectionClosed(false)
, mTransactionInProgress(false)
, mDestroying(false)
, mProgressHandler(nullptr)
, mFlags(aFlags)
, mIgnoreLockingMode(aIgnoreLockingMode)
@ -572,56 +573,51 @@ NS_IMETHODIMP_(MozExternalRefCountType) Connection::Release(void)
nsrefcnt count = --mRefCnt;
NS_LOG_RELEASE(this, count, "Connection");
if (1 == count) {
// If the refcount is 1, the single reference must be from
// gService->mConnections (in class |Service|). Which means we can
// perform our failsafe Close() and unregister...
// If the refcount went to 1, the single reference must be from
// gService->mConnections (in class |Service|). And the code calling
// Release is either:
// - The "user" code that had created the connection, releasing on any
// thread.
// - One of Service's getConnections() callers had acquired a strong
// reference to the Connection that out-lived the last "user" reference,
// and now that just got dropped. Note that this reference could be
// getting dropped on the main thread or Connection->threadOpenedOn
// (because of the NewRunnableMethod used by minimizeMemory).
//
// HOWEVER, there is an edge-case where our failsafe Close() may trigger
// a call to AsyncClose() which obtains a strong reference. This reference
// will be released via NS_ReleaseOnMainThreadSystemGroup() before Close()
// returns, which can potentially result in reentrancy into this method and
// this branch a second time. (It may also be deferred if we're not in
// that event target ourselves.) To avoid reentrancy madness, we explicitly
// bump our refcount up to 2 without going through AddRef().
++mRefCnt;
// Okay, now our refcount is 2, we trigger Close().
Unused << Close();
// Now our refcount should either be at 2 (because nothing happened, or the
// addref and release pair happened due to SpinningSynchronousClose) or
// 3 (because SpinningSynchronousClose happened but didn't release yet).
//
// We *really* want to avoid re-entrancy, and we have potentially two strong
// references remaining that will invoke Release() and potentially trigger
// a transition to 1 again. Since the second reference would be just a
// proxy release of an already-closed connection, it's not a big deal for us
// to unregister the connection now. We do need to take care to avoid a
// strong refcount transition to 1 from 2 because that would induce
// reentrancy. Note that we do not have any concerns about other threads
// being involved here; we MUST be the main thread if AsyncClose() is
// involved.
//
// Note: While Close() potentially spins the nested event loop, it is
// conceivable that Service::CollectReports or Service::minimizeMemory might
// be invoked. These call Service::getConnections() and will perform
// matching AddRef and Release calls but will definitely not retain any
// references. (Because connectionReady() will return false so both loops
// will immediately "continue" to bypass the connection in question.)
// Because our refcount is at least 2 at the lowest point, these do not pose
// a problem.
if (mRefCnt == 3) {
// pending proxy release, strong release to 2
// Either way, we should now perform our failsafe Close() and unregister.
// However, we only want to do this once, and the reality is that our
// refcount could go back up above 1 and down again at any time if we are
// off the main thread and getConnections() gets called on the main thread,
// so we use an atomic here to do this exactly once.
if (mDestroying.compareExchange(false, true)) {
// Close the connection, dispatching to the opening thread if we're not
// on that thread already and that thread is still accepting runnables.
// We do this because it's possible we're on the main thread because of
// getConnections(), and we REALLY don't want to transfer I/O to the main
// thread if we can avoid it.
if (threadOpenedOn->IsOnCurrentThread()) {
// This could cause SpinningSynchronousClose() to be invoked and AddRef
// triggered for AsyncCloseConnection's strong ref if the conn was ever
// use for async purposes. (Main-thread only, though.)
Unused << Close();
} else {
nsCOMPtr<nsIRunnable> event =
NewRunnableMethod("storage::Connection::Close",
this, &Connection::Close);
if (NS_FAILED(threadOpenedOn->Dispatch(event.forget(),
NS_DISPATCH_NORMAL))) {
// The target thread was dead and so we've just leaked our runnable.
// This should not happen because our non-main-thread consumers should
// be explicitly closing their connections, not relying on us to close
// them for them. (It's okay to let a statement go out of scope for
// automatic cleanup, but not a Connection.)
MOZ_ASSERT(false, "Leaked Connection::Close(), ownership fail.");
Unused << Close();
}
}
// This will drop its strong reference right here, right now.
mStorageService->unregisterConnection(this);
// now weak release to 1, the outstanding refcount will strong release to
// 0 and result in destruction later.
--mRefCnt;
} else if (mRefCnt == 2) {
// weak release to 1
--mRefCnt;
// strong release to 0, destruction will happen, we must NOT touch
// `this` after this point.
mStorageService->unregisterConnection(this);
} else {
MOZ_ASSERT(false, "Connection refcount invariant violated.");
}
} else if (0 == count) {
mRefCnt = 1; /* stabilize */

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

@ -9,6 +9,7 @@
#include "nsAutoPtr.h"
#include "nsCOMPtr.h"
#include "mozilla/Atomics.h"
#include "mozilla/Mutex.h"
#include "nsProxyRelease.h"
#include "nsThreadUtils.h"
@ -380,6 +381,16 @@ private:
*/
bool mTransactionInProgress;
/**
* Used to trigger cleanup logic only the first time our refcount hits 1. We
* may trigger a failsafe Close() that invokes SpinningSynchronousClose()
* which invokes AsyncClose() which may bump our refcount back up to 2 (and
* which will then fall back down to 1 again). It's also possible that the
* Service may bump our refcount back above 1 if getConnections() runs before
* we invoke unregisterConnection().
*/
mozilla::Atomic<bool> mDestroying;
/**
* Stores the mapping of a given function by name to its instance. Access is
* protected by sharedDBMutex.

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

@ -297,17 +297,12 @@ Service::unregisterConnection(Connection *aConnection)
MOZ_ASSERT(forgettingRef,
"Attempt to unregister unknown storage connection!");
// Ensure the connection is released on its opening thread. We explicitly use
// aAlwaysDispatch=false because at the time of writing this, LocalStorage's
// StorageDBThread uses a hand-rolled PRThread implementation that cannot
// handle us dispatching events at it during shutdown. However, it is
// arguably also desirable for callers to not be aware of our connection
// tracking mechanism. And by synchronously dropping the reference (when
// on the correct thread), this avoids surprises for the caller and weird
// shutdown edge cases.
nsCOMPtr<nsIThread> thread = forgettingRef->threadOpenedOn;
NS_ProxyRelease(
"storage::Service::mConnections", thread, forgettingRef.forget(), false);
// Do not proxy the release anywhere, just let this reference drop here. (We
// previously did proxy the release, but that was because we invoked Close()
// in the destructor and Close() likes to complain if it's not invoked on the
// opener thread, so it was essential that the last reference be dropped on
// the opener thread. We now enqueue Close() inside our caller, Release(), so
// it doesn't actually matter what thread our reference drops on.)
}
void

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

@ -20,10 +20,11 @@ XPCOMUtils.defineLazyGetter(this, "log", () => {
});
const PREF_ENABLED = "marionette.enabled";
const PREF_PORT = "marionette.port";
const PREF_PORT_FALLBACK = "marionette.defaultPrefs.port";
const PREF_LOG_LEVEL = "marionette.log.level";
const PREF_LOG_LEVEL_FALLBACK = "marionette.logging";
const PREF_LOG_LEVEL = "marionette.log.level";
const PREF_PORT_FALLBACK = "marionette.defaultPrefs.port";
const PREF_PORT = "marionette.port";
const PREF_RECOMMENDED = "marionette.prefs.recommended";
const DEFAULT_LOG_LEVEL = "info";
const NOTIFY_RUNNING = "remote-active";
@ -46,6 +47,241 @@ const ENV_ENABLED = "MOZ_MARIONETTE";
// pref being set to 4444.
const ENV_PRESERVE_PREFS = "MOZ_MARIONETTE_PREF_STATE_ACROSS_RESTARTS";
// Marionette sets preferences recommended for automation when it starts,
// unless marionette.prefs.recommended has been set to false.
// Where noted, some prefs should also be set in the profile passed to
// Marionette to prevent them from affecting startup, since some of these
// are checked before Marionette initialises.
const RECOMMENDED_PREFS = new Map([
// Disable automatic downloading of new releases.
//
// This should also be set in the profile prior to starting Firefox,
// as it is picked up at runtime.
["app.update.auto", false],
// Disable automatically upgrading Firefox.
//
// This should also be set in the profile prior to starting Firefox,
// as it is picked up at runtime.
["app.update.enabled", false],
// Increase the APZ content response timeout in tests to 1 minute.
// This is to accommodate the fact that test environments tends to be
// slower than production environments (with the b2g emulator being
// the slowest of them all), resulting in the production timeout value
// sometimes being exceeded and causing false-positive test failures.
//
// (bug 1176798, bug 1177018, bug 1210465)
["apz.content_response_timeout", 60000],
// Indicate that the download panel has been shown once so that
// whichever download test runs first doesn't show the popup
// inconsistently.
["browser.download.panel.shown", true],
// Do not show the EULA notification.
//
// This should also be set in the profile prior to starting Firefox,
// as it is picked up at runtime.
["browser.EULA.override", true],
// Turn off about:newtab and make use of about:blank instead for new
// opened tabs.
//
// This should also be set in the profile prior to starting Firefox,
// as it is picked up at runtime.
["browser.newtabpage.enabled", false],
// Assume the about:newtab page's intro panels have been shown to not
// depend on which test runs first and happens to open about:newtab
["browser.newtabpage.introShown", true],
// Never start the browser in offline mode
//
// This should also be set in the profile prior to starting Firefox,
// as it is picked up at runtime.
["browser.offline", false],
// Background thumbnails in particular cause grief, and disabling
// thumbnails in general cannot hurt
["browser.pagethumbnails.capturing_disabled", true],
// Disable safebrowsing components.
//
// These should also be set in the profile prior to starting Firefox,
// as it is picked up at runtime.
["browser.safebrowsing.blockedURIs.enabled", false],
["browser.safebrowsing.downloads.enabled", false],
["browser.safebrowsing.passwords.enabled", false],
["browser.safebrowsing.malware.enabled", false],
["browser.safebrowsing.phishing.enabled", false],
// Disable updates to search engines.
//
// Should be set in profile.
["browser.search.update", false],
// Do not restore the last open set of tabs if the browser has crashed
["browser.sessionstore.resume_from_crash", false],
// Don't check for the default web browser during startup.
//
// These should also be set in the profile prior to starting Firefox,
// as it is picked up at runtime.
["browser.shell.checkDefaultBrowser", false],
// Start with a blank page (about:blank)
["browser.startup.page", 0],
// Do not redirect user when a milstone upgrade of Firefox is detected
["browser.startup.homepage_override.mstone", "ignore"],
// Disable browser animations
["toolkit.cosmeticAnimations.enabled", false],
// Do not allow background tabs to be zombified, otherwise for tests
// that open additional tabs, the test harness tab itself might get
// unloaded
["browser.tabs.disableBackgroundZombification", false],
// Do not warn when closing all other open tabs
["browser.tabs.warnOnCloseOtherTabs", false],
// Do not warn when multiple tabs will be opened
["browser.tabs.warnOnOpen", false],
// Disable first run splash page on Windows 10
["browser.usedOnWindows10.introURL", ""],
// Disable the UI tour.
//
// Should be set in profile.
["browser.uitour.enabled", false],
// Turn off search suggestions in the location bar so as not to trigger
// network connections.
["browser.urlbar.suggest.searches", false],
// Turn off the location bar search suggestions opt-in. It interferes with
// tests that don't expect it to be there.
["browser.urlbar.userMadeSearchSuggestionsChoice", true],
// Do not show datareporting policy notifications which can
// interfere with tests
[
"datareporting.healthreport.documentServerURI",
"http://%(server)s/dummy/healthreport/",
],
["datareporting.healthreport.logging.consoleEnabled", false],
["datareporting.healthreport.service.enabled", false],
["datareporting.healthreport.service.firstRun", false],
["datareporting.healthreport.uploadEnabled", false],
["datareporting.policy.dataSubmissionEnabled", false],
["datareporting.policy.dataSubmissionPolicyAccepted", false],
["datareporting.policy.dataSubmissionPolicyBypassNotification", true],
// Disable popup-blocker
["dom.disable_open_during_load", false],
// Enabling the support for File object creation in the content process
["dom.file.createInChild", true],
// Disable the ProcessHangMonitor
["dom.ipc.reportProcessHangs", false],
// Disable slow script dialogues
["dom.max_chrome_script_run_time", 0],
["dom.max_script_run_time", 0],
// Only load extensions from the application and user profile
// AddonManager.SCOPE_PROFILE + AddonManager.SCOPE_APPLICATION
//
// Should be set in profile.
["extensions.autoDisableScopes", 0],
["extensions.enabledScopes", 5],
// Disable metadata caching for installed add-ons by default
["extensions.getAddons.cache.enabled", false],
// Disable installing any distribution extensions or add-ons.
// Should be set in profile.
["extensions.installDistroAddons", false],
// Make sure Shield doesn't hit the network.
["extensions.shield-recipe-client.api_url", ""],
["extensions.showMismatchUI", false],
// Turn off extension updates so they do not bother tests
["extensions.update.enabled", false],
["extensions.update.notifyUser", false],
// Make sure opening about:addons will not hit the network
[
"extensions.webservice.discoverURL",
"http://%(server)s/dummy/discoveryURL",
],
// Allow the application to have focus even it runs in the background
["focusmanager.testmode", true],
// Disable useragent updates
["general.useragent.updates.enabled", false],
// Always use network provider for geolocation tests so we bypass the
// macOS dialog raised by the corelocation provider
["geo.provider.testing", true],
// Do not scan Wifi
["geo.wifi.scan", false],
// No hang monitor
["hangmonitor.timeout", 0],
// Show chrome errors and warnings in the error console
["javascript.options.showInConsole", true],
// Do not prompt for temporary redirects
["network.http.prompt-temp-redirect", false],
// Disable speculative connections so they are not reported as leaking
// when they are hanging around
["network.http.speculative-parallel-limit", 0],
// Do not automatically switch between offline and online
["network.manage-offline-status", false],
// Make sure SNTP requests do not hit the network
["network.sntp.pools", "%(server)s"],
// Local documents have access to all other local documents,
// including directory listings
["security.fileuri.strict_origin_policy", false],
// Tests do not wait for the notification button security delay
["security.notification_enable_delay", 0],
// Ensure blocklist updates do not hit the network
["services.settings.server", "http://%(server)s/dummy/blocklist/"],
// Do not automatically fill sign-in forms with known usernames and
// passwords
["signon.autofillForms", false],
// Disable password capture, so that tests that include forms are not
// influenced by the presence of the persistent doorhanger notification
["signon.rememberSignons", false],
// Disable first-run welcome page
["startup.homepage_welcome_url", "about:blank"],
["startup.homepage_welcome_url.additional", ""],
// Prevent starting into safe mode after application crashes
["toolkit.startup.max_resumed_crashes", -1],
]);
const isRemote = Services.appinfo.processType ==
Services.appinfo.PROCESS_TYPE_CONTENT;
@ -155,6 +391,7 @@ class MarionetteMainProcess {
log.level = prefs.logLevel;
this.enabled = env.exists(ENV_ENABLED);
this.alteredPrefs = new Set();
Services.prefs.addObserver(PREF_ENABLED, this);
Services.ppmm.addMessageListener("Marionette:IsRunning", this);
@ -225,7 +462,7 @@ class MarionetteMainProcess {
if (this.gfxWindow === null || subject === this.gfxWindow) {
Services.obs.removeObserver(this, topic);
Services.obs.addObserver(this, "xpcom-shutdown");
Services.obs.addObserver(this, "xpcom-will-shutdown");
this.finalUIStartup = true;
this.init();
}
@ -254,15 +491,15 @@ class MarionetteMainProcess {
if (this.gfxWindow) {
Services.obs.addObserver(this, "domwindowclosed");
} else {
Services.obs.addObserver(this, "xpcom-shutdown");
Services.obs.addObserver(this, "xpcom-will-shutdown");
this.finalUIStartup = true;
this.init();
}
break;
case "xpcom-shutdown":
Services.obs.removeObserver(this, "xpcom-shutdown");
case "xpcom-will-shutdown":
Services.obs.removeObserver(this, "xpcom-will-shutdown");
this.uninit();
break;
}
@ -295,6 +532,16 @@ class MarionetteMainProcess {
}
await startupRecorder;
if (Preferences.get(PREF_RECOMMENDED)) {
for (let [k, v] of RECOMMENDED_PREFS) {
if (!Preferences.isSet(k)) {
log.debug(`Setting recommended pref ${k} to ${v}`);
Preferences.set(k, v);
this.alteredPrefs.add(k);
}
}
}
try {
ChromeUtils.import("chrome://marionette/content/server.js");
let listener = new server.TCPListener(prefs.port);
@ -302,9 +549,11 @@ class MarionetteMainProcess {
this.server = listener;
} catch (e) {
log.fatal("Remote protocol server failed to start", e);
this.uninit();
Services.startup.quit(Ci.nsIAppStartup.eForceQuit);
}
env.set(ENV_ENABLED, "1");
Services.obs.notifyObservers(this, NOTIFY_RUNNING, true);
log.info(`Listening on port ${this.server.port}`);
});
@ -313,6 +562,11 @@ class MarionetteMainProcess {
uninit() {
if (this.running) {
this.server.stop();
for (let k of this.alteredPrefs) {
log.debug(`Resetting recommended pref ${k}`);
Preferences.reset(k);
}
this.alteredPrefs.clear();
Services.obs.notifyObservers(this, NOTIFY_RUNNING);
}
}

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

@ -19,7 +19,7 @@ error module
.. js:autoclass:: InvalidSessionIDError
.. js:autoclass:: JavaScriptError
.. js:autoclass:: MoveTargetOutOfBoundsError
.. js:autoclass:: NoAlertOpenError
.. js:autoclass:: NoSuchAlertError
.. js:autoclass:: NoSuchElementError
.. js:autoclass:: NoSuchFrameError
.. js:autoclass:: NoSuchWindowError

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

@ -32,7 +32,7 @@ const {
InvalidArgumentError,
InvalidCookieDomainError,
InvalidSelectorError,
NoAlertOpenError,
NoSuchAlertError,
NoSuchFrameError,
NoSuchWindowError,
SessionNotCreatedError,
@ -3162,7 +3162,7 @@ GeckoDriver.prototype.sendKeysToDialog = async function(cmd) {
GeckoDriver.prototype._checkIfAlertIsPresent = function() {
if (!this.dialog || !this.dialog.ui) {
throw new NoAlertOpenError("No modal dialog is currently open");
throw new NoSuchAlertError("No modal dialog is currently open");
}
};

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

@ -18,7 +18,7 @@ const ERRORS = new Set([
"InvalidSessionIDError",
"JavaScriptError",
"MoveTargetOutOfBoundsError",
"NoAlertOpenError",
"NoSuchAlertError",
"NoSuchElementError",
"NoSuchFrameError",
"NoSuchWindowError",
@ -418,7 +418,7 @@ class MoveTargetOutOfBoundsError extends WebDriverError {
* An attempt was made to operate on a modal dialog when one was
* not open.
*/
class NoAlertOpenError extends WebDriverError {
class NoSuchAlertError extends WebDriverError {
constructor(message) {
super(message);
this.status = "no such alert";
@ -554,7 +554,7 @@ const STATUSES = new Map([
["invalid session id", InvalidSessionIDError],
["javascript error", JavaScriptError],
["move target out of bounds", MoveTargetOutOfBoundsError],
["no alert open", NoAlertOpenError],
["no such alert", NoSuchAlertError],
["no such element", NoSuchElementError],
["no such frame", NoSuchFrameError],
["no such window", NoSuchWindowError],

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

@ -6,12 +6,7 @@ from __future__ import absolute_import
import json
from marionette_driver.transport import (
Command,
Proto2Command,
Proto2Response,
Response,
)
from marionette_driver.transport import Command, Response
from marionette_harness import MarionetteTestCase
@ -116,46 +111,3 @@ class TestResponse(MessageTestCase):
self.assertEquals(msg[1], resp.id)
self.assertEquals(msg[2], resp.error)
self.assertEquals(msg[3], resp.result)
class TestProto2Command(MessageTestCase):
def create(self, name="name", params="params"):
return Proto2Command(name, params)
def test_initialise(self):
cmd = self.create()
self.assert_attr(cmd, "id")
self.assert_attr(cmd, "name")
self.assert_attr(cmd, "params")
self.assertEqual(None, cmd.id)
self.assertEqual("name", cmd.name)
self.assertEqual("params", cmd.params)
def test_from_data_unknown(self):
with self.assertRaises(ValueError):
cmd = Proto2Command.from_data({})
class TestProto2Response(MessageTestCase):
def create(self, error="error", result="result"):
return Proto2Response(error, result)
def test_initialise(self):
resp = self.create()
self.assert_attr(resp, "id")
self.assert_attr(resp, "error")
self.assert_attr(resp, "result")
self.assertEqual(None, resp.id)
self.assertEqual("error", resp.error)
self.assertEqual("result", resp.result)
def test_from_data_error(self):
data = {"error": "error"}
resp = Proto2Response.from_data(data)
self.assertEqual(data, resp.error)
self.assertEqual(None, resp.result)
def test_from_data_result(self):
resp = Proto2Response.from_data("result")
self.assertEqual(None, resp.error)
self.assertEqual("result", resp.result)

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

@ -1,4 +1,5 @@
[test_marionette.py]
[test_transport.py]
[test_cli_arguments.py]
skip-if = manage_instance == false || appname == 'fennec' # Bug 1298921
[test_geckoinstance.py]

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

@ -14,7 +14,6 @@ const ServerSocket = CC(
ChromeUtils.import("resource://gre/modules/Log.jsm");
ChromeUtils.import("resource://gre/modules/Preferences.jsm");
ChromeUtils.import("resource://gre/modules/Services.jsm");
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
ChromeUtils.import("chrome://marionette/content/assert.js");
const {GeckoDriver} = ChromeUtils.import("chrome://marionette/content/driver.js", {});
@ -30,9 +29,6 @@ const {
} = ChromeUtils.import("chrome://marionette/content/message.js", {});
const {DebuggerTransport} = ChromeUtils.import("chrome://marionette/content/transport.js", {});
XPCOMUtils.defineLazyServiceGetter(
this, "env", "@mozilla.org/process/environment;1", "nsIEnvironment");
const logger = Log.repository.getLogger("Marionette");
const {KeepWhenOffline, LoopbackOnly} = Ci.nsIServerSocket;
@ -44,246 +40,8 @@ this.server = {};
const PROTOCOL_VERSION = 3;
const ENV_ENABLED = "MOZ_MARIONETTE";
const PREF_CONTENT_LISTENER = "marionette.contentListener";
const PREF_PORT = "marionette.port";
const PREF_RECOMMENDED = "marionette.prefs.recommended";
// Marionette sets preferences recommended for automation when it starts,
// unless marionette.prefs.recommended has been set to false.
// Where noted, some prefs should also be set in the profile passed to
// Marionette to prevent them from affecting startup, since some of these
// are checked before Marionette initialises.
const RECOMMENDED_PREFS = new Map([
// Disable automatic downloading of new releases.
//
// This should also be set in the profile prior to starting Firefox,
// as it is picked up at runtime.
["app.update.auto", false],
// Disable automatically upgrading Firefox.
//
// This should also be set in the profile prior to starting Firefox,
// as it is picked up at runtime.
["app.update.enabled", false],
// Increase the APZ content response timeout in tests to 1 minute.
// This is to accommodate the fact that test environments tends to be
// slower than production environments (with the b2g emulator being
// the slowest of them all), resulting in the production timeout value
// sometimes being exceeded and causing false-positive test failures.
//
// (bug 1176798, bug 1177018, bug 1210465)
["apz.content_response_timeout", 60000],
// Indicate that the download panel has been shown once so that
// whichever download test runs first doesn't show the popup
// inconsistently.
["browser.download.panel.shown", true],
// Do not show the EULA notification.
//
// This should also be set in the profile prior to starting Firefox,
// as it is picked up at runtime.
["browser.EULA.override", true],
// Turn off about:newtab and make use of about:blank instead for new
// opened tabs.
//
// This should also be set in the profile prior to starting Firefox,
// as it is picked up at runtime.
["browser.newtabpage.enabled", false],
// Assume the about:newtab page's intro panels have been shown to not
// depend on which test runs first and happens to open about:newtab
["browser.newtabpage.introShown", true],
// Never start the browser in offline mode
//
// This should also be set in the profile prior to starting Firefox,
// as it is picked up at runtime.
["browser.offline", false],
// Background thumbnails in particular cause grief, and disabling
// thumbnails in general cannot hurt
["browser.pagethumbnails.capturing_disabled", true],
// Disable safebrowsing components.
//
// These should also be set in the profile prior to starting Firefox,
// as it is picked up at runtime.
["browser.safebrowsing.blockedURIs.enabled", false],
["browser.safebrowsing.downloads.enabled", false],
["browser.safebrowsing.passwords.enabled", false],
["browser.safebrowsing.malware.enabled", false],
["browser.safebrowsing.phishing.enabled", false],
// Disable updates to search engines.
//
// Should be set in profile.
["browser.search.update", false],
// Do not restore the last open set of tabs if the browser has crashed
["browser.sessionstore.resume_from_crash", false],
// Don't check for the default web browser during startup.
//
// These should also be set in the profile prior to starting Firefox,
// as it is picked up at runtime.
["browser.shell.checkDefaultBrowser", false],
// Start with a blank page (about:blank)
["browser.startup.page", 0],
// Do not redirect user when a milstone upgrade of Firefox is detected
["browser.startup.homepage_override.mstone", "ignore"],
// Disable browser animations
["toolkit.cosmeticAnimations.enabled", false],
// Do not allow background tabs to be zombified, otherwise for tests
// that open additional tabs, the test harness tab itself might get
// unloaded
["browser.tabs.disableBackgroundZombification", false],
// Do not warn when closing all other open tabs
["browser.tabs.warnOnCloseOtherTabs", false],
// Do not warn when multiple tabs will be opened
["browser.tabs.warnOnOpen", false],
// Disable first run splash page on Windows 10
["browser.usedOnWindows10.introURL", ""],
// Disable the UI tour.
//
// Should be set in profile.
["browser.uitour.enabled", false],
// Turn off search suggestions in the location bar so as not to trigger
// network connections.
["browser.urlbar.suggest.searches", false],
// Turn off the location bar search suggestions opt-in. It interferes with
// tests that don't expect it to be there.
["browser.urlbar.userMadeSearchSuggestionsChoice", true],
// Do not show datareporting policy notifications which can
// interfere with tests
[
"datareporting.healthreport.documentServerURI",
"http://%(server)s/dummy/healthreport/",
],
["datareporting.healthreport.logging.consoleEnabled", false],
["datareporting.healthreport.service.enabled", false],
["datareporting.healthreport.service.firstRun", false],
["datareporting.healthreport.uploadEnabled", false],
["datareporting.policy.dataSubmissionEnabled", false],
["datareporting.policy.dataSubmissionPolicyAccepted", false],
["datareporting.policy.dataSubmissionPolicyBypassNotification", true],
// Disable popup-blocker
["dom.disable_open_during_load", false],
// Enabling the support for File object creation in the content process
["dom.file.createInChild", true],
// Disable the ProcessHangMonitor
["dom.ipc.reportProcessHangs", false],
// Disable slow script dialogues
["dom.max_chrome_script_run_time", 0],
["dom.max_script_run_time", 0],
// Only load extensions from the application and user profile
// AddonManager.SCOPE_PROFILE + AddonManager.SCOPE_APPLICATION
//
// Should be set in profile.
["extensions.autoDisableScopes", 0],
["extensions.enabledScopes", 5],
// Disable metadata caching for installed add-ons by default
["extensions.getAddons.cache.enabled", false],
// Disable installing any distribution extensions or add-ons.
// Should be set in profile.
["extensions.installDistroAddons", false],
// Make sure Shield doesn't hit the network.
["extensions.shield-recipe-client.api_url", ""],
["extensions.showMismatchUI", false],
// Turn off extension updates so they do not bother tests
["extensions.update.enabled", false],
["extensions.update.notifyUser", false],
// Make sure opening about:addons will not hit the network
[
"extensions.webservice.discoverURL",
"http://%(server)s/dummy/discoveryURL",
],
// Allow the application to have focus even it runs in the background
["focusmanager.testmode", true],
// Disable useragent updates
["general.useragent.updates.enabled", false],
// Always use network provider for geolocation tests so we bypass the
// macOS dialog raised by the corelocation provider
["geo.provider.testing", true],
// Do not scan Wifi
["geo.wifi.scan", false],
// No hang monitor
["hangmonitor.timeout", 0],
// Show chrome errors and warnings in the error console
["javascript.options.showInConsole", true],
// Do not prompt for temporary redirects
["network.http.prompt-temp-redirect", false],
// Disable speculative connections so they are not reported as leaking
// when they are hanging around
["network.http.speculative-parallel-limit", 0],
// Do not automatically switch between offline and online
["network.manage-offline-status", false],
// Make sure SNTP requests do not hit the network
["network.sntp.pools", "%(server)s"],
// Local documents have access to all other local documents,
// including directory listings
["security.fileuri.strict_origin_policy", false],
// Tests do not wait for the notification button security delay
["security.notification_enable_delay", 0],
// Ensure blocklist updates do not hit the network
["services.settings.server", "http://%(server)s/dummy/blocklist/"],
// Do not automatically fill sign-in forms with known usernames and
// passwords
["signon.autofillForms", false],
// Disable password capture, so that tests that include forms are not
// influenced by the presence of the persistent doorhanger notification
["signon.rememberSignons", false],
// Disable first-run welcome page
["startup.homepage_welcome_url", "about:blank"],
["startup.homepage_welcome_url.additional", ""],
// Prevent starting into safe mode after application crashes
["toolkit.startup.max_resumed_crashes", -1],
]);
/**
* Bootstraps Marionette and handles incoming client connections.
@ -303,7 +61,6 @@ server.TCPListener = class {
this.conns = new Set();
this.nextConnID = 0;
this.alive = false;
this.alteredPrefs = new Set();
}
/**
@ -350,23 +107,9 @@ server.TCPListener = class {
return;
}
if (Preferences.get(PREF_RECOMMENDED)) {
// set recommended prefs if they are not already user-defined
for (let [k, v] of RECOMMENDED_PREFS) {
if (!Preferences.isSet(k)) {
logger.debug(`Setting recommended pref ${k} to ${v}`);
Preferences.set(k, v);
this.alteredPrefs.add(k);
}
}
}
// Start socket server and listening for connection attempts
this.acceptConnections = true;
Preferences.set(PREF_PORT, this.port);
env.set(ENV_ENABLED, "1");
this.alive = true;
}
@ -375,12 +118,6 @@ server.TCPListener = class {
return;
}
for (let k of this.alteredPrefs) {
logger.debug(`Resetting recommended pref ${k}`);
Preferences.reset(k);
}
this.alteredPrefs.clear();
// Shutdown server socket, and no longer listen for new connections
this.acceptConnections = false;
this.alive = false;

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

@ -15,7 +15,7 @@ const {
InvalidSessionIDError,
JavaScriptError,
MoveTargetOutOfBoundsError,
NoAlertOpenError,
NoSuchAlertError,
NoSuchElementError,
NoSuchFrameError,
NoSuchWindowError,
@ -333,9 +333,9 @@ add_test(function test_JavaScriptError() {
run_next_test();
});
add_test(function test_NoAlertOpenError() {
let err = new NoAlertOpenError("foo");
equal("NoAlertOpenError", err.name);
add_test(function test_NoSuchAlertError() {
let err = new NoSuchAlertError("foo");
equal("NoSuchAlertError", err.name);
equal("foo", err.message);
equal("no such alert", err.status);
ok(err instanceof WebDriverError);

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

@ -155,6 +155,8 @@ class PaymentDialog extends PaymentStateSubscriberMixin(HTMLElement) {
switch (state.completionState) {
case "initial":
case "processing":
case "success":
case "fail":
break;
default:
throw new Error("Invalid completionState");

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

@ -31,6 +31,8 @@
<button id="setShippingError">Shipping Error</button>
<button id="setStateDefault">Default</button>
<button id="setStateProcessing">Processing</button>
<button id="setStateSuccess">Success</button>
<button id="setStateFail">Fail</button>
</div>
</body>
</html>

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

@ -293,6 +293,18 @@ let buttonActions = {
completionState: "processing",
});
},
setStateSuccess() {
requestStore.setState({
completionState: "success",
});
},
setStateFail() {
requestStore.setState({
completionState: "fail",
});
},
};
window.addEventListener("click", function onButtonClick(evt) {

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

@ -82,7 +82,9 @@ payment-dialog > footer {
border: none;
}
payment-dialog[changes-prevented][completion-state="processing"] #pay {
payment-dialog[changes-prevented][completion-state="fail"] #pay,
payment-dialog[changes-prevented][completion-state="processing"] #pay,
payment-dialog[changes-prevented][completion-state="success"] #pay {
/* Show the pay button above #disabled-overlay */
position: relative;
z-index: 1;

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

@ -13,6 +13,8 @@
<!ENTITY cancelPaymentButton.label "Cancel">
<!ENTITY approvePaymentButton.label "Pay">
<!ENTITY processingPaymentButton.label "Processing">
<!ENTITY successPaymentButton.label "Done">
<!ENTITY failPaymentButton.label "Fail">
<!ENTITY orderDetailsLabel "Order Details">
<!ENTITY orderTotalLabel "Total">
]>
@ -87,7 +89,9 @@
<button id="cancel">&cancelPaymentButton.label;</button>
<button id="pay"
data-initial-label="&approvePaymentButton.label;"
data-processing-label="&processingPaymentButton.label;"></button>
data-processing-label="&processingPaymentButton.label;"
data-fail-label="&failPaymentButton.label;"
data-success-label="&successPaymentButton.label;"></button>
</footer>
</section>
<section id="order-details-overlay" hidden="hidden">

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

@ -36,6 +36,12 @@ Test the payment-dialog custom element
let el1;
let completionStates = [
["processing", "Processing"],
["success", "Done"],
["fail", "Fail"],
];
/* test that:
the view-all-items button exists
that clicking it changes the state on the store
@ -117,10 +123,12 @@ add_task(async function test_completionState() {
let payButton = document.getElementById("pay");
is(payButton.textContent, "Pay", "Check default label");
ok(!payButton.disabled, "Button is enabled");
await el1.requestStore.setState({completionState: "processing"});
await asyncElementRendered();
is(payButton.textContent, "Processing", "Check processing label");
ok(!payButton.disabled, "Button is still enabled");
for (let [completionState, label] of completionStates) {
await el1.requestStore.setState({completionState});
await asyncElementRendered();
is(payButton.textContent, label, "Check payButton label");
ok(!payButton.disabled, "Button is still enabled");
}
});
add_task(async function test_completionStateChangesPrevented() {
@ -132,21 +140,19 @@ add_task(async function test_completionStateChangesPrevented() {
is(payButton.textContent, "Pay", "Check default label");
ok(!payButton.disabled, "Button is enabled");
await el1.requestStore.setState({
changesPrevented: true,
completionState: "processing",
});
await asyncElementRendered();
is(payButton.textContent, "Processing", "Check processing label");
ok(payButton.disabled, "Button is disabled");
let {
x,
y,
width,
height,
} = payButton.getBoundingClientRect();
let visibleElement = document.elementFromPoint(x + width / 2, y + height / 2);
ok(payButton === visibleElement, "Pay button is on top of the overlay");
for (let [completionState, label] of completionStates) {
await el1.requestStore.setState({
changesPrevented: true,
completionState,
});
await asyncElementRendered();
is(payButton.textContent, label, "Check payButton label");
ok(payButton.disabled, "Button is disabled");
let rect = payButton.getBoundingClientRect();
let visibleElement =
document.elementFromPoint(rect.x + rect.width / 2, rect.y + rect.height / 2);
ok(payButton === visibleElement, "Pay button is on top of the overlay");
}
});
add_task(async function test_disconnect() {

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

@ -310,14 +310,17 @@ class SyncedBookmarksMirror {
* The current local time, in seconds.
* @param {Number} [options.remoteTimeSeconds]
* The current server time, in seconds.
* @param {String[]} [options.weakUpload]
* GUIDs of bookmarks to weakly upload.
* @return {Object.<String, BookmarkChangeRecord>}
* A changeset containing locally changed and reconciled records to
* upload to the server, and to store in the mirror once upload
* succeeds.
*/
async apply({ localTimeSeconds = Date.now() / 1000,
remoteTimeSeconds = 0 } = {}) {
let hasChanges = await this.hasChanges();
remoteTimeSeconds = 0,
weakUpload = [] } = {}) {
let hasChanges = weakUpload.length > 0 || (await this.hasChanges());
if (!hasChanges) {
MirrorLog.debug("No changes detected in both mirror and Places");
return {};
@ -425,7 +428,7 @@ class SyncedBookmarksMirror {
await this.noteObserverChanges(observersToNotify);
MirrorLog.debug("Staging locally changed items for upload");
await this.stageItemsToUpload();
await this.stageItemsToUpload(weakUpload);
MirrorLog.debug("Fetching records for local items to upload");
let changeRecords = await this.fetchLocalChangeRecords();
@ -1472,8 +1475,21 @@ class SyncedBookmarksMirror {
* items. The change counter in Places is the persistent record of items that
* we need to upload, so, if upload is interrupted or fails, we'll stage the
* items again on the next sync.
*
* @param {String[]} weakUpload
* GUIDs of bookmarks to weakly upload.
*/
async stageItemsToUpload() {
async stageItemsToUpload(weakUpload) {
// Stage explicit weak uploads such as repair responses.
for (let chunk of PlacesSyncUtils.chunkArray(weakUpload,
SQLITE_MAX_VARIABLE_NUMBER)) {
await this.db.execute(`
INSERT INTO itemsToWeaklyReupload(id)
SELECT b.id FROM moz_bookmarks b
WHERE b.guid IN (${new Array(chunk.length).fill("?").join(",")})`,
chunk);
}
// Stage remotely changed items with older local creation dates. These are
// tracked "weakly": if the upload is interrupted or fails, we won't
// reupload the record on the next sync.

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

@ -1,3 +1,6 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
add_task(async function test_missing_children() {
let buf = await openMirror("missing_childen");

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

@ -1,3 +1,6 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
add_task(async function test_duping() {
let buf = await openMirror("duping");

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

@ -1,3 +1,6 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
add_task(async function test_complex_orphaning() {
let buf = await openMirror("complex_orphaning");

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

@ -0,0 +1,39 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
add_task(async function test_explicit_weakupload() {
let buf = await openMirror("weakupload");
await PlacesUtils.bookmarks.insertTree({
guid: PlacesUtils.bookmarks.menuGuid,
children: [{
guid: "mozBmk______",
url: "https://mozilla.org",
title: "Mozilla",
tags: ["moz", "dot", "org"],
}],
});
await buf.store(shuffle([{
id: "menu",
type: "folder",
children: ["mozBmk______"],
}, {
id: "mozBmk______",
type: "bookmark",
title: "Mozilla",
bmkUri: "https://mozilla.org",
tags: ["moz", "dot", "org"],
}]), { needsMerge: false });
await PlacesTestUtils.markBookmarksAsSynced();
let changesToUpload = await buf.apply({
weakUpload: ["mozBmk______"]
});
ok("mozBmk______" in changesToUpload);
equal(changesToUpload.mozBmk______.counter, 0);
await buf.finalize();
await PlacesUtils.bookmarks.eraseEverything();
await PlacesSyncUtils.bookmarks.reset();
});

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

@ -1,3 +1,6 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
add_task(async function test_no_changes() {
let buf = await openMirror("nochanges");

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

@ -1,3 +1,6 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
add_task(async function test_livemarks() {
let { site, stopServer } = makeLivemarkServer();

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

@ -1,3 +1,6 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
add_task(async function test_value_structure_conflict() {
let buf = await openMirror("value_structure_conflict");

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

@ -1,3 +1,6 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
add_task(async function test_value_combo() {
let buf = await openMirror("value_combo");

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

@ -8,6 +8,7 @@ support-files =
[test_bookmark_corruption.js]
[test_bookmark_deduping.js]
[test_bookmark_deletion.js]
[test_bookmark_explicit_weakupload.js]
[test_bookmark_haschanges.js]
[test_bookmark_kinds.js]
[test_bookmark_structure_changes.js]

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

@ -647,7 +647,7 @@ var AddonRepository = {
if (typeof aEntry.ratings == "object") {
addon.averageRating = Math.min(5, aEntry.ratings.average);
addon.reviewCount = aEntry.ratings.count;
addon.reviewCount = aEntry.ratings.text_count;
}
addon.reviewURL = aEntry.ratings_url;

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

@ -39,7 +39,8 @@
"32": "http://localhost/repo/1/icon.png"
},
"ratings": {
"count": 1111,
"count": 1234,
"text_count": 1111,
"average": 1
},
"homepage": "http://localhost/repo/1/homepage.html",
@ -95,7 +96,8 @@
}
],
"ratings": {
"count": 1112,
"count": 2223,
"text_count": 1112,
"average": 2
},
"homepage": "http://localhost/repo/2/homepage.html",

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

@ -49,7 +49,8 @@
}
],
"ratings": {
"count": 1111,
"count": 1234,
"text_count": 1111,
"average": 4
},
"ratings_url": "http://localhost:%PORT%/review1.html",

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

@ -66,7 +66,6 @@ toolbarbutton[checked="true"]:not([disabled="true"]) {
padding-bottom: 2px;
padding-inline-start: 4px;
padding-inline-end: 2px;
color: ButtonText;
}
@media (-moz-windows-default-theme) {

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

@ -16,31 +16,26 @@
var path = require("path");
var helpers = require("../helpers");
var globals = require("../globals");
var modules = helpers.modulesGlobalData;
const placesOverlayFiles = [
"toolkit/content/globalOverlay.js",
"browser/base/content/utilityOverlay.js",
"browser/components/places/content/controller.js",
"browser/components/places/content/treeView.js"
"browser/base/content/utilityOverlay.js"
];
const extraPlacesDefinitions = [
// Straight definitions.
{name: "Cc", writable: false},
{name: "Ci", writable: false},
{name: "Cr", writable: false},
{name: "Cu", writable: false},
// Via Components.utils / XPCOMUtils.defineLazyModuleGetter (and map to
// Via Components.utils, defineModuleGetter, defineLazyModuleGetters or
// defineLazyScriptGetter (and map to
// single) variable.
{name: "XPCOMUtils", writable: false},
{name: "Task", writable: false},
{name: "PlacesUtils", writable: false},
{name: "PlacesUIUtils", writable: false},
{name: "PlacesTransactions", writable: false}
];
const placesOverlayModules = [
"PlacesUtils.jsm"
{name: "PlacesTransactions", writable: false},
{name: "ForgetAboutSite", writable: false},
{name: "PlacesTreeView", writable: false},
{name: "PlacesInsertionPoint", writable: false},
{name: "PlacesController", writable: false},
{name: "PlacesControllerDragHelper", writable: false}
];
function getScriptGlobals() {
@ -54,14 +49,6 @@ function getScriptGlobals() {
}
}
for (let file of placesOverlayModules) {
if (file in modules) {
for (let globalVar of modules[file]) {
fileGlobals.push({name: globalVar, writable: false});
}
}
}
return fileGlobals.concat(extraPlacesDefinitions);
}