зеркало из https://github.com/mozilla/pjs.git
Merge mozilla-inbound and mozilla-central
This commit is contained in:
Коммит
6d250b33b2
|
@ -5462,7 +5462,7 @@ function hrefAndLinkNodeForClickEvent(event)
|
|||
// If there is no linkNode, try simple XLink.
|
||||
let href, baseURI;
|
||||
node = event.target;
|
||||
while (node) {
|
||||
while (node && !href) {
|
||||
if (node.nodeType == Node.ELEMENT_NODE) {
|
||||
href = node.getAttributeNS("http://www.w3.org/1999/xlink", "href");
|
||||
if (href)
|
||||
|
|
|
@ -53,7 +53,7 @@ let gTests = [
|
|||
setup: function() {},
|
||||
clean: function() {},
|
||||
event: {},
|
||||
target: "commonlink",
|
||||
targets: [ "commonlink", "mathxlink", "svgxlink", "maplink" ],
|
||||
expectedInvokedMethods: [],
|
||||
preventDefault: false,
|
||||
},
|
||||
|
@ -64,7 +64,7 @@ let gTests = [
|
|||
clean: function() {},
|
||||
event: { ctrlKey: true,
|
||||
metaKey: true },
|
||||
target: "commonlink",
|
||||
targets: [ "commonlink", "mathxlink", "svgxlink", "maplink" ],
|
||||
expectedInvokedMethods: [ "urlSecurityCheck", "openLinkIn" ],
|
||||
preventDefault: true,
|
||||
},
|
||||
|
@ -77,17 +77,28 @@ let gTests = [
|
|||
clean: function() {},
|
||||
event: { shiftKey: true,
|
||||
altKey: true },
|
||||
target: "commonlink",
|
||||
targets: [ "commonlink", "maplink" ],
|
||||
expectedInvokedMethods: [ "gatherTextUnder", "saveURL" ],
|
||||
preventDefault: true,
|
||||
},
|
||||
|
||||
{
|
||||
desc: "Shift+Alt left click on XLinks",
|
||||
setup: function() {},
|
||||
clean: function() {},
|
||||
event: { shiftKey: true,
|
||||
altKey: true },
|
||||
targets: [ "mathxlink", "svgxlink"],
|
||||
expectedInvokedMethods: [ "saveURL" ],
|
||||
preventDefault: true,
|
||||
},
|
||||
|
||||
{
|
||||
desc: "Shift click",
|
||||
setup: function() {},
|
||||
clean: function() {},
|
||||
event: { shiftKey: true },
|
||||
target: "commonlink",
|
||||
targets: [ "commonlink", "mathxlink", "svgxlink", "maplink" ],
|
||||
expectedInvokedMethods: [ "urlSecurityCheck", "openLinkIn" ],
|
||||
preventDefault: true,
|
||||
},
|
||||
|
@ -97,17 +108,27 @@ let gTests = [
|
|||
setup: function() {},
|
||||
clean: function() {},
|
||||
event: { altKey: true },
|
||||
target: "commonlink",
|
||||
targets: [ "commonlink", "maplink" ],
|
||||
expectedInvokedMethods: [ "gatherTextUnder", "saveURL" ],
|
||||
preventDefault: true,
|
||||
},
|
||||
|
||||
{
|
||||
desc: "Alt click on XLinks",
|
||||
setup: function() {},
|
||||
clean: function() {},
|
||||
event: { altKey: true },
|
||||
targets: [ "mathxlink", "svgxlink" ],
|
||||
expectedInvokedMethods: [ "saveURL" ],
|
||||
preventDefault: true,
|
||||
},
|
||||
|
||||
{
|
||||
desc: "Panel click",
|
||||
setup: function() {},
|
||||
clean: function() {},
|
||||
event: {},
|
||||
target: "panellink",
|
||||
targets: [ "panellink" ],
|
||||
expectedInvokedMethods: [ "urlSecurityCheck", "getShortcutOrURI", "loadURI" ],
|
||||
preventDefault: true,
|
||||
},
|
||||
|
@ -117,7 +138,7 @@ let gTests = [
|
|||
setup: function() {},
|
||||
clean: function() {},
|
||||
event: { button: 1 },
|
||||
target: "commonlink",
|
||||
targets: [ "commonlink", "mathxlink", "svgxlink", "maplink" ],
|
||||
expectedInvokedMethods: [ "urlSecurityCheck", "openLinkIn" ],
|
||||
preventDefault: true,
|
||||
},
|
||||
|
@ -133,7 +154,7 @@ let gTests = [
|
|||
} catch(ex) {}
|
||||
},
|
||||
event: { button: 1 },
|
||||
target: "commonlink",
|
||||
targets: [ "commonlink", "mathxlink", "svgxlink", "maplink" ],
|
||||
expectedInvokedMethods: [ "urlSecurityCheck", "openLinkIn" ],
|
||||
preventDefault: true,
|
||||
},
|
||||
|
@ -153,7 +174,7 @@ let gTests = [
|
|||
} catch(ex) {}
|
||||
},
|
||||
event: { button: 1 },
|
||||
target: "emptylink",
|
||||
targets: [ "emptylink" ],
|
||||
expectedInvokedMethods: [ "middleMousePaste" ],
|
||||
preventDefault: true,
|
||||
},
|
||||
|
@ -206,7 +227,7 @@ function test() {
|
|||
// Click handler used to steal click events.
|
||||
let gClickHandler = {
|
||||
handleEvent: function (event) {
|
||||
let linkId = event.target.id;
|
||||
let linkId = event.target.id || event.target.localName;
|
||||
is(event.type, "click",
|
||||
gCurrentTest.desc + ":Handler received a click event on " + linkId);
|
||||
|
||||
|
@ -223,7 +244,7 @@ let gClickHandler = {
|
|||
});
|
||||
|
||||
if (gInvokedMethods.length != gCurrentTest.expectedInvokedMethods.length) {
|
||||
is(false, "More than the expected methods have been called");
|
||||
ok(false, "Wrong number of invoked methods");
|
||||
gInvokedMethods.forEach(function (method) info(method + " was invoked"));
|
||||
}
|
||||
|
||||
|
@ -257,35 +278,45 @@ function setupTestBrowserWindow() {
|
|||
let doc = gTestWin.content.document;
|
||||
let mainDiv = doc.createElement("div");
|
||||
mainDiv.innerHTML =
|
||||
'<a id="commonlink" href="http://mochi.test/moz/">Common link</a>' +
|
||||
'<a id="panellink" href="http://mochi.test/moz/">Panel link</a>' +
|
||||
'<a id="emptylink">Empty link</a>';
|
||||
'<p><a id="commonlink" href="http://mochi.test/moz/">Common link</a></p>' +
|
||||
'<p><a id="panellink" href="http://mochi.test/moz/">Panel link</a></p>' +
|
||||
'<p><a id="emptylink">Empty link</a></p>' +
|
||||
'<p><math id="mathxlink" xmlns="http://www.w3.org/1998/Math/MathML" xlink:type="simple" xlink:href="http://mochi.test/moz/"><mtext>MathML XLink</mtext></math></p>' +
|
||||
'<p><svg id="svgxlink" xmlns="http://www.w3.org/2000/svg" width="100px" height="50px" version="1.1"><a xlink:type="simple" xlink:href="http://mochi.test/moz/"><text transform="translate(10, 25)">SVG XLink</text></a></svg></p>' +
|
||||
'<p><map name="map" id="map"><area href="http://mochi.test/moz/" shape="rect" coords="0,0,128,128" /></map><img id="maplink" usemap="#map" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAIAAABMXPacAAAABGdBTUEAALGPC%2FxhBQAAAOtJREFUeF7t0IEAAAAAgKD9qRcphAoDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGBgwIAAAT0N51AAAAAASUVORK5CYII%3D"/></p>'
|
||||
doc.body.appendChild(mainDiv);
|
||||
}
|
||||
|
||||
function runNextTest() {
|
||||
if (gCurrentTest) {
|
||||
if (!gCurrentTest) {
|
||||
gCurrentTest = gTests.shift();
|
||||
gCurrentTest.setup();
|
||||
}
|
||||
|
||||
if (gCurrentTest.targets.length == 0) {
|
||||
info(gCurrentTest.desc + ": cleaning up...")
|
||||
gCurrentTest.clean();
|
||||
gInvokedMethods.length = 0;
|
||||
|
||||
if (gTests.length > 0) {
|
||||
gCurrentTest = gTests.shift();
|
||||
gCurrentTest.setup();
|
||||
}
|
||||
else {
|
||||
finishTest();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (gTests.length > 0) {
|
||||
gCurrentTest = gTests.shift();
|
||||
// Move to next target.
|
||||
gInvokedMethods.length = 0;
|
||||
let target = gCurrentTest.targets.shift();
|
||||
|
||||
info(gCurrentTest.desc + ": starting...");
|
||||
// Prepare for test.
|
||||
gCurrentTest.setup();
|
||||
info(gCurrentTest.desc + ": testing " + target);
|
||||
|
||||
// Fire click event.
|
||||
let target = gTestWin.content.document.getElementById(gCurrentTest.target);
|
||||
ok(target, gCurrentTest.desc + ": target is valid (" + target.id + ")");
|
||||
EventUtils.synthesizeMouse(target, 2, 2, gCurrentTest.event, gTestWin.content);
|
||||
}
|
||||
else {
|
||||
// No more tests to run.
|
||||
finishTest()
|
||||
}
|
||||
// Fire click event.
|
||||
let targetElt = gTestWin.content.document.getElementById(target);
|
||||
ok(targetElt, gCurrentTest.desc + ": target is valid (" + targetElt.id + ")");
|
||||
EventUtils.synthesizeMouseAtCenter(targetElt, gCurrentTest.event, gTestWin.content);
|
||||
}
|
||||
|
||||
function finishTest() {
|
||||
|
|
|
@ -431,6 +431,19 @@ PlacesViewBase.prototype = {
|
|||
}
|
||||
},
|
||||
|
||||
toggleCutNode: function PVB_toggleCutNode(aNode, aValue) {
|
||||
let elt = aNode._DOMElement;
|
||||
if (elt) {
|
||||
// We may get the popup for menus, but we need the menu itself.
|
||||
if (elt.localName == "menupopup")
|
||||
elt = elt.parentNode;
|
||||
if (aValue)
|
||||
elt.setAttribute("cutting", "true");
|
||||
else
|
||||
elt.removeAttribute("cutting");
|
||||
}
|
||||
},
|
||||
|
||||
nodeURIChanged: function PVB_nodeURIChanged(aPlacesNode, aURIString) {
|
||||
let elt = aPlacesNode._DOMElement;
|
||||
if (!elt)
|
||||
|
@ -658,6 +671,7 @@ PlacesViewBase.prototype = {
|
|||
}
|
||||
|
||||
if (this._controller) {
|
||||
this._controller.terminate();
|
||||
this._viewElt.controllers.removeController(this._controller);
|
||||
this._controller = null;
|
||||
}
|
||||
|
|
|
@ -117,6 +117,9 @@ function PlacesController(aView) {
|
|||
XPCOMUtils.defineLazyServiceGetter(this, "clipboard",
|
||||
"@mozilla.org/widget/clipboard;1",
|
||||
"nsIClipboard");
|
||||
XPCOMUtils.defineLazyGetter(this, "profileName", function () {
|
||||
return Services.dirsvc.get("ProfD", Ci.nsIFile).leafName;
|
||||
});
|
||||
}
|
||||
|
||||
PlacesController.prototype = {
|
||||
|
@ -125,6 +128,20 @@ PlacesController.prototype = {
|
|||
*/
|
||||
_view: null,
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([
|
||||
Ci.nsIClipboardOwner
|
||||
]),
|
||||
|
||||
// nsIClipboardOwner
|
||||
LosingOwnership: function PC_LosingOwnership (aXferable) {
|
||||
this.cutNodes = [];
|
||||
},
|
||||
|
||||
terminate: function PC_terminate() {
|
||||
if (this._cutNodes.length > 0)
|
||||
this._clearClipboard();
|
||||
},
|
||||
|
||||
supportsCommand: function PC_supportsCommand(aCommand) {
|
||||
//LOG("supportsCommand: " + command);
|
||||
// Non-Places specific commands that we also support
|
||||
|
@ -1086,74 +1103,127 @@ PlacesController.prototype = {
|
|||
}
|
||||
},
|
||||
|
||||
get clipboardAction () {
|
||||
let action = {};
|
||||
let actionOwner;
|
||||
try {
|
||||
let xferable = Cc["@mozilla.org/widget/transferable;1"].
|
||||
createInstance(Ci.nsITransferable);
|
||||
xferable.addDataFlavor(PlacesUtils.TYPE_X_MOZ_PLACE_ACTION)
|
||||
this.clipboard.getData(xferable, Ci.nsIClipboard.kGlobalClipboard);
|
||||
xferable.getTransferData(PlacesUtils.TYPE_X_MOZ_PLACE_ACTION, action, {});
|
||||
[action, actionOwner] =
|
||||
action.value.QueryInterface(Ci.nsISupportsString).data.split(",");
|
||||
} catch(ex) {
|
||||
// Paste from external sources don't have any associated action, just
|
||||
// fallback to a copy action.
|
||||
return "copy";
|
||||
}
|
||||
// For cuts also check who inited the action, since cuts across different
|
||||
// instances should instead be handled as copies (The sources are not
|
||||
// available for this instance).
|
||||
if (action == "cut" && actionOwner != this.profileName)
|
||||
action = "copy";
|
||||
|
||||
return action;
|
||||
},
|
||||
|
||||
_clearClipboard: function PC__clearClipboard() {
|
||||
this.clipboard.emptyClipboard(Ci.nsIClipboard.kGlobalClipboard);
|
||||
// Unfortunately just invoking emptyClipboard is not enough, since it
|
||||
// does not act on the native clipboard.
|
||||
let xferable = Cc["@mozilla.org/widget/transferable;1"].
|
||||
createInstance(Ci.nsITransferable);
|
||||
// GTK doesn't like empty transferables, so just add an unknown type.
|
||||
xferable.addDataFlavor("text/x-moz-place-empty");
|
||||
this.clipboard.setData(xferable, null, Ci.nsIClipboard.kGlobalClipboard);
|
||||
},
|
||||
|
||||
_populateClipboard: function PC__populateClipboard(aNodes, aAction) {
|
||||
// This order is _important_! It controls how this and other applications
|
||||
// select data to be inserted based on type.
|
||||
let contents = [
|
||||
{ type: PlacesUtils.TYPE_X_MOZ_PLACE, entries: [] },
|
||||
{ type: PlacesUtils.TYPE_X_MOZ_URL, entries: [] },
|
||||
{ type: PlacesUtils.TYPE_HTML, entries: [] },
|
||||
{ type: PlacesUtils.TYPE_UNICODE, entries: [] },
|
||||
];
|
||||
|
||||
// Avoid handling descendants of a copied node, the transactions take care
|
||||
// of them automatically.
|
||||
let copiedFolders = [];
|
||||
aNodes.forEach(function (node) {
|
||||
if (this._shouldSkipNode(node, copiedFolders))
|
||||
return;
|
||||
if (PlacesUtils.nodeIsFolder(node))
|
||||
copiedFolders.push(node);
|
||||
|
||||
let overrideURI = PlacesUtils.nodeIsLivemarkContainer(node) ?
|
||||
PlacesUtils.livemarks.getFeedURI(node.itemId).spec : null;
|
||||
let resolveShortcuts = !PlacesControllerDragHelper.canMoveNode(node);
|
||||
|
||||
contents.forEach(function (content) {
|
||||
content.entries.push(
|
||||
PlacesUtils.wrapNode(node, content.type, overrideURI, resolveShortcuts)
|
||||
);
|
||||
});
|
||||
}, this);
|
||||
|
||||
function addData(type, data) {
|
||||
xferable.addDataFlavor(type);
|
||||
xferable.setTransferData(type, PlacesUtils.toISupportsString(data),
|
||||
data.length * 2);
|
||||
}
|
||||
|
||||
let xferable = Cc["@mozilla.org/widget/transferable;1"].
|
||||
createInstance(Ci.nsITransferable);
|
||||
let hasData = false;
|
||||
// This order matters here! It controls how this and other applications
|
||||
// select data to be inserted based on type.
|
||||
contents.forEach(function (content) {
|
||||
if (content.entries.length > 0) {
|
||||
hasData = true;
|
||||
let glue =
|
||||
content.type == PlacesUtils.TYPE_X_MOZ_PLACE ? "," : PlacesUtils.endl;
|
||||
addData(content.type, content.entries.join(glue));
|
||||
}
|
||||
});
|
||||
|
||||
// Track the exected action in the xferable. This must be the last flavor
|
||||
// since it's the least preferred one.
|
||||
// Enqueue a unique instance identifier to distinguish operations across
|
||||
// concurrent instances of the application.
|
||||
addData(PlacesUtils.TYPE_X_MOZ_PLACE_ACTION, aAction + "," + this.profileName);
|
||||
|
||||
if (hasData)
|
||||
this.clipboard.setData(xferable, this, Ci.nsIClipboard.kGlobalClipboard);
|
||||
},
|
||||
|
||||
_cutNodes: [],
|
||||
set cutNodes(aNodes) {
|
||||
let self = this;
|
||||
function updateCutNodes(aValue) {
|
||||
self._cutNodes.forEach(function (aNode) {
|
||||
self._view.toggleCutNode(aNode, aValue);
|
||||
});
|
||||
}
|
||||
|
||||
updateCutNodes(false);
|
||||
this._cutNodes = aNodes;
|
||||
updateCutNodes(true);
|
||||
return aNodes;
|
||||
},
|
||||
|
||||
/**
|
||||
* Copy Bookmarks and Folders to the clipboard
|
||||
*/
|
||||
copy: function PC_copy() {
|
||||
let result = this._view.result;
|
||||
|
||||
let didSuppressNotifications = result.suppressNotifications;
|
||||
if (!didSuppressNotifications)
|
||||
result.suppressNotifications = true;
|
||||
|
||||
try {
|
||||
let nodes = this._view.selectedNodes;
|
||||
|
||||
let xferable = Cc["@mozilla.org/widget/transferable;1"].
|
||||
createInstance(Ci.nsITransferable);
|
||||
let foundFolder = false, foundLink = false;
|
||||
let copiedFolders = [];
|
||||
let placeString, mozURLString, htmlString, unicodeString;
|
||||
placeString = mozURLString = htmlString = unicodeString = "";
|
||||
|
||||
for (let i = 0; i < nodes.length; ++i) {
|
||||
let node = nodes[i];
|
||||
if (this._shouldSkipNode(node, copiedFolders))
|
||||
continue;
|
||||
if (PlacesUtils.nodeIsFolder(node))
|
||||
copiedFolders.push(node);
|
||||
|
||||
function generateChunk(type, overrideURI) {
|
||||
let suffix = i < (nodes.length - 1) ? PlacesUtils.endl : "";
|
||||
let uri = overrideURI;
|
||||
|
||||
if (PlacesUtils.nodeIsLivemarkContainer(node))
|
||||
uri = PlacesUtils.livemarks.getFeedURI(node.itemId).spec
|
||||
|
||||
mozURLString += (PlacesUtils.wrapNode(node, PlacesUtils.TYPE_X_MOZ_URL,
|
||||
uri) + suffix);
|
||||
unicodeString += (PlacesUtils.wrapNode(node, PlacesUtils.TYPE_UNICODE,
|
||||
uri) + suffix);
|
||||
htmlString += (PlacesUtils.wrapNode(node, PlacesUtils.TYPE_HTML,
|
||||
uri) + suffix);
|
||||
|
||||
let placeSuffix = i < (nodes.length - 1) ? "," : "";
|
||||
let resolveShortcuts = !PlacesControllerDragHelper.canMoveNode(node);
|
||||
return PlacesUtils.wrapNode(node, type, overrideURI, resolveShortcuts) + placeSuffix;
|
||||
}
|
||||
|
||||
// all items wrapped as TYPE_X_MOZ_PLACE
|
||||
placeString += generateChunk(PlacesUtils.TYPE_X_MOZ_PLACE);
|
||||
}
|
||||
|
||||
function addData(type, data) {
|
||||
xferable.addDataFlavor(type);
|
||||
xferable.setTransferData(type, PlacesUIUtils._wrapString(data), data.length * 2);
|
||||
}
|
||||
// This order is _important_! It controls how this and other applications
|
||||
// select data to be inserted based on type.
|
||||
if (placeString)
|
||||
addData(PlacesUtils.TYPE_X_MOZ_PLACE, placeString);
|
||||
if (mozURLString)
|
||||
addData(PlacesUtils.TYPE_X_MOZ_URL, mozURLString);
|
||||
if (unicodeString)
|
||||
addData(PlacesUtils.TYPE_UNICODE, unicodeString);
|
||||
if (htmlString)
|
||||
addData(PlacesUtils.TYPE_HTML, htmlString);
|
||||
|
||||
if (placeString || unicodeString || htmlString || mozURLString) {
|
||||
this.clipboard.setData(xferable, null, Ci.nsIClipboard.kGlobalClipboard);
|
||||
}
|
||||
this._populateClipboard(this._view.selectedNodes, "copy");
|
||||
}
|
||||
finally {
|
||||
if (!didSuppressNotifications)
|
||||
|
@ -1165,101 +1235,94 @@ PlacesController.prototype = {
|
|||
* Cut Bookmarks and Folders to the clipboard
|
||||
*/
|
||||
cut: function PC_cut() {
|
||||
this.copy();
|
||||
this.remove("Cut Selection");
|
||||
let result = this._view.result;
|
||||
let didSuppressNotifications = result.suppressNotifications;
|
||||
if (!didSuppressNotifications)
|
||||
result.suppressNotifications = true;
|
||||
try {
|
||||
this._populateClipboard(this._view.selectedNodes, "cut");
|
||||
this.cutNodes = this._view.selectedNodes;
|
||||
}
|
||||
finally {
|
||||
if (!didSuppressNotifications)
|
||||
result.suppressNotifications = false;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Paste Bookmarks and Folders from the clipboard
|
||||
*/
|
||||
paste: function PC_paste() {
|
||||
// Strategy:
|
||||
//
|
||||
// There can be data of various types (folder, separator, link) on the
|
||||
// clipboard. We need to get all of that data and build edit transactions
|
||||
// for them. This means asking the clipboard once for each type and
|
||||
// aggregating the results.
|
||||
|
||||
/**
|
||||
* Constructs a transferable that can receive data of specific types.
|
||||
* @param types
|
||||
* The types of data the transferable can hold, in order of
|
||||
* preference.
|
||||
* @returns The transferable.
|
||||
*/
|
||||
function makeXferable(types) {
|
||||
var xferable = Cc["@mozilla.org/widget/transferable;1"].
|
||||
createInstance(Ci.nsITransferable);
|
||||
for (var i = 0; i < types.length; ++i)
|
||||
xferable.addDataFlavor(types[i]);
|
||||
return xferable;
|
||||
}
|
||||
|
||||
var clipboard = this.clipboard;
|
||||
|
||||
var ip = this._view.insertionPoint;
|
||||
// No reason to proceed if there isn't a valid insertion point.
|
||||
let ip = this._view.insertionPoint;
|
||||
if (!ip)
|
||||
throw Cr.NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
/**
|
||||
* Gets a list of transactions to perform the paste of specific types.
|
||||
* @param types
|
||||
* The types of data to form paste transactions for
|
||||
* @returns An array of transactions that perform the paste.
|
||||
*/
|
||||
function getTransactions(types) {
|
||||
var xferable = makeXferable(types);
|
||||
clipboard.getData(xferable, Ci.nsIClipboard.kGlobalClipboard);
|
||||
let action = this.clipboardAction;
|
||||
|
||||
var data = { }, type = { };
|
||||
try {
|
||||
xferable.getAnyTransferData(type, data, { });
|
||||
data = data.value.QueryInterface(Ci.nsISupportsString).data;
|
||||
var items = PlacesUtils.unwrapNodes(data, type.value);
|
||||
var transactions = [];
|
||||
var index = ip.index;
|
||||
for (var i = 0; i < items.length; ++i) {
|
||||
var txn;
|
||||
if (ip.isTag) {
|
||||
var uri = PlacesUtils._uri(items[i].uri);
|
||||
txn = PlacesUIUtils.ptm.tagURI(uri, [ip.itemId]);
|
||||
}
|
||||
else {
|
||||
// adjusted to make sure that items are given the correct index
|
||||
// transactions insert differently if index == -1
|
||||
// transaction will enqueue the item.
|
||||
if (ip.index > -1)
|
||||
index = ip.index + i;
|
||||
txn = PlacesUIUtils.makeTransaction(items[i], type.value,
|
||||
ip.itemId, index, true);
|
||||
}
|
||||
transactions.push(txn);
|
||||
}
|
||||
return transactions;
|
||||
}
|
||||
catch (e) {
|
||||
// getAnyTransferData will throw if there is no data of the specified
|
||||
// type on the clipboard.
|
||||
// unwrapNodes will throw if the data that is present is malformed in
|
||||
// some way.
|
||||
// In either case, don't fail horribly, just return no data.
|
||||
}
|
||||
return [];
|
||||
let xferable = Cc["@mozilla.org/widget/transferable;1"].
|
||||
createInstance(Ci.nsITransferable);
|
||||
// This order matters here! It controls the preferred flavors for this
|
||||
// paste operation.
|
||||
[ PlacesUtils.TYPE_X_MOZ_PLACE,
|
||||
PlacesUtils.TYPE_X_MOZ_URL,
|
||||
PlacesUtils.TYPE_UNICODE,
|
||||
].forEach(function (type) xferable.addDataFlavor(type));
|
||||
|
||||
this.clipboard.getData(xferable, Ci.nsIClipboard.kGlobalClipboard);
|
||||
|
||||
// Now get the clipboard contents, in the best available flavor.
|
||||
let data = {}, type = {}, items = [];
|
||||
try {
|
||||
xferable.getAnyTransferData(type, data, {});
|
||||
data = data.value.QueryInterface(Ci.nsISupportsString).data;
|
||||
type = type.value;
|
||||
items = PlacesUtils.unwrapNodes(data, type);
|
||||
} catch(ex) {
|
||||
// No supported data exists or nodes unwrap failed, just bail out.
|
||||
return;
|
||||
}
|
||||
|
||||
// Get transactions to paste any folders, separators or links that might
|
||||
// be on the clipboard, aggregate them and execute them.
|
||||
var transactions = getTransactions([PlacesUtils.TYPE_X_MOZ_PLACE,
|
||||
PlacesUtils.TYPE_X_MOZ_URL,
|
||||
PlacesUtils.TYPE_UNICODE]);
|
||||
var txn = PlacesUIUtils.ptm.aggregateTransactions("Paste", transactions);
|
||||
PlacesUIUtils.ptm.doTransaction(txn);
|
||||
let transactions = [];
|
||||
let insertionIndex = ip.index;
|
||||
for (let i = 0; i < items.length; ++i) {
|
||||
if (ip.isTag) {
|
||||
// Pasting into a tag container means tagging the item, regardless of
|
||||
// the requested action.
|
||||
transactions.push(
|
||||
new PlacesTagURITransaction(PlacesUtils._uri(items[i].uri),
|
||||
[ip.itemId])
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
// select the pasted items, they should be consecutive
|
||||
var insertedNodeIds = [];
|
||||
for (var i = 0; i < transactions.length; ++i)
|
||||
insertedNodeIds.push(PlacesUtils.bookmarks
|
||||
.getIdForItemAt(ip.itemId, ip.index + i));
|
||||
// Adjust index to make sure items are pasted in the correct position.
|
||||
// If index is DEFAULT_INDEX, items are just appended.
|
||||
if (ip.index != PlacesUtils.bookmarks.DEFAULT_INDEX)
|
||||
insertionIndex = ip.index + i;
|
||||
|
||||
transactions.push(
|
||||
PlacesUIUtils.makeTransaction(items[i], type, ip.itemId,
|
||||
insertionIndex, action == "copy")
|
||||
);
|
||||
}
|
||||
|
||||
PlacesUtils.transactionManager.doTransaction(
|
||||
new PlacesAggregatedTransaction("Paste", transactions)
|
||||
);
|
||||
|
||||
// Cut/past operations are not repeatable, so clear the clipboard.
|
||||
if (action == "cut") {
|
||||
this._clearClipboard();
|
||||
}
|
||||
|
||||
// Select the pasted items, they should be consecutive.
|
||||
let insertedNodeIds = [];
|
||||
for (let i = 0; i < transactions.length; ++i) {
|
||||
insertedNodeIds.push(
|
||||
PlacesUtils.bookmarks.getIdForItemAt(ip.itemId, ip.index + i)
|
||||
);
|
||||
}
|
||||
if (insertedNodeIds.length > 0)
|
||||
this._view.selectItems(insertedNodeIds, false);
|
||||
}
|
||||
|
|
|
@ -60,6 +60,14 @@
|
|||
if (result) {
|
||||
result.root.containerOpen = false;
|
||||
}
|
||||
|
||||
// Unregister the controllber before unlinking the view, otherwise it
|
||||
// may still try to update commands on a view with a null result.
|
||||
if (this._controller) {
|
||||
this._controller.terminate();
|
||||
this.controllers.removeController(this._controller);
|
||||
}
|
||||
|
||||
this.view = null;
|
||||
]]></destructor>
|
||||
|
||||
|
@ -333,6 +341,17 @@
|
|||
]]></getter>
|
||||
</property>
|
||||
|
||||
<method name="toggleCutNode">
|
||||
<parameter name="aNode"/>
|
||||
<parameter name="aValue"/>
|
||||
<body><![CDATA[
|
||||
aNode._cutting = aValue;
|
||||
try {
|
||||
this.view.nodeIconChanged(aNode);
|
||||
} catch(ex) { /* ignore no more valid nodes */ }
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<!-- nsIPlacesView -->
|
||||
<property name="removableSelectionRanges">
|
||||
<getter><![CDATA[
|
||||
|
|
|
@ -1093,6 +1093,11 @@ PlacesTreeView.prototype = {
|
|||
return;
|
||||
|
||||
let node = this._getNodeForRow(aRow);
|
||||
|
||||
if (node._cutting) {
|
||||
aProperties.AppendElement(this._getAtomFor("cutting"));
|
||||
}
|
||||
|
||||
if (!node._cellProperties) {
|
||||
let properties = new Array();
|
||||
let itemId = node.itemId;
|
||||
|
|
|
@ -75,19 +75,6 @@ var PlacesUIUtils = {
|
|||
return URIFixup.createFixupURI(aSpec, Ci.nsIURIFixup.FIXUP_FLAG_NONE);
|
||||
},
|
||||
|
||||
/**
|
||||
* Wraps a string in a nsISupportsString wrapper
|
||||
* @param aString
|
||||
* The string to wrap
|
||||
* @returns A nsISupportsString object containing a string.
|
||||
*/
|
||||
_wrapString: function PUIU__wrapString(aString) {
|
||||
var s = Cc["@mozilla.org/supports-string;1"].
|
||||
createInstance(Ci.nsISupportsString);
|
||||
s.data = aString;
|
||||
return s;
|
||||
},
|
||||
|
||||
getFormattedString: function PUIU_getFormattedString(key, params) {
|
||||
return bundle.formatStringFromName(key, params, params.length);
|
||||
},
|
||||
|
@ -814,9 +801,7 @@ var PlacesUIUtils = {
|
|||
browserWindow.whereToOpenLink(aEvent, false, true) : "window";
|
||||
if (where == "window") {
|
||||
// There is no browser window open, thus open a new one.
|
||||
var uriList = Cc["@mozilla.org/supports-string;1"].
|
||||
createInstance(Ci.nsISupportsString);
|
||||
uriList.data = urls.join("|");
|
||||
var uriList = PlacesUtils.toISupportsString(urls.join("|"));
|
||||
var args = Cc["@mozilla.org/supports-array;1"].
|
||||
createInstance(Ci.nsISupportsArray);
|
||||
args.AppendElement(uriList);
|
||||
|
|
|
@ -73,6 +73,7 @@ _BROWSER_TEST_FILES = \
|
|||
browser_toolbar_migration.js \
|
||||
browser_library_batch_delete.js \
|
||||
browser_555547.js \
|
||||
browser_416459_cut.js \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(_BROWSER_TEST_FILES)
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
const TEST_URL = "http://example.com/";
|
||||
|
||||
let gLibrary;
|
||||
let gItemId;
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
gLibrary = openLibrary(onLibraryReady);
|
||||
}
|
||||
|
||||
function onLibraryReady(library) {
|
||||
PlacesOrganizer = gLibrary.PlacesOrganizer;
|
||||
|
||||
// Sanity checks.
|
||||
ok(PlacesUtils, "PlacesUtils in scope");
|
||||
ok(PlacesUIUtils, "PlacesUIUtils in scope");
|
||||
ok(PlacesOrganizer, "PlacesOrganizer in scope");
|
||||
|
||||
gItemId = PlacesUtils.bookmarks.insertBookmark(
|
||||
PlacesUtils.toolbarFolderId, NetUtil.newURI(TEST_URL),
|
||||
PlacesUtils.bookmarks.DEFAULT_INDEX, "test"
|
||||
);
|
||||
|
||||
selectBookmarkIn("BookmarksToolbar");
|
||||
|
||||
waitForClipboard(function(aData) !!aData,
|
||||
cutSelection,
|
||||
onClipboardReady,
|
||||
PlacesUtils.TYPE_X_MOZ_PLACE);
|
||||
}
|
||||
|
||||
function selectBookmarkIn(aLeftPaneQuery) {
|
||||
info("Selecting " + aLeftPaneQuery + " in the left pane");
|
||||
PlacesOrganizer.selectLeftPaneQuery(aLeftPaneQuery);
|
||||
let rootId = PlacesUtils.getConcreteItemId(PlacesOrganizer._places.selectedNode);
|
||||
is(PlacesUtils.bookmarks.getFolderIdForItem(gItemId), rootId,
|
||||
"Bookmark has the right parent");
|
||||
info("Selecting the bookmark in the right pane");
|
||||
PlacesOrganizer._content.selectItems([gItemId]);
|
||||
let bookmarkNode = PlacesOrganizer._content.selectedNode;
|
||||
is(bookmarkNode.uri, TEST_URL, "Found the expected bookmark");
|
||||
}
|
||||
|
||||
function cutSelection() {
|
||||
info("Cutting selection");
|
||||
PlacesOrganizer._content.controller.cut();
|
||||
}
|
||||
|
||||
function pasteClipboard(aLeftPaneQuery) {
|
||||
info("Selecting " + aLeftPaneQuery + " in the left pane");
|
||||
PlacesOrganizer.selectLeftPaneQuery(aLeftPaneQuery);
|
||||
info("Pasting clipboard");
|
||||
PlacesOrganizer._content.controller.paste();
|
||||
}
|
||||
|
||||
function onClipboardReady() {
|
||||
pasteClipboard("UnfiledBookmarks");
|
||||
selectBookmarkIn("UnfiledBookmarks");
|
||||
|
||||
// Cleanup.
|
||||
gLibrary.close();
|
||||
PlacesUtils.bookmarks.removeFolderChildren(PlacesUtils.unfiledBookmarksFolderId);
|
||||
finish();
|
||||
}
|
|
@ -16,9 +16,13 @@ registerCleanupFunction(function(){
|
|||
|
||||
|
||||
function openLibrary(callback) {
|
||||
var library = window.openDialog("chrome://browser/content/places/places.xul",
|
||||
let library = window.openDialog("chrome://browser/content/places/places.xul",
|
||||
"", "chrome,toolbar=yes,dialog=no,resizable");
|
||||
waitForFocus(function () {
|
||||
callback(library);
|
||||
}, library);
|
||||
|
||||
return library;
|
||||
}
|
||||
|
||||
Components.utils.import("resource://gre/modules/NetUtil.jsm");
|
||||
|
|
|
@ -230,6 +230,16 @@ menuitem.bookmark-item {
|
|||
list-style-image: url("moz-icon://stock/gtk-directory?size=menu");
|
||||
}
|
||||
|
||||
.bookmark-item[cutting] > .toolbarbutton-icon,
|
||||
.bookmark-item[cutting] > .menu-iconic-left > .menu-iconic-icon {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.bookmark-item[cutting] > .toolbarbutton-text,
|
||||
.bookmark-item[cutting] > .menu-iconic-left > .menu-iconic-text {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
/* Stock icons for the menu bar items */
|
||||
menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) {
|
||||
-moz-binding: url("chrome://global/content/bindings/menu.xml#menuitem-iconic");
|
||||
|
|
|
@ -99,13 +99,12 @@ treechildren::-moz-tree-image(title, query, folder) {
|
|||
list-style-image: url("moz-icon://stock/gtk-directory?size=menu");
|
||||
}
|
||||
|
||||
treechildren::-moz-tree-row(session-start) {
|
||||
border-top:1px dotted ThreeDShadow;
|
||||
font-weight: bold;
|
||||
treechildren::-moz-tree-image(cutting) {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
treechildren::-moz-tree-cell-text(date, session-continue) {
|
||||
color: -moz-Field;
|
||||
treechildren::-moz-tree-cell-text(cutting) {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
/**** menuitem stock icons ****/
|
||||
|
|
|
@ -263,6 +263,16 @@ toolbarbutton.bookmark-item > menupopup {
|
|||
height: 16px;
|
||||
}
|
||||
|
||||
.bookmark-item[cutting] > .toolbarbutton-icon,
|
||||
.bookmark-item[cutting] > .menu-iconic-left > .menu-iconic-icon {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.bookmark-item[cutting] > .toolbarbutton-text,
|
||||
.bookmark-item[cutting] > .menu-iconic-left > .menu-iconic-text {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
#bookmarksToolbarFolderMenu,
|
||||
#BMB_bookmarksToolbar {
|
||||
list-style-image: url("chrome://browser/skin/places/bookmarksToolbar.png");
|
||||
|
|
|
@ -119,10 +119,6 @@ treechildren::-moz-tree-image(title, separator) {
|
|||
margin: 0;
|
||||
}
|
||||
|
||||
treechildren::-moz-tree-row(session-start) {
|
||||
border-top:1px dotted ThreeDShadow;
|
||||
}
|
||||
|
||||
treechildren::-moz-tree-image(container, OrganizerQuery_AllBookmarks) {
|
||||
list-style-image: url("chrome://browser/skin/places/allBookmarks.png");
|
||||
}
|
||||
|
@ -178,12 +174,6 @@ treechildren::-moz-tree-image(title, query, folder, open) {
|
|||
-moz-image-region: rect(0, 16px, 16px, 0);
|
||||
}
|
||||
|
||||
/* FIXME this should make the date field invisible, but only does it for
|
||||
unselected items and maybe won't work for different color schemes. */
|
||||
treechildren::-moz-tree-cell-text(date, session-continue) {
|
||||
color:white;
|
||||
}
|
||||
|
||||
treechildren::-moz-tree-cell-text(title, separator) {
|
||||
color: ThreeDShadow;
|
||||
margin: 0px 5px;
|
||||
|
@ -197,3 +187,11 @@ treechildren::-moz-tree-twisty(title, separator) {
|
|||
-moz-appearance: none;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
treechildren::-moz-tree-image(cutting) {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
treechildren::-moz-tree-cell-text(cutting) {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
|
|
@ -566,6 +566,16 @@ menuitem.bookmark-item {
|
|||
-moz-image-region: rect(16px, 32px, 32px, 16px);
|
||||
}
|
||||
|
||||
.bookmark-item[cutting] > .toolbarbutton-icon,
|
||||
.bookmark-item[cutting] > .menu-iconic-left > .menu-iconic-icon {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.bookmark-item[cutting] > .toolbarbutton-text,
|
||||
.bookmark-item[cutting] > .menu-iconic-left > .menu-iconic-text {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
/* ::::: primary toolbar buttons ::::: */
|
||||
|
||||
.toolbarbutton-1 {
|
||||
|
|
|
@ -116,13 +116,12 @@ treechildren::-moz-tree-image(title, query, folder, open) {
|
|||
-moz-image-region: rect(16px, 32px, 32px, 16px);
|
||||
}
|
||||
|
||||
treechildren::-moz-tree-row(session-start) {
|
||||
border-top:1px dotted ThreeDShadow;
|
||||
font-weight: bold;
|
||||
treechildren::-moz-tree-image(cutting) {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
treechildren::-moz-tree-cell-text(date, session-continue) {
|
||||
color: -moz-Field;
|
||||
treechildren::-moz-tree-cell-text(cutting) {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
/* Browser Sidebars */
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# -*- makefile -*-
|
||||
# vim:set ts=8 sw=8 sts=8 noet:
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
|
@ -23,6 +25,7 @@
|
|||
# Benjamin Smedberg <bsmedberg@covad.net>
|
||||
# Chase Phillips <chase@mozilla.org>
|
||||
# Mark Mentovai <mark@moxienet.com>
|
||||
# Joey Armstrong <joey@mozilla.com>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
|
@ -95,14 +98,11 @@ endif
|
|||
AUTOCONF ?= $(shell which autoconf-2.13 autoconf2.13 autoconf213 2>/dev/null | grep -v '^no autoconf' | head -1)
|
||||
|
||||
ifeq (,$(strip $(AUTOCONF)))
|
||||
AUTOCONF=$(error Couldn't find autoconf 2.13)
|
||||
AUTOCONF=$(error Could not find autoconf 2.13)
|
||||
endif
|
||||
|
||||
MKDIR := mkdir
|
||||
SH := /bin/sh
|
||||
ifndef MAKE
|
||||
MAKE := gmake
|
||||
endif
|
||||
PERL ?= perl
|
||||
PYTHON ?= python
|
||||
|
||||
|
|
|
@ -8451,7 +8451,10 @@ if test -z "${GLIB_CFLAGS}" -o -z "${GLIB_LIBS}" ; then
|
|||
fi
|
||||
fi
|
||||
|
||||
if test -z "${GLIB_GMODULE_LIBS}" -a -n "${GLIB_CONFIG}"; then
|
||||
if test -z "${GLIB_GMODULE_LIBS}" \
|
||||
-a -n "${GLIB_CONFIG}"\
|
||||
-a "${GLIB_CONFIG}" != no\
|
||||
; then
|
||||
GLIB_GMODULE_LIBS=`$GLIB_CONFIG gmodule --libs`
|
||||
fi
|
||||
|
||||
|
|
|
@ -72,8 +72,10 @@ public:
|
|||
NS_DECL_NSIDOMFILE
|
||||
NS_DECL_NSIXHRSENDABLE
|
||||
|
||||
nsDOMFile(nsIFile *aFile, const nsAString& aContentType)
|
||||
nsDOMFile(nsIFile *aFile, const nsAString& aContentType,
|
||||
nsISupports *aCacheToken = nsnull)
|
||||
: mFile(aFile),
|
||||
mCacheToken(aCacheToken),
|
||||
mContentType(aContentType),
|
||||
mIsFullFile(true)
|
||||
{}
|
||||
|
@ -86,6 +88,7 @@ public:
|
|||
nsDOMFile(const nsDOMFile* aOther, PRUint64 aStart, PRUint64 aLength,
|
||||
const nsAString& aContentType)
|
||||
: mFile(aOther->mFile),
|
||||
mCacheToken(aOther->mCacheToken),
|
||||
mStart(aOther->mIsFullFile ? aStart :
|
||||
(aOther->mStart + aStart)),
|
||||
mLength(aLength),
|
||||
|
@ -112,6 +115,7 @@ public:
|
|||
|
||||
protected:
|
||||
nsCOMPtr<nsIFile> mFile;
|
||||
nsCOMPtr<nsISupports> mCacheToken;
|
||||
|
||||
// start and length in
|
||||
PRUint64 mStart;
|
||||
|
|
|
@ -1915,6 +1915,8 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDocument)
|
|||
}
|
||||
tmp->mFirstChild = nsnull;
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mScriptEventManager)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mXPathEvaluatorTearoff)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mCachedRootElement)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDisplayDocument)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mFirstBaseNodeWithHref)
|
||||
|
@ -1937,16 +1939,27 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDocument)
|
|||
tmp->mBoxObjectTable = nsnull;
|
||||
}
|
||||
|
||||
if (tmp->mListenerManager) {
|
||||
tmp->mListenerManager->Disconnect();
|
||||
tmp->mListenerManager = nsnull;
|
||||
}
|
||||
|
||||
if (tmp->mSubDocuments) {
|
||||
PL_DHashTableDestroy(tmp->mSubDocuments);
|
||||
tmp->mSubDocuments = nsnull;
|
||||
}
|
||||
|
||||
tmp->mAnimationFrameListeners.Clear();
|
||||
|
||||
tmp->mRadioGroups.Clear();
|
||||
|
||||
// nsDocument has a pretty complex destructor, so we're going to
|
||||
// assume that *most* cycles you actually want to break somewhere
|
||||
// else, and not unlink an awful lot here.
|
||||
//
|
||||
// In rare cases where you think an unlink will help here, add one
|
||||
// manually.
|
||||
|
||||
tmp->mInUnlinkOrDeletion = PR_FALSE;
|
||||
|
||||
tmp->mIdentifierMap.Clear();
|
||||
|
||||
tmp->mInUnlinkOrDeletion = PR_FALSE;
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
|
||||
|
|
|
@ -1616,8 +1616,25 @@ void nsXMLHttpRequest::CreateResponseBlob(nsIRequest *request)
|
|||
if (file) {
|
||||
nsCAutoString contentType;
|
||||
mChannel->GetContentType(contentType);
|
||||
mResponseBlob = new nsDOMFile(file,
|
||||
NS_ConvertASCIItoUTF16(contentType));
|
||||
nsCOMPtr<nsISupports> cacheToken;
|
||||
if (cc) {
|
||||
cc->GetCacheToken(getter_AddRefs(cacheToken));
|
||||
}
|
||||
|
||||
NS_ConvertASCIItoUTF16 wideContentType(contentType);
|
||||
|
||||
nsCOMPtr<nsIDOMBlob> blob =
|
||||
new nsDOMFile(file, wideContentType, cacheToken);
|
||||
|
||||
// XXXkhuey this is a complete hack ... but we need to get 6 out the door
|
||||
// The response blob here should not be a File object, it should only
|
||||
// be a Blob. Unfortunately, because nsDOMFile has grown through
|
||||
// accretion over the years and is in dangerous need of a refactoring,
|
||||
// slicing it is the easiest way to get there ...
|
||||
PRUint64 size = 0;
|
||||
blob->GetSize(&size);
|
||||
blob->MozSlice(0, size, wideContentType, 2, getter_AddRefs(mResponseBlob));
|
||||
|
||||
mResponseBody.Truncate();
|
||||
mResponseBodyUnicode.SetIsVoid(PR_TRUE);
|
||||
}
|
||||
|
@ -1888,9 +1905,20 @@ nsXMLHttpRequest::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult
|
|||
void *blobData = PR_Malloc(blobLen);
|
||||
if (blobData) {
|
||||
memcpy(blobData, mResponseBody.BeginReading(), blobLen);
|
||||
mResponseBlob =
|
||||
|
||||
NS_ConvertASCIItoUTF16 wideContentType(contentType);
|
||||
nsCOMPtr<nsIDOMBlob> blob =
|
||||
new nsDOMMemoryFile(blobData, blobLen, EmptyString(),
|
||||
NS_ConvertASCIItoUTF16(contentType));
|
||||
wideContentType);
|
||||
|
||||
// XXXkhuey this is a complete hack ... but we need to get 6 out the door
|
||||
// The response blob here should not be a File object, it should only
|
||||
// be a Blob. Unfortunately, because nsDOMFile has grown through
|
||||
// accretion over the years and is in dangerous need of a refactoring,
|
||||
// slicing it is the easiest way to get there ...
|
||||
blob->MozSlice(0, blobLen, wideContentType,
|
||||
2, getter_AddRefs(mResponseBlob));
|
||||
|
||||
mResponseBody.Truncate();
|
||||
}
|
||||
NS_ASSERTION(mResponseBodyUnicode.IsVoid(),
|
||||
|
|
|
@ -160,6 +160,8 @@ checkResponseTextAccessThrows(xhr);
|
|||
checkResponseXMLAccessThrows(xhr);
|
||||
b = xhr.response;
|
||||
ok(b, "should have a non-null blob");
|
||||
ok(b instanceof Blob, "should be a Blob");
|
||||
ok(!(b instanceof File), "should not be a File");
|
||||
is(b.size, "hello pass\n".length, "wrong blob size");
|
||||
|
||||
var fr = new FileReader();
|
||||
|
|
|
@ -57,6 +57,21 @@ NS_INTERFACE_MAP_END
|
|||
|
||||
/* Implementation */
|
||||
|
||||
static nsresult
|
||||
GetValueFromString(const nsAString &aValueAsString,
|
||||
PRBool *aValue)
|
||||
{
|
||||
if (aValueAsString.EqualsLiteral("true")) {
|
||||
*aValue = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
if (aValueAsString.EqualsLiteral("false")) {
|
||||
*aValue = PR_FALSE;
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSVGBoolean::SetBaseValueString(const nsAString &aValueAsString,
|
||||
nsSVGElement *aSVGElement,
|
||||
|
@ -64,12 +79,10 @@ nsSVGBoolean::SetBaseValueString(const nsAString &aValueAsString,
|
|||
{
|
||||
PRBool val;
|
||||
|
||||
if (aValueAsString.EqualsLiteral("true"))
|
||||
val = PR_TRUE;
|
||||
else if (aValueAsString.EqualsLiteral("false"))
|
||||
val = PR_FALSE;
|
||||
else
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
nsresult rv = GetValueFromString(aValueAsString, &val);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
mBaseVal = val;
|
||||
if (!mIsAnimated) {
|
||||
|
@ -148,17 +161,17 @@ nsSVGBoolean::SMILBool::ValueFromString(const nsAString& aStr,
|
|||
nsSMILValue& aValue,
|
||||
PRBool& aPreventCachingOfSandwich) const
|
||||
{
|
||||
PRBool value;
|
||||
nsresult rv = GetValueFromString(aStr, &value);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsSMILValue val(&SMILBoolType::sSingleton);
|
||||
|
||||
if (aStr.EqualsLiteral("true"))
|
||||
val.mU.mBool = PR_TRUE;
|
||||
else if (aStr.EqualsLiteral("false"))
|
||||
val.mU.mBool = PR_FALSE;
|
||||
else
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
val.mU.mBool = value;
|
||||
aValue = val;
|
||||
aPreventCachingOfSandwich = PR_FALSE;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -391,6 +391,8 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
|||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsXULDocument, nsXMLDocument)
|
||||
delete tmp->mTemplateBuilderTable;
|
||||
tmp->mTemplateBuilderTable = nsnull;
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mCommandDispatcher)
|
||||
//XXX We should probably unlink all the objects we traverse.
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
|
|
|
@ -190,13 +190,20 @@ nsXULPrototypeDocument::~nsXULPrototypeDocument()
|
|||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(nsXULPrototypeDocument)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_0(nsXULPrototypeDocument)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXULPrototypeDocument)
|
||||
tmp->mPrototypeWaiters.Clear();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsXULPrototypeDocument)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_MEMBER(mRoot,
|
||||
nsXULPrototypeElement)
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mGlobalObject");
|
||||
cb.NoteXPCOMChild(static_cast<nsIScriptGlobalObject*>(tmp->mGlobalObject));
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_MEMBER(mNodeInfoManager,
|
||||
nsNodeInfoManager)
|
||||
for (PRUint32 i = 0; i < tmp->mPrototypeWaiters.Length(); ++i) {
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mPrototypeWaiters[i]");
|
||||
cb.NoteXPCOMChild(static_cast<nsINode*>(tmp->mPrototypeWaiters[i].get()));
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXULPrototypeDocument)
|
||||
|
|
|
@ -81,9 +81,15 @@ public:
|
|||
mQuerySetPriority(aQuerySetPriority),
|
||||
mContainer(aContainer),
|
||||
mResult(aResult),
|
||||
mNext(nsnull) {}
|
||||
mNext(nsnull)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsTemplateMatch);
|
||||
}
|
||||
|
||||
~nsTemplateMatch() {}
|
||||
~nsTemplateMatch()
|
||||
{
|
||||
MOZ_COUNT_DTOR(nsTemplateMatch);
|
||||
}
|
||||
|
||||
static nsTemplateMatch*
|
||||
Create(nsFixedSizeAllocator& aPool,
|
||||
|
|
|
@ -275,6 +275,11 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXULTemplateBuilder)
|
|||
if (tmp->mMatchMap.IsInitialized()) {
|
||||
tmp->mMatchMap.Enumerate(DestroyMatchList, &(tmp->mPool));
|
||||
}
|
||||
for (PRUint32 i = 0; i < tmp->mQuerySets.Length(); ++i) {
|
||||
nsTemplateQuerySet* qs = tmp->mQuerySets[i];
|
||||
delete qs;
|
||||
}
|
||||
tmp->mQuerySets.Clear();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsXULTemplateBuilder)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDataSource)
|
||||
|
|
|
@ -86,7 +86,9 @@ nsIRDFResource* nsXULTemplateQueryProcessorRDF::kNC_BookmarkSeparator;
|
|||
nsIRDFResource* nsXULTemplateQueryProcessorRDF::kRDF_type;
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(nsXULTemplateQueryProcessorRDF)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_0(nsXULTemplateQueryProcessorRDF)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXULTemplateQueryProcessorRDF)
|
||||
tmp->Done();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
static PLDHashOperator
|
||||
BindingDependenciesTraverser(nsISupports* key,
|
||||
|
@ -1056,7 +1058,7 @@ nsXULTemplateQueryProcessorRDF::SynchronizeAll(nsIRDFResource* aSource,
|
|||
// Get all the matches whose assignments are currently supported
|
||||
// by aSource and aProperty: we'll need to recompute them.
|
||||
nsCOMArray<nsXULTemplateResultRDF>* results;
|
||||
if (!mBindingDependencies.Get(aSource, &results))
|
||||
if (!mBindingDependencies.Get(aSource, &results) || !mBuilder)
|
||||
return NS_OK;
|
||||
|
||||
PRUint32 length = results->Count();
|
||||
|
@ -1125,6 +1127,7 @@ nsXULTemplateQueryProcessorRDF::CheckContainer(nsIRDFResource* aResource,
|
|||
PRBool* aIsContainer)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aIsContainer);
|
||||
NS_ENSURE_STATE(mDB);
|
||||
|
||||
// We have to look at all of the arcs extending out of the
|
||||
// resource: if any of them are that "containment" property, then
|
||||
|
@ -1159,6 +1162,7 @@ nsresult
|
|||
nsXULTemplateQueryProcessorRDF::CheckEmpty(nsIRDFResource* aResource,
|
||||
PRBool* aIsEmpty)
|
||||
{
|
||||
NS_ENSURE_STATE(mDB);
|
||||
*aIsEmpty = PR_TRUE;
|
||||
|
||||
for (nsResourceSet::ConstIterator property = mContainmentProperties.First();
|
||||
|
@ -1186,6 +1190,7 @@ nsresult
|
|||
nsXULTemplateQueryProcessorRDF::CheckIsSeparator(nsIRDFResource* aResource,
|
||||
PRBool* aIsSeparator)
|
||||
{
|
||||
NS_ENSURE_STATE(mDB);
|
||||
return mDB->HasAssertion(aResource, kRDF_type, kNC_BookmarkSeparator,
|
||||
PR_TRUE, aIsSeparator);
|
||||
}
|
||||
|
@ -1903,7 +1908,7 @@ nsXULTemplateQueryProcessorRDF::GetContainerIndexOf(nsIXULTemplateResult* aResul
|
|||
nsCOMPtr<nsISupports> ref;
|
||||
nsresult rv = aResult->GetBindingObjectFor(mRefVariable,
|
||||
getter_AddRefs(ref));
|
||||
if (NS_FAILED(rv))
|
||||
if (NS_FAILED(rv) || !mDB)
|
||||
return -1;
|
||||
|
||||
nsCOMPtr<nsIRDFResource> container = do_QueryInterface(ref);
|
||||
|
@ -1940,7 +1945,7 @@ nsXULTemplateQueryProcessorRDF::GetSortValue(nsIXULTemplateResult* aResult,
|
|||
return rv;
|
||||
|
||||
nsCOMPtr<nsIRDFNode> value;
|
||||
if (source) {
|
||||
if (source && mDB) {
|
||||
// first check predicate?sort=true so that datasources may use a
|
||||
// custom value for sorting
|
||||
rv = mDB->GetTarget(source, aSortPredicate, PR_TRUE,
|
||||
|
|
|
@ -81,6 +81,7 @@ class nsXULTreeBuilder : public nsXULTemplateBuilder,
|
|||
public:
|
||||
// nsISupports
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsXULTreeBuilder, nsXULTemplateBuilder)
|
||||
|
||||
// nsIXULTreeBuilder
|
||||
NS_DECL_NSIXULTREEBUILDER
|
||||
|
@ -304,15 +305,42 @@ NS_NewXULTreeBuilder(nsISupports* aOuter, REFNSIID aIID, void** aResult)
|
|||
return rv;
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(nsXULTreeBuilder)
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(nsXULTreeBuilder, nsXULTemplateBuilder)
|
||||
NS_IMPL_RELEASE_INHERITED(nsXULTreeBuilder, nsXULTemplateBuilder)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsXULTreeBuilder, nsXULTemplateBuilder)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mBoxObject)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mSelection)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mPersistStateStore)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mObservers)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
static PRBool TraverseObservers(nsISupports* aElement, void *aData)
|
||||
{
|
||||
nsCycleCollectionTraversalCallback *cb =
|
||||
static_cast<nsCycleCollectionTraversalCallback*>(aData);
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, "mObservers[i]");
|
||||
cb->NoteXPCOMChild(aElement);
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXULTreeBuilder, nsXULTemplateBuilder)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mBoxObject)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mSelection)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mPersistStateStore)
|
||||
if (tmp->mObservers) {
|
||||
tmp->mObservers->EnumerateForwards(TraverseObservers, &cb);
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
DOMCI_DATA(XULTreeBuilder, nsXULTreeBuilder)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(nsXULTreeBuilder)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIXULTreeBuilder)
|
||||
NS_INTERFACE_MAP_ENTRY(nsITreeView)
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(XULTreeBuilder)
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsXULTreeBuilder)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIXULTreeBuilder)
|
||||
NS_INTERFACE_MAP_ENTRY(nsITreeView)
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(XULTreeBuilder)
|
||||
NS_INTERFACE_MAP_END_INHERITING(nsXULTemplateBuilder)
|
||||
|
||||
|
||||
|
|
|
@ -120,10 +120,19 @@ interface nsIXPCComponents_utils_Sandbox : nsISupports
|
|||
{
|
||||
};
|
||||
|
||||
/**
|
||||
* interface for callback to be passed to Cu.schedulePreciseGC
|
||||
*/
|
||||
[scriptable, function, uuid(71000535-b0fd-44d1-8ce0-909760e3953c)]
|
||||
interface ScheduledGCCallback : nsISupports
|
||||
{
|
||||
void callback();
|
||||
};
|
||||
|
||||
/**
|
||||
* interface of Components.utils
|
||||
*/
|
||||
[scriptable, uuid(5f0acf45-135a-48d1-976c-082ce3b24ead)]
|
||||
[scriptable, uuid(fed2d752-6cb3-4135-97b0-2c290e541e2d)]
|
||||
interface nsIXPCComponents_Utils : nsISupports
|
||||
{
|
||||
|
||||
|
@ -228,6 +237,13 @@ interface nsIXPCComponents_Utils : nsISupports
|
|||
*/
|
||||
void forceGC();
|
||||
|
||||
/*
|
||||
* Schedule a garbage collection cycle for a point in the future when no JS
|
||||
* is running. Call the provided function once this has occurred.
|
||||
*/
|
||||
[implicit_jscontext]
|
||||
void schedulePreciseGC(in ScheduledGCCallback callback);
|
||||
|
||||
/*
|
||||
* To be called from JS only.
|
||||
*
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
#include "nsNullPrincipal.h"
|
||||
#include "nsJSUtils.h"
|
||||
#include "mozJSComponentLoader.h"
|
||||
#include "nsContentUtils.h"
|
||||
|
||||
/***************************************************************************/
|
||||
// stuff used by all
|
||||
|
@ -3775,6 +3776,48 @@ nsXPCComponents_Utils::ForceGC()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
class PreciseGCRunnable : public nsRunnable
|
||||
{
|
||||
public:
|
||||
PreciseGCRunnable(JSContext *aCx, ScheduledGCCallback* aCallback)
|
||||
: mCallback(aCallback), mCx(aCx) {}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
nsCOMPtr<nsIJSRuntimeService> runtimeSvc = do_GetService("@mozilla.org/js/xpc/RuntimeService;1");
|
||||
NS_ENSURE_STATE(runtimeSvc);
|
||||
|
||||
JSRuntime* rt = nsnull;
|
||||
runtimeSvc->GetRuntime(&rt);
|
||||
NS_ENSURE_STATE(rt);
|
||||
|
||||
JSContext *cx;
|
||||
JSContext *iter = nsnull;
|
||||
while ((cx = JS_ContextIterator(rt, &iter)) != NULL) {
|
||||
if (JS_IsRunning(cx)) {
|
||||
return NS_DispatchToMainThread(this);
|
||||
}
|
||||
}
|
||||
|
||||
JS_GC(mCx);
|
||||
|
||||
mCallback->Callback();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<ScheduledGCCallback> mCallback;
|
||||
JSContext *mCx;
|
||||
};
|
||||
|
||||
/* [inline_jscontext] void schedulePreciseGC(in ScheduledGCCallback callback); */
|
||||
NS_IMETHODIMP
|
||||
nsXPCComponents_Utils::SchedulePreciseGC(ScheduledGCCallback* aCallback, JSContext* aCx)
|
||||
{
|
||||
nsRefPtr<PreciseGCRunnable> event = new PreciseGCRunnable(aCx, aCallback);
|
||||
return NS_DispatchToMainThread(event);
|
||||
}
|
||||
|
||||
/* void getGlobalForObject(); */
|
||||
NS_IMETHODIMP
|
||||
nsXPCComponents_Utils::GetGlobalForObject()
|
||||
|
|
|
@ -66,6 +66,7 @@ _CHROME_FILES = \
|
|||
test_bug596580.xul \
|
||||
test_bug654370.xul \
|
||||
test_bug658560.xul \
|
||||
test_precisegc.xul \
|
||||
$(NULL)
|
||||
|
||||
# Disabled until this test gets updated to test the new proxy based
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
|
||||
type="text/css"?>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=533596
|
||||
-->
|
||||
<window title="Mozilla Bug 661927"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
|
||||
<!-- test results are displayed in the html:body -->
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
|
||||
</body>
|
||||
|
||||
<!-- test code goes here -->
|
||||
<script type="application/javascript"><![CDATA[
|
||||
Components.utils.schedulePreciseGC(
|
||||
function() {
|
||||
ok(true, "callback executed");
|
||||
SimpleTest.finish();
|
||||
});
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
]]></script>
|
||||
</window>
|
|
@ -3656,6 +3656,7 @@ DocumentViewerImpl::Print(nsIPrintSettings* aPrintSettings,
|
|||
return pDoc->Print();
|
||||
|
||||
if (!mPrintEngine) {
|
||||
NS_ENSURE_STATE(mDeviceContext);
|
||||
mPrintEngine = new nsPrintEngine();
|
||||
|
||||
rv = mPrintEngine->Initialize(this, mContainer, mDocument,
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<?xml-stylesheet type="text/css" href="data:text/css,
|
||||
tree { height: 100px; -moz-appearance: none; border: none; }
|
||||
treecol, treecolpicker { visibility: hidden; }
|
||||
treechildren::-moz-tree-cell-text { opacity: 0; }
|
||||
"?>
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<tree>
|
||||
<treecols>
|
||||
<treecol flex="1"/>
|
||||
</treecols>
|
||||
<treechildren>
|
||||
<treeitem>
|
||||
<treerow>
|
||||
<treecell label="test"/>
|
||||
</treerow>
|
||||
</treeitem>
|
||||
</treechildren>
|
||||
</tree>
|
||||
</window>
|
|
@ -1649,3 +1649,4 @@ fails-if(layersGPUAccelerated&&cocoaWidget) == 654950-1.html 654950-1-ref.html #
|
|||
== 658952.html 658952-ref.html
|
||||
== 664127-1.xul 664127-1-ref.xul
|
||||
== 660682-1.html 660682-1-ref.html
|
||||
== 668319-1.xul about:blank
|
||||
|
|
|
@ -3553,6 +3553,9 @@ nsTreeBodyFrame::PaintText(PRInt32 aRowIndex,
|
|||
// out and to paint.
|
||||
nsStyleContext* textContext = GetPseudoStyleContext(nsCSSAnonBoxes::moztreecelltext);
|
||||
|
||||
// Obtain opacity value for the image.
|
||||
float opacity = textContext->GetStyleDisplay()->mOpacity;
|
||||
|
||||
// Obtain the margins for the text and then deflate our rect by that
|
||||
// amount. The text is assumed to be contained within the deflated rect.
|
||||
nsRect textRect(aTextRect);
|
||||
|
@ -3619,8 +3622,19 @@ nsTreeBodyFrame::PaintText(PRInt32 aRowIndex,
|
|||
PRUint8 direction = aTextRTL ? NS_STYLE_DIRECTION_RTL :
|
||||
NS_STYLE_DIRECTION_LTR;
|
||||
|
||||
gfxContext* ctx = aRenderingContext.ThebesContext();
|
||||
if (opacity != 1.0f) {
|
||||
ctx->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
|
||||
}
|
||||
|
||||
nsLayoutUtils::DrawString(this, &aRenderingContext, text.get(), text.Length(),
|
||||
textRect.TopLeft() + nsPoint(0, baseline), direction);
|
||||
|
||||
if (opacity != 1.0f) {
|
||||
ctx->PopGroupToSource();
|
||||
ctx->Paint(opacity);
|
||||
}
|
||||
|
||||
#ifdef MOZ_TIMELINE
|
||||
NS_TIMELINE_STOP_TIMER("Render Outline Text");
|
||||
NS_TIMELINE_MARK_TIMER("Render Outline Text");
|
||||
|
|
|
@ -428,12 +428,14 @@ HistoryTracker.prototype = {
|
|||
onEndUpdateBatch: function HT_onEndUpdateBatch() {},
|
||||
onPageChanged: function HT_onPageChanged() {},
|
||||
onTitleChanged: function HT_onTitleChanged() {},
|
||||
onDeleteVisits: function () {},
|
||||
onDeleteURI: function () {},
|
||||
|
||||
/* Every add is worth 1 point.
|
||||
* OnBeforeDeleteURI will triggger a sync for MULTI-DEVICE (see below)
|
||||
* Clearing all history will trigger a sync for MULTI-DEVICE (see below)
|
||||
*/
|
||||
_upScoreXLarge: function BMT__upScore() {
|
||||
_upScoreXLarge: function HT__upScoreXLarge() {
|
||||
this.score += SCORE_INCREMENT_XLARGE;
|
||||
},
|
||||
|
||||
|
@ -445,18 +447,16 @@ HistoryTracker.prototype = {
|
|||
this.score += SCORE_INCREMENT_SMALL;
|
||||
}
|
||||
},
|
||||
onDeleteVisits: function onDeleteVisits() {
|
||||
},
|
||||
onBeforeDeleteURI: function onBeforeDeleteURI(uri, guid) {
|
||||
if (this.ignoreAll)
|
||||
|
||||
onBeforeDeleteURI: function onBeforeDeleteURI(uri, guid, reason) {
|
||||
if (this.ignoreAll || reason == Ci.nsINavHistoryObserver.REASON_EXPIRED)
|
||||
return;
|
||||
this._log.trace("onBeforeDeleteURI: " + uri.spec);
|
||||
if (this.addChangedID(guid)) {
|
||||
this._upScoreXLarge();
|
||||
}
|
||||
},
|
||||
onDeleteURI: function HT_onDeleteURI(uri, guid) {
|
||||
},
|
||||
|
||||
onClearHistory: function HT_onClearHistory() {
|
||||
this._log.trace("onClearHistory");
|
||||
this._upScoreXLarge();
|
||||
|
|
|
@ -21,10 +21,10 @@ let tracker = engine._tracker;
|
|||
|
||||
let _counter = 0;
|
||||
function addVisit() {
|
||||
PlacesUtils.history.addVisit(
|
||||
Utils.makeURI("http://getfirefox.com/" + _counter),
|
||||
Date.now() * 1000, null, 1, false, 0);
|
||||
_counter += 1;
|
||||
let uri = Utils.makeURI("http://getfirefox.com/" + _counter);
|
||||
PlacesUtils.history.addVisit(uri, Date.now() * 1000, null, 1, false, 0);
|
||||
_counter++;
|
||||
return uri;
|
||||
}
|
||||
|
||||
|
||||
|
@ -87,6 +87,38 @@ add_test(function test_track_delete() {
|
|||
PlacesUtils.history.removePage(uri);
|
||||
});
|
||||
|
||||
add_test(function test_dont_track_expiration() {
|
||||
_("Expirations are not tracked.");
|
||||
let uriToExpire = addVisit();
|
||||
let guidToExpire = engine._store.GUIDForUri(uriToExpire);
|
||||
let uriToRemove = addVisit();
|
||||
let guidToRemove = engine._store.GUIDForUri(uriToRemove);
|
||||
|
||||
tracker.clearChangedIDs();
|
||||
do_check_false(guidToExpire in tracker.changedIDs);
|
||||
do_check_false(guidToRemove in tracker.changedIDs);
|
||||
|
||||
onScoreUpdated(function() {
|
||||
do_check_false(guidToExpire in tracker.changedIDs);
|
||||
do_check_true(guidToRemove in tracker.changedIDs);
|
||||
do_check_eq([id for (id in tracker.changedIDs)].length, 1);
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
// Observe expiration.
|
||||
Services.obs.addObserver(function onExpiration(aSubject, aTopic, aData) {
|
||||
Services.obs.removeObserver(onExpiration, aTopic);
|
||||
// Remove the remaining page to update its score.
|
||||
PlacesUtils.history.removePage(uriToRemove);
|
||||
}, PlacesUtils.TOPIC_EXPIRATION_FINISHED, false);
|
||||
|
||||
// Force expiration of 1 entry.
|
||||
Services.prefs.setIntPref("places.history.expiration.max_pages", 0);
|
||||
Cc["@mozilla.org/places/expiration;1"]
|
||||
.getService(Ci.nsIObserver)
|
||||
.observe(null, "places-debug-start-expiration", 1);
|
||||
});
|
||||
|
||||
add_test(function test_stop_tracking() {
|
||||
_("Let's stop tracking again.");
|
||||
tracker.clearChangedIDs();
|
||||
|
|
|
@ -1858,19 +1858,25 @@ nsDownloadManager::OnVisit(nsIURI *aURI, PRInt64 aVisitID, PRTime aTime,
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDownloadManager::OnTitleChanged(nsIURI *aURI, const nsAString &aPageTitle)
|
||||
nsDownloadManager::OnTitleChanged(nsIURI *aURI,
|
||||
const nsAString &aPageTitle,
|
||||
const nsACString &aGUID)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDownloadManager::OnBeforeDeleteURI(nsIURI *aURI, const nsACString& aGUID)
|
||||
nsDownloadManager::OnBeforeDeleteURI(nsIURI *aURI,
|
||||
const nsACString& aGUID,
|
||||
PRUint16 aReason)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDownloadManager::OnDeleteURI(nsIURI *aURI, const nsACString& aGUID)
|
||||
nsDownloadManager::OnDeleteURI(nsIURI *aURI,
|
||||
const nsACString& aGUID,
|
||||
PRUint16 aReason)
|
||||
{
|
||||
return RemoveDownloadsForURI(aURI);
|
||||
}
|
||||
|
@ -1882,15 +1888,18 @@ nsDownloadManager::OnClearHistory()
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDownloadManager::OnPageChanged(nsIURI *aURI, PRUint32 aWhat,
|
||||
const nsAString &aValue)
|
||||
nsDownloadManager::OnPageChanged(nsIURI *aURI,
|
||||
PRUint32 aChangedAttribute,
|
||||
const nsAString& aNewValue,
|
||||
const nsACString &aGUID)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDownloadManager::OnDeleteVisits(nsIURI *aURI, PRTime aVisitTime,
|
||||
const nsACString& aGUID)
|
||||
const nsACString& aGUID,
|
||||
PRUint16 aReason)
|
||||
{
|
||||
// Don't bother removing downloads until the page is removed.
|
||||
return NS_OK;
|
||||
|
|
|
@ -120,7 +120,7 @@ FetchPageInfo(StatementCache<mozIStorageStatement>& aStmtCache,
|
|||
|
||||
nsCOMPtr<mozIStorageStatement> stmt =
|
||||
aStmtCache.GetCachedStatement(NS_LITERAL_CSTRING(
|
||||
"SELECT h.id, h.favicon_id, "
|
||||
"SELECT h.id, h.favicon_id, h.guid, "
|
||||
"(") + redirectedBookmarksFragment + NS_LITERAL_CSTRING(") "
|
||||
"FROM moz_places h WHERE h.url = :page_url"
|
||||
));
|
||||
|
@ -142,19 +142,20 @@ FetchPageInfo(StatementCache<mozIStorageStatement>& aStmtCache,
|
|||
rv = stmt->GetInt64(0, &_page.id);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
PRBool isNull;
|
||||
stmt->GetIsNull(1, &isNull);
|
||||
rv = stmt->GetIsNull(1, &isNull);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
// favicon_id can be NULL.
|
||||
if (!isNull) {
|
||||
rv = stmt->GetInt64(1, &_page.iconId);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
stmt->GetIsNull(2, &isNull);
|
||||
rv = stmt->GetUTF8String(2, _page.guid);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = stmt->GetIsNull(3, &isNull);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
// The page could not be bookmarked.
|
||||
if (!isNull) {
|
||||
rv = stmt->GetUTF8String(2, _page.bookmarkedSpec);
|
||||
rv = stmt->GetUTF8String(3, _page.bookmarkedSpec);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
|
@ -807,6 +808,10 @@ AsyncAssociateIconToPage::Run()
|
|||
rv = stmt->Execute();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Get the new id and GUID.
|
||||
rv = FetchPageInfo(mFaviconSvc->mSyncStatements, mPage);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mIcon.status |= ICON_STATUS_ASSOCIATED;
|
||||
}
|
||||
// Otherwise just associate the icon to the page, if needed.
|
||||
|
@ -959,7 +964,7 @@ NotifyIconObservers::Run()
|
|||
rv = NS_NewURI(getter_AddRefs(pageURI), mPage.spec);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mFaviconSvc->SendFaviconNotifications(pageURI, iconURI);
|
||||
mFaviconSvc->SendFaviconNotifications(pageURI, iconURI, mPage.guid);
|
||||
|
||||
// If the page is bookmarked and the bookmarked url is different from the
|
||||
// updated one, start a new task to update its icon as well.
|
||||
|
|
|
@ -102,6 +102,7 @@ struct PageData
|
|||
, canAddToHistory(true)
|
||||
, iconId(0)
|
||||
{
|
||||
guid.SetIsVoid(PR_TRUE);
|
||||
}
|
||||
|
||||
PRInt64 id;
|
||||
|
@ -110,6 +111,7 @@ struct PageData
|
|||
nsString revHost;
|
||||
bool canAddToHistory; // False for disabled history and unsupported schemas.
|
||||
PRInt64 iconId;
|
||||
nsCString guid;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -499,9 +499,11 @@ public:
|
|||
* The new title to notify about.
|
||||
*/
|
||||
NotifyTitleObservers(const nsCString& aSpec,
|
||||
const nsString& aTitle)
|
||||
const nsString& aTitle,
|
||||
const nsCString& aGUID)
|
||||
: mSpec(aSpec)
|
||||
, mTitle(aTitle)
|
||||
, mGUID(aGUID)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -514,13 +516,14 @@ public:
|
|||
NS_ENSURE_TRUE(navHistory, NS_ERROR_OUT_OF_MEMORY);
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
(void)NS_NewURI(getter_AddRefs(uri), mSpec);
|
||||
navHistory->NotifyTitleChange(uri, mTitle);
|
||||
navHistory->NotifyTitleChange(uri, mTitle, mGUID);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
private:
|
||||
const nsCString mSpec;
|
||||
const nsString mTitle;
|
||||
const nsCString mGUID;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -697,7 +700,7 @@ public:
|
|||
|
||||
// Notify about title change if needed.
|
||||
if ((!known && !place.title.IsVoid()) || place.titleChanged) {
|
||||
event = new NotifyTitleObservers(place.spec, place.title);
|
||||
event = new NotifyTitleObservers(place.spec, place.title, place.guid);
|
||||
rv = NS_DispatchToMainThread(event);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
@ -1166,7 +1169,7 @@ public:
|
|||
}
|
||||
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
new NotifyTitleObservers(mPlace.spec, mPlace.title);
|
||||
new NotifyTitleObservers(mPlace.spec, mPlace.title, mPlace.guid);
|
||||
nsresult rv = NS_DispatchToMainThread(event);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
|
|
|
@ -129,6 +129,8 @@ var PlacesUtils = {
|
|||
TYPE_HTML: "text/html",
|
||||
// Place entries as raw URL text
|
||||
TYPE_UNICODE: "text/unicode",
|
||||
// Used to track the action that populated the clipboard.
|
||||
TYPE_X_MOZ_PLACE_ACTION: "text/x-moz-place-action",
|
||||
|
||||
EXCLUDE_FROM_BACKUP_ANNO: "places/excludeFromBackup",
|
||||
GUID_ANNO: "placesInternal/GUID",
|
||||
|
@ -165,6 +167,19 @@ var PlacesUtils = {
|
|||
return NetUtil.newURI(aSpec);
|
||||
},
|
||||
|
||||
/**
|
||||
* Wraps a string in a nsISupportsString wrapper.
|
||||
* @param aString
|
||||
* The string to wrap.
|
||||
* @returns A nsISupportsString object containing a string.
|
||||
*/
|
||||
toISupportsString: function PU_toISupportsString(aString) {
|
||||
let s = Cc["@mozilla.org/supports-string;1"].
|
||||
createInstance(Ci.nsISupportsString);
|
||||
s.data = aString;
|
||||
return s;
|
||||
},
|
||||
|
||||
getFormattedString: function PU_getFormattedString(key, params) {
|
||||
return bundle.formatStringFromName(key, params, params.length);
|
||||
},
|
||||
|
|
|
@ -256,16 +256,92 @@ nsFaviconService::SetFaviconUrlForPage(nsIURI* aPageURI, nsIURI* aFaviconURI)
|
|||
NS_ENSURE_ARG(aPageURI);
|
||||
NS_ENSURE_ARG(aFaviconURI);
|
||||
|
||||
if (mFaviconsExpirationRunning)
|
||||
// If we are about to expire all favicons, don't bother setting a new one.
|
||||
if (mFaviconsExpirationRunning) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRBool hasData;
|
||||
nsresult rv = SetFaviconUrlForPageInternal(aPageURI, aFaviconURI, &hasData);
|
||||
nsNavHistory* history = nsNavHistory::GetHistoryService();
|
||||
NS_ENSURE_TRUE(history, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
if (history->InPrivateBrowsingMode()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
PRInt64 iconId = -1;
|
||||
PRBool hasData = PR_FALSE;
|
||||
{
|
||||
DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(stmt, mDBGetIconInfo);
|
||||
rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("icon_url"), aFaviconURI);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PRBool hasResult = PR_FALSE;
|
||||
if (NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult) {
|
||||
// We already have an entry for this icon, just get its stats.
|
||||
rv = stmt->GetInt64(0, &iconId);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
PRInt32 dataSize;
|
||||
rv = stmt->GetInt32(1, &dataSize);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (dataSize > 0) {
|
||||
hasData = PR_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mozStorageTransaction transaction(mDBConn, PR_FALSE);
|
||||
|
||||
if (iconId == -1) {
|
||||
// We did not find any entry for this icon, so create a new one.
|
||||
DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(stmt, mDBInsertIcon);
|
||||
rv = stmt->BindNullByName(NS_LITERAL_CSTRING("icon_id"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("icon_url"), aFaviconURI);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = stmt->BindNullByName(NS_LITERAL_CSTRING("data"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = stmt->BindNullByName(NS_LITERAL_CSTRING("mime_type"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = stmt->BindNullByName(NS_LITERAL_CSTRING("expiration"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = stmt->Execute();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
{
|
||||
DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(getInfoStmt, mDBGetIconInfo);
|
||||
rv = URIBinder::Bind(getInfoStmt, NS_LITERAL_CSTRING("icon_url"), aFaviconURI);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
PRBool hasResult;
|
||||
rv = getInfoStmt->ExecuteStep(&hasResult);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ASSERTION(hasResult, "hasResult is false but the call succeeded?");
|
||||
iconId = getInfoStmt->AsInt64(0);
|
||||
}
|
||||
}
|
||||
|
||||
// Now, link our icon entry with the page.
|
||||
PRInt64 pageId;
|
||||
nsCAutoString guid;
|
||||
rv = history->GetOrCreateIdForPage(aPageURI, &pageId, guid);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// send favicon change notifications if the URL has any data
|
||||
if (hasData)
|
||||
SendFaviconNotifications(aPageURI, aFaviconURI);
|
||||
DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(stmt, mDBSetPageFavicon);
|
||||
rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("page_id"), pageId);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("icon_id"), iconId);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = stmt->Execute();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = transaction.Commit();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Send favicon change notifications only if the icon has any data.
|
||||
if (hasData) {
|
||||
SendFaviconNotifications(aPageURI, aFaviconURI, guid);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -284,115 +360,18 @@ nsFaviconService::GetDefaultFavicon(nsIURI** _retval)
|
|||
return mDefaultIcon->Clone(_retval);
|
||||
}
|
||||
|
||||
|
||||
// nsFaviconService::SetFaviconUrlForPageInternal
|
||||
//
|
||||
// This creates a new entry in the favicon table if necessary and tells the
|
||||
// history service to associate the given favicon ID with the given URI. We
|
||||
// don't want to update the history table directly since that may involve
|
||||
// creating a new row in the history table, which should only be done by
|
||||
// history.
|
||||
//
|
||||
// This sets aHasData if there was already icon data for this favicon. Used
|
||||
// to know if we should try reloading.
|
||||
//
|
||||
// Does NOT send out notifications. Caller should send out notifications
|
||||
// if the favicon has data.
|
||||
|
||||
nsresult
|
||||
nsFaviconService::SetFaviconUrlForPageInternal(nsIURI* aPageURI,
|
||||
nsIURI* aFaviconURI,
|
||||
PRBool* aHasData)
|
||||
{
|
||||
nsresult rv;
|
||||
PRInt64 iconId = -1;
|
||||
*aHasData = PR_FALSE;
|
||||
|
||||
nsNavHistory* historyService = nsNavHistory::GetHistoryService();
|
||||
NS_ENSURE_TRUE(historyService, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
if (historyService->InPrivateBrowsingMode())
|
||||
return NS_OK;
|
||||
|
||||
mozStorageTransaction transaction(mDBConn, PR_FALSE);
|
||||
{
|
||||
DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(stmt, mDBGetIconInfo);
|
||||
rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("icon_url"), aFaviconURI);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PRBool hasResult = PR_FALSE;
|
||||
if (NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult) {
|
||||
// We already have an entry for this icon, just get the stats
|
||||
rv = stmt->GetInt64(0, &iconId);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// see if this icon has data already
|
||||
PRInt32 dataSize;
|
||||
rv = stmt->GetInt32(1, &dataSize);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (dataSize > 0)
|
||||
*aHasData = PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (iconId == -1) {
|
||||
// We did not find any entry, so create a new one
|
||||
// not-binded params are automatically nullified by mozStorage
|
||||
DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(stmt, mDBInsertIcon);
|
||||
rv = stmt->BindNullByName(NS_LITERAL_CSTRING("icon_id"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("icon_url"), aFaviconURI);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = stmt->Execute();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
{
|
||||
DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(getInfoStmt, mDBGetIconInfo);
|
||||
rv = URIBinder::Bind(getInfoStmt, NS_LITERAL_CSTRING("icon_url"), aFaviconURI);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PRBool hasResult;
|
||||
rv = getInfoStmt->ExecuteStep(&hasResult);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ASSERTION(hasResult, "hasResult is false but the call succeeded?");
|
||||
iconId = getInfoStmt->AsInt64(0);
|
||||
}
|
||||
}
|
||||
|
||||
// now link our icon entry with the page
|
||||
PRInt64 pageId;
|
||||
rv = historyService->GetUrlIdFor(aPageURI, &pageId, PR_TRUE);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(stmt, mDBSetPageFavicon);
|
||||
rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("page_id"), pageId);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("icon_id"), iconId);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = stmt->Execute();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = transaction.Commit();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
// nsFaviconService::SendFaviconNotifications
|
||||
//
|
||||
// Call to send out favicon changed notifications. Should only be called
|
||||
// when you know there is data loaded for the favicon.
|
||||
|
||||
void
|
||||
nsFaviconService::SendFaviconNotifications(nsIURI* aPageURI,
|
||||
nsIURI* aFaviconURI)
|
||||
nsIURI* aFaviconURI,
|
||||
const nsACString& aGUID)
|
||||
{
|
||||
nsCAutoString faviconSpec;
|
||||
nsNavHistory* historyService = nsNavHistory::GetHistoryService();
|
||||
if (historyService && NS_SUCCEEDED(aFaviconURI->GetSpec(faviconSpec))) {
|
||||
historyService->SendPageChangedNotification(aPageURI,
|
||||
nsINavHistoryObserver::ATTRIBUTE_FAVICON,
|
||||
NS_ConvertUTF8toUTF16(faviconSpec));
|
||||
nsNavHistory* history = nsNavHistory::GetHistoryService();
|
||||
if (history && NS_SUCCEEDED(aFaviconURI->GetSpec(faviconSpec))) {
|
||||
history->SendPageChangedNotification(aPageURI,
|
||||
nsINavHistoryObserver::ATTRIBUTE_FAVICON,
|
||||
NS_ConvertUTF8toUTF16(faviconSpec),
|
||||
aGUID);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -144,7 +144,18 @@ public:
|
|||
*/
|
||||
nsresult FinalizeStatements();
|
||||
|
||||
void SendFaviconNotifications(nsIURI* aPage, nsIURI* aFaviconURI);
|
||||
/**
|
||||
* Call to send out favicon changed notifications. Should only be called
|
||||
* when there is data loaded for the favicon.
|
||||
* @param aPageURI
|
||||
* The URI of the page to notify about.
|
||||
* @param aFaviconURI
|
||||
* The moz-anno:favicon URI of the icon.
|
||||
* @param aGUID
|
||||
* The unique ID associated with the page.
|
||||
*/
|
||||
void SendFaviconNotifications(nsIURI* aPageURI, nsIURI* aFaviconURI,
|
||||
const nsACString& aGUID);
|
||||
|
||||
/**
|
||||
* This cache should be used only for background thread statements.
|
||||
|
|
|
@ -809,7 +809,7 @@ interface nsINavHistoryResult : nsISupports
|
|||
* DANGER! If you are in the middle of a batch transaction, there may be a
|
||||
* database transaction active. You can still access the DB, but be careful.
|
||||
*/
|
||||
[scriptable, uuid(06602bb6-0774-4576-8855-ea930bb85bbe)]
|
||||
[scriptable, uuid(c837f6ba-6ad7-4810-a425-8ce29e05d17e)]
|
||||
interface nsINavHistoryObserver : nsISupports
|
||||
{
|
||||
/**
|
||||
|
@ -870,9 +870,21 @@ interface nsINavHistoryObserver : nsISupports
|
|||
* The URI of the page.
|
||||
* @param aPageTitle
|
||||
* The new title of the page.
|
||||
* @param aGUID
|
||||
* The unique ID associated with the page.
|
||||
*/
|
||||
void onTitleChanged(in nsIURI aURI,
|
||||
in AString aPageTitle);
|
||||
in AString aPageTitle,
|
||||
in ACString aGUID);
|
||||
|
||||
/**
|
||||
* Removed by the user.
|
||||
*/
|
||||
const unsigned short REASON_DELETED = 0;
|
||||
/**
|
||||
* Removed by automatic expiration.
|
||||
*/
|
||||
const unsigned short REASON_EXPIRED = 1;
|
||||
|
||||
/**
|
||||
* This page and all of its visits are about to be deleted. Note: the page
|
||||
|
@ -882,9 +894,12 @@ interface nsINavHistoryObserver : nsISupports
|
|||
* The URI being deleted.
|
||||
* @param aGUID
|
||||
* The unique ID associated with the page.
|
||||
* @param aReason
|
||||
* Indicates the reason for the removal. See REASON_* constants.
|
||||
*/
|
||||
void onBeforeDeleteURI(in nsIURI aURI,
|
||||
in ACString aGUID);
|
||||
in ACString aGUID,
|
||||
in unsigned short aReason);
|
||||
|
||||
/**
|
||||
* This page and all of its visits are being deleted. Note: the page may not
|
||||
|
@ -900,9 +915,12 @@ interface nsINavHistoryObserver : nsISupports
|
|||
* The URI that was deleted.
|
||||
* @param aGUID
|
||||
* The unique ID associated with the page.
|
||||
* @param aReason
|
||||
* Indicates the reason for the removal. see REASON_* constants.
|
||||
*/
|
||||
void onDeleteURI(in nsIURI aURI,
|
||||
in ACString aGUID);
|
||||
in ACString aGUID,
|
||||
in unsigned short aReason);
|
||||
|
||||
/**
|
||||
* Notification that all of history is being deleted.
|
||||
|
@ -910,20 +928,27 @@ interface nsINavHistoryObserver : nsISupports
|
|||
void onClearHistory();
|
||||
|
||||
/**
|
||||
* A page has had some attribute on it changed. Note that for TYPED and
|
||||
* HIDDEN, the page may not necessarily have been added yet.
|
||||
* onPageChanged attribute indicating that favicon has been updated.
|
||||
* aNewValue parameter will be set to the new favicon URI string.
|
||||
*/
|
||||
const unsigned long ATTRIBUTE_FAVICON = 3;
|
||||
|
||||
/**
|
||||
* An attribute of this page changed.
|
||||
*
|
||||
* @param aURI
|
||||
* The URI of the page on which an attribute changed.
|
||||
* @param aWhat
|
||||
* The attribute whose value changed.
|
||||
* @param aValue
|
||||
* The attribute's new value.
|
||||
* The URI of the page on which an attribute changed.
|
||||
* @param aChangedAttribute
|
||||
* The attribute whose value changed. See ATTRIBUTE_* constants.
|
||||
* @param aNewValue
|
||||
* The attribute's new value.
|
||||
* @param aGUID
|
||||
* The unique ID associated with the page.
|
||||
*/
|
||||
const unsigned long ATTRIBUTE_FAVICON = 3; // favicon updated, aString = favicon annotation URI
|
||||
void onPageChanged(in nsIURI aURI,
|
||||
in unsigned long aWhat,
|
||||
in AString aValue);
|
||||
in unsigned long aChangedAttribute,
|
||||
in AString aNewValue,
|
||||
in ACString aGUID);
|
||||
|
||||
/**
|
||||
* Called when some visits of an history entry are expired.
|
||||
|
@ -940,10 +965,13 @@ interface nsINavHistoryObserver : nsISupports
|
|||
* is expired, you will only get an onDeleteURI notification. If a
|
||||
* page entry is removed, then you can be sure that we don't have
|
||||
* anymore visits for it.
|
||||
* @param aReason
|
||||
* Indicates the reason for the removal. see REASON_* constants.
|
||||
*/
|
||||
void onDeleteVisits(in nsIURI aURI,
|
||||
in PRTime aVisitTime,
|
||||
in ACString aGUID);
|
||||
in ACString aGUID,
|
||||
in unsigned short aReason);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -967,11 +967,11 @@ nsNavBookmarks::InsertBookmark(PRInt64 aFolder,
|
|||
|
||||
mozStorageTransaction transaction(mDBConn, PR_FALSE);
|
||||
|
||||
PRInt64 placeId;
|
||||
nsNavHistory* history = nsNavHistory::GetHistoryService();
|
||||
NS_ENSURE_TRUE(history, NS_ERROR_OUT_OF_MEMORY);
|
||||
// If the URI is unknown, this will create a new entry.
|
||||
nsresult rv = history->GetUrlIdFor(aURI, &placeId, PR_TRUE);
|
||||
PRInt64 placeId;
|
||||
nsCAutoString placeGuid;
|
||||
nsresult rv = history->GetOrCreateIdForPage(aURI, &placeId, placeGuid);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Get the correct index for insertion. This also ensures the parent exists.
|
||||
|
@ -2424,7 +2424,8 @@ nsNavBookmarks::GetBookmarkedURIFor(nsIURI* aURI, nsIURI** _retval)
|
|||
nsNavHistory* history = nsNavHistory::GetHistoryService();
|
||||
NS_ENSURE_TRUE(history, NS_ERROR_OUT_OF_MEMORY);
|
||||
PRInt64 placeId;
|
||||
nsresult rv = history->GetUrlIdFor(aURI, &placeId, PR_FALSE);
|
||||
nsCAutoString placeGuid;
|
||||
nsresult rv = history->GetIdForPage(aURI, &placeId, placeGuid);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (!placeId) {
|
||||
// This URI is unknown, just return null.
|
||||
|
@ -2466,11 +2467,11 @@ nsNavBookmarks::ChangeBookmarkURI(PRInt64 aBookmarkId, nsIURI* aNewURI)
|
|||
|
||||
mozStorageTransaction transaction(mDBConn, PR_FALSE);
|
||||
|
||||
// This will create a new page if one doesn't exist.
|
||||
PRInt64 newPlaceId;
|
||||
nsNavHistory* history = nsNavHistory::GetHistoryService();
|
||||
NS_ENSURE_TRUE(history, NS_ERROR_OUT_OF_MEMORY);
|
||||
rv = history->GetUrlIdFor(aNewURI, &newPlaceId, PR_TRUE);
|
||||
PRInt64 newPlaceId;
|
||||
nsCAutoString newPlaceGuid;
|
||||
rv = history->GetOrCreateIdForPage(aNewURI, &newPlaceId, newPlaceGuid);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (!newPlaceId)
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
@ -3064,20 +3065,25 @@ nsNavBookmarks::OnVisit(nsIURI* aURI, PRInt64 aVisitId, PRTime aTime,
|
|||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNavBookmarks::OnBeforeDeleteURI(nsIURI* aURI, const nsACString& aGUID)
|
||||
nsNavBookmarks::OnBeforeDeleteURI(nsIURI* aURI,
|
||||
const nsACString& aGUID,
|
||||
PRUint16 aReason)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNavBookmarks::OnDeleteURI(nsIURI* aURI, const nsACString& aGUID)
|
||||
nsNavBookmarks::OnDeleteURI(nsIURI* aURI,
|
||||
const nsACString& aGUID,
|
||||
PRUint16 aReason)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
nsNavHistory* history = nsNavHistory::GetHistoryService();
|
||||
PRInt64 placeId;
|
||||
nsCAutoString placeGuid;
|
||||
NS_ABORT_IF_FALSE(
|
||||
history && NS_SUCCEEDED(history->GetUrlIdFor(aURI, &placeId, PR_FALSE)) && !placeId,
|
||||
history && NS_SUCCEEDED(history->GetIdForPage(aURI, &placeId, placeGuid)) && !placeId,
|
||||
"OnDeleteURI was notified for a page that still exists?"
|
||||
);
|
||||
#endif
|
||||
|
@ -3094,7 +3100,9 @@ nsNavBookmarks::OnClearHistory()
|
|||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNavBookmarks::OnTitleChanged(nsIURI* aURI, const nsAString& aPageTitle)
|
||||
nsNavBookmarks::OnTitleChanged(nsIURI* aURI,
|
||||
const nsAString& aPageTitle,
|
||||
const nsACString& aGUID)
|
||||
{
|
||||
// NOOP. We don't consume page titles from moz_places anymore.
|
||||
// Title-change notifications are sent from SetItemTitle.
|
||||
|
@ -3103,17 +3111,19 @@ nsNavBookmarks::OnTitleChanged(nsIURI* aURI, const nsAString& aPageTitle)
|
|||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNavBookmarks::OnPageChanged(nsIURI* aURI, PRUint32 aWhat,
|
||||
const nsAString& aValue)
|
||||
nsNavBookmarks::OnPageChanged(nsIURI* aURI,
|
||||
PRUint32 aChangedAttribute,
|
||||
const nsAString& aNewValue,
|
||||
const nsACString& aGUID)
|
||||
{
|
||||
nsresult rv;
|
||||
if (aWhat == nsINavHistoryObserver::ATTRIBUTE_FAVICON) {
|
||||
if (aChangedAttribute == nsINavHistoryObserver::ATTRIBUTE_FAVICON) {
|
||||
ItemChangeData changeData;
|
||||
rv = aURI->GetSpec(changeData.bookmark.url);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
changeData.property = NS_LITERAL_CSTRING("favicon");
|
||||
changeData.isAnnotation = PR_FALSE;
|
||||
changeData.newValue = NS_ConvertUTF16toUTF8(aValue);
|
||||
changeData.newValue = NS_ConvertUTF16toUTF8(aNewValue);
|
||||
changeData.bookmark.lastModified = 0;
|
||||
changeData.bookmark.type = TYPE_BOOKMARK;
|
||||
|
||||
|
@ -3150,7 +3160,8 @@ nsNavBookmarks::OnPageChanged(nsIURI* aURI, PRUint32 aWhat,
|
|||
|
||||
NS_IMETHODIMP
|
||||
nsNavBookmarks::OnDeleteVisits(nsIURI* aURI, PRTime aVisitTime,
|
||||
const nsACString& aGUID)
|
||||
const nsACString& aGUID,
|
||||
PRUint16 aReason)
|
||||
{
|
||||
// Notify "cleartime" only if all visits to the page have been removed.
|
||||
if (!aVisitTime) {
|
||||
|
|
|
@ -1691,48 +1691,50 @@ nsNavHistory::MigrateV11Up(mozIStorageConnection *aDBConn)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
// nsNavHistory::GetUrlIdFor
|
||||
//
|
||||
// Called by the bookmarks and annotation services, this function returns the
|
||||
// ID of the row for the given URL, optionally creating one if it doesn't
|
||||
// exist. A newly created entry will have no visits.
|
||||
//
|
||||
// If aAutoCreate is false and the item doesn't exist, the entry ID will be
|
||||
// zero.
|
||||
//
|
||||
// This DOES NOT check for bad URLs other than that they're nonempty.
|
||||
|
||||
nsresult
|
||||
nsNavHistory::GetUrlIdFor(nsIURI* aURI, PRInt64* aEntryID,
|
||||
PRBool aAutoCreate)
|
||||
nsNavHistory::GetIdForPage(nsIURI* aURI,
|
||||
PRInt64* _pageId,
|
||||
nsCString& _GUID)
|
||||
{
|
||||
*aEntryID = 0;
|
||||
{
|
||||
DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(stmt, mDBGetURLPageInfo);
|
||||
nsresult rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"), aURI);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
*_pageId = 0;
|
||||
|
||||
PRBool hasEntry = PR_FALSE;
|
||||
rv = stmt->ExecuteStep(&hasEntry);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(stmt, mDBGetURLPageInfo);
|
||||
nsresult rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"), aURI);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (hasEntry)
|
||||
return stmt->GetInt64(kGetInfoIndex_PageID, aEntryID);
|
||||
PRBool hasEntry = PR_FALSE;
|
||||
rv = stmt->ExecuteStep(&hasEntry);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (hasEntry) {
|
||||
rv = stmt->GetInt64(kGetInfoIndex_PageID, _pageId);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = stmt->GetUTF8String(5, _GUID);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
if (aAutoCreate) {
|
||||
// create a new hidden, untyped, unvisited entry
|
||||
nsAutoString voidString;
|
||||
voidString.SetIsVoid(PR_TRUE);
|
||||
nsCAutoString guid;
|
||||
return InternalAddNewPage(aURI, voidString, PR_TRUE, PR_FALSE, 0, PR_TRUE, aEntryID, guid);
|
||||
}
|
||||
|
||||
// Doesn't exist: don't do anything, entry ID was already set to 0 above
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsNavHistory::GetOrCreateIdForPage(nsIURI* aURI,
|
||||
PRInt64* _pageId,
|
||||
nsCString& _GUID)
|
||||
{
|
||||
nsresult rv = GetIdForPage(aURI, _pageId, _GUID);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (*_pageId == 0) {
|
||||
// Create a new hidden, untyped and unvisited entry.
|
||||
nsAutoString voidString;
|
||||
voidString.SetIsVoid(PR_TRUE);
|
||||
rv = InternalAddNewPage(aURI, voidString, PR_TRUE, PR_FALSE, 0, PR_TRUE,
|
||||
_pageId, _GUID);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsNavHistory::InternalAddNewPage
|
||||
//
|
||||
|
@ -2043,10 +2045,13 @@ nsNavHistory::NotifyOnVisit(nsIURI* aURI,
|
|||
}
|
||||
|
||||
void
|
||||
nsNavHistory::NotifyTitleChange(nsIURI* aURI, const nsString& aTitle)
|
||||
nsNavHistory::NotifyTitleChange(nsIURI* aURI,
|
||||
const nsString& aTitle,
|
||||
const nsACString& aGUID)
|
||||
{
|
||||
MOZ_ASSERT(!aGUID.IsEmpty());
|
||||
NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
|
||||
nsINavHistoryObserver, OnTitleChanged(aURI, aTitle));
|
||||
nsINavHistoryObserver, OnTitleChanged(aURI, aTitle, aGUID));
|
||||
}
|
||||
|
||||
PRInt32
|
||||
|
@ -4216,13 +4221,15 @@ nsNavHistory::CleanupPlacesOnVisitsDelete(const nsCString& aPlaceIdsQueryString)
|
|||
GUIDs.AppendElement(guid);
|
||||
// Notify we are about to remove this uri.
|
||||
NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
|
||||
nsINavHistoryObserver, OnBeforeDeleteURI(uri, guid));
|
||||
nsINavHistoryObserver,
|
||||
OnBeforeDeleteURI(uri, guid, nsINavHistoryObserver::REASON_DELETED));
|
||||
}
|
||||
else {
|
||||
// Notify that we will delete all visits for this page, but not the page
|
||||
// itself, since it's bookmarked or a place: query.
|
||||
NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
|
||||
nsINavHistoryObserver, OnDeleteVisits(uri, 0, guid));
|
||||
nsINavHistoryObserver,
|
||||
OnDeleteVisits(uri, 0, guid, nsINavHistoryObserver::REASON_DELETED));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4245,7 +4252,8 @@ nsNavHistory::CleanupPlacesOnVisitsDelete(const nsCString& aPlaceIdsQueryString)
|
|||
// Finally notify about the removed URIs.
|
||||
for (PRInt32 i = 0; i < URIs.Count(); ++i) {
|
||||
NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
|
||||
nsINavHistoryObserver, OnDeleteURI(URIs[i], GUIDs[i]));
|
||||
nsINavHistoryObserver,
|
||||
OnDeleteURI(URIs[i], GUIDs[i], nsINavHistoryObserver::REASON_DELETED));
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -4271,7 +4279,8 @@ nsNavHistory::RemovePages(nsIURI **aURIs, PRUint32 aLength, PRBool aDoBatchNotif
|
|||
nsCString deletePlaceIdsQueryString;
|
||||
for (PRUint32 i = 0; i < aLength; i++) {
|
||||
PRInt64 placeId;
|
||||
rv = GetUrlIdFor(aURIs[i], &placeId, PR_FALSE);
|
||||
nsCAutoString guid;
|
||||
rv = GetIdForPage(aURIs[i], &placeId, guid);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (placeId != 0) {
|
||||
if (!deletePlaceIdsQueryString.IsEmpty())
|
||||
|
@ -5368,7 +5377,8 @@ nsNavHistory::AsyncExecuteLegacyQueries(nsINavHistoryQuery** aQueries,
|
|||
|
||||
NS_IMETHODIMP
|
||||
nsNavHistory::NotifyOnPageExpired(nsIURI *aURI, PRTime aVisitTime,
|
||||
PRBool aWholeEntry, const nsACString& aGUID)
|
||||
PRBool aWholeEntry, const nsACString& aGUID,
|
||||
PRUint16 aReason)
|
||||
{
|
||||
// Invalidate the cached value for whether there's history or not.
|
||||
mHasHistoryEntries = -1;
|
||||
|
@ -5377,12 +5387,13 @@ nsNavHistory::NotifyOnPageExpired(nsIURI *aURI, PRTime aVisitTime,
|
|||
if (aWholeEntry) {
|
||||
// Notify our observers that the page has been removed.
|
||||
NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
|
||||
nsINavHistoryObserver, OnDeleteURI(aURI, aGUID));
|
||||
nsINavHistoryObserver, OnDeleteURI(aURI, aGUID, aReason));
|
||||
}
|
||||
else {
|
||||
// Notify our observers that some visits for the page have been removed.
|
||||
NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
|
||||
nsINavHistoryObserver, OnDeleteVisits(aURI, aVisitTime, aGUID));
|
||||
nsINavHistoryObserver,
|
||||
OnDeleteVisits(aURI, aVisitTime, aGUID, aReason));
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -6665,11 +6676,15 @@ nsNavHistory::URIToResultNode(nsIURI* aURI,
|
|||
}
|
||||
|
||||
void
|
||||
nsNavHistory::SendPageChangedNotification(nsIURI* aURI, PRUint32 aWhat,
|
||||
const nsAString& aValue)
|
||||
nsNavHistory::SendPageChangedNotification(nsIURI* aURI,
|
||||
PRUint32 aChangedAttribute,
|
||||
const nsAString& aNewValue,
|
||||
const nsACString& aGUID)
|
||||
{
|
||||
MOZ_ASSERT(!aGUID.IsEmpty());
|
||||
NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
|
||||
nsINavHistoryObserver, OnPageChanged(aURI, aWhat, aValue));
|
||||
nsINavHistoryObserver,
|
||||
OnPageChanged(aURI, aChangedAttribute, aNewValue, aGUID));
|
||||
}
|
||||
|
||||
// nsNavHistory::TitleForDomain
|
||||
|
@ -6781,9 +6796,9 @@ nsNavHistory::SetPageTitleInternal(nsIURI* aURI, const nsAString& aTitle)
|
|||
{
|
||||
nsresult rv;
|
||||
|
||||
// first, make sure the page exists, and fetch the old title (we need the one
|
||||
// that isn't changing to send notifications)
|
||||
// Make sure the page exists by fetching its GUID and the old title.
|
||||
nsAutoString title;
|
||||
nsCAutoString guid;
|
||||
{
|
||||
DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(stmt, mDBGetURLPageInfo);
|
||||
rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"), aURI);
|
||||
|
@ -6802,6 +6817,8 @@ nsNavHistory::SetPageTitleInternal(nsIURI* aURI, const nsAString& aTitle)
|
|||
|
||||
rv = stmt->GetString(kGetInfoIndex_Title, title);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = stmt->GetUTF8String(5, guid);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
// It is actually common to set the title to be the same thing it used to
|
||||
|
@ -6825,8 +6842,9 @@ nsNavHistory::SetPageTitleInternal(nsIURI* aURI, const nsAString& aTitle)
|
|||
rv = stmt->Execute();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
MOZ_ASSERT(!guid.IsEmpty());
|
||||
NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
|
||||
nsINavHistoryObserver, OnTitleChanged(aURI, aTitle));
|
||||
nsINavHistoryObserver, OnTitleChanged(aURI, aTitle, guid));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -236,11 +236,35 @@ public:
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the database ID for the given URI, or 0 if not found and autoCreate
|
||||
* is false.
|
||||
* Fetches the database id and the GUID associated to the given URI.
|
||||
*
|
||||
* @param aURI
|
||||
* The page to look for.
|
||||
* @param _pageId
|
||||
* Will be set to the database id associated with the page.
|
||||
* If the page doesn't exist, this will be zero.
|
||||
* @param _GUID
|
||||
* Will be set to the unique id associated with the page.
|
||||
* If the page doesn't exist, this will be empty.
|
||||
* @note This DOES NOT check for bad URLs other than that they're nonempty.
|
||||
*/
|
||||
nsresult GetUrlIdFor(nsIURI* aURI, PRInt64* aEntryID,
|
||||
PRBool aAutoCreate);
|
||||
nsresult GetIdForPage(nsIURI* aURI,
|
||||
PRInt64* _pageId, nsCString& _GUID);
|
||||
|
||||
/**
|
||||
* Fetches the database id and the GUID associated to the given URI, creating
|
||||
* a new database entry if one doesn't exist yet.
|
||||
*
|
||||
* @param aURI
|
||||
* The page to look for or create.
|
||||
* @param _pageId
|
||||
* Will be set to the database id associated with the page.
|
||||
* @param _GUID
|
||||
* Will be set to the unique id associated with the page.
|
||||
* @note This DOES NOT check for bad URLs other than that they're nonempty.
|
||||
*/
|
||||
nsresult GetOrCreateIdForPage(nsIURI* aURI,
|
||||
PRInt64* _pageId, nsCString& _GUID);
|
||||
|
||||
nsresult UpdateFrecency(PRInt64 aPlaceId);
|
||||
|
||||
|
@ -336,8 +360,9 @@ public:
|
|||
|
||||
// used by other places components to send history notifications (for example,
|
||||
// when the favicon has changed)
|
||||
void SendPageChangedNotification(nsIURI* aURI, PRUint32 aWhat,
|
||||
const nsAString& aValue);
|
||||
void SendPageChangedNotification(nsIURI* aURI, PRUint32 aChangedAttribute,
|
||||
const nsAString& aValue,
|
||||
const nsACString& aGUID);
|
||||
|
||||
/**
|
||||
* Returns current number of days stored in history.
|
||||
|
@ -602,7 +627,8 @@ public:
|
|||
* Fires onTitleChanged event to nsINavHistoryService observers
|
||||
*/
|
||||
void NotifyTitleChange(nsIURI* aURI,
|
||||
const nsString& title);
|
||||
const nsString& title,
|
||||
const nsACString& aGUID);
|
||||
|
||||
bool isBatching() {
|
||||
return mBatchLevel > 0;
|
||||
|
|
|
@ -2995,7 +2995,8 @@ nsNavHistoryQueryResultNode::OnVisit(nsIURI* aURI, PRInt64 aVisitId,
|
|||
*/
|
||||
NS_IMETHODIMP
|
||||
nsNavHistoryQueryResultNode::OnTitleChanged(nsIURI* aURI,
|
||||
const nsAString& aPageTitle)
|
||||
const nsAString& aPageTitle,
|
||||
const nsACString& aGUID)
|
||||
{
|
||||
if (!mExpanded) {
|
||||
// When we are not expanded, we don't update, just invalidate and unhook.
|
||||
|
@ -3062,8 +3063,9 @@ nsNavHistoryQueryResultNode::OnTitleChanged(nsIURI* aURI,
|
|||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNavHistoryQueryResultNode::OnBeforeDeleteURI(nsIURI *aURI,
|
||||
const nsACString& aGUID)
|
||||
nsNavHistoryQueryResultNode::OnBeforeDeleteURI(nsIURI* aURI,
|
||||
const nsACString& aGUID,
|
||||
PRUint16 aReason)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -3073,8 +3075,9 @@ nsNavHistoryQueryResultNode::OnBeforeDeleteURI(nsIURI *aURI,
|
|||
* the given URI.
|
||||
*/
|
||||
NS_IMETHODIMP
|
||||
nsNavHistoryQueryResultNode::OnDeleteURI(nsIURI *aURI,
|
||||
const nsACString& aGUID)
|
||||
nsNavHistoryQueryResultNode::OnDeleteURI(nsIURI* aURI,
|
||||
const nsACString& aGUID,
|
||||
PRUint16 aReason)
|
||||
{
|
||||
if (IsContainersQuery()) {
|
||||
// Incremental updates of query returning queries are pretty much
|
||||
|
@ -3141,22 +3144,23 @@ static nsresult setFaviconCallback(
|
|||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNavHistoryQueryResultNode::OnPageChanged(nsIURI *aURI, PRUint32 aWhat,
|
||||
const nsAString &aValue)
|
||||
nsNavHistoryQueryResultNode::OnPageChanged(nsIURI* aURI,
|
||||
PRUint32 aChangedAttribute,
|
||||
const nsAString& aNewValue,
|
||||
const nsACString& aGUID)
|
||||
{
|
||||
nsCAutoString spec;
|
||||
nsresult rv = aURI->GetSpec(spec);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
switch (aWhat) {
|
||||
switch (aChangedAttribute) {
|
||||
case nsINavHistoryObserver::ATTRIBUTE_FAVICON: {
|
||||
NS_ConvertUTF16toUTF8 newFavicon(aValue);
|
||||
PRBool onlyOneEntry = (mOptions->ResultType() ==
|
||||
nsINavHistoryQueryOptions::RESULTS_AS_URI ||
|
||||
mOptions->ResultType() ==
|
||||
nsINavHistoryQueryOptions::RESULTS_AS_TAG_CONTENTS);
|
||||
rv = UpdateURIs(PR_TRUE, onlyOneEntry, PR_FALSE, spec, setFaviconCallback,
|
||||
&newFavicon);
|
||||
&NS_ConvertUTF16toUTF8(aNewValue));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
break;
|
||||
}
|
||||
|
@ -3168,8 +3172,10 @@ nsNavHistoryQueryResultNode::OnPageChanged(nsIURI *aURI, PRUint32 aWhat,
|
|||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNavHistoryQueryResultNode::OnDeleteVisits(nsIURI* aURI, PRTime aVisitTime,
|
||||
const nsACString& aGUID)
|
||||
nsNavHistoryQueryResultNode::OnDeleteVisits(nsIURI* aURI,
|
||||
PRTime aVisitTime,
|
||||
const nsACString& aGUID,
|
||||
PRUint16 aReason)
|
||||
{
|
||||
NS_PRECONDITION(mOptions->QueryType() == nsINavHistoryQueryOptions::QUERY_TYPE_HISTORY,
|
||||
"Bookmarks queries should not get a OnDeleteVisits notification");
|
||||
|
@ -3177,7 +3183,7 @@ nsNavHistoryQueryResultNode::OnDeleteVisits(nsIURI* aURI, PRTime aVisitTime,
|
|||
// All visits for this uri have been removed, but the uri won't be removed
|
||||
// from the databse, most likely because it's a bookmark. For a history
|
||||
// query this is equivalent to a onDeleteURI notification.
|
||||
nsresult rv = OnDeleteURI(aURI, aGUID);
|
||||
nsresult rv = OnDeleteURI(aURI, aGUID, aReason);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
|
@ -5128,24 +5134,30 @@ nsNavHistoryResult::OnVisit(nsIURI* aURI, PRInt64 aVisitId, PRTime aTime,
|
|||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNavHistoryResult::OnTitleChanged(nsIURI* aURI, const nsAString& aPageTitle)
|
||||
nsNavHistoryResult::OnTitleChanged(nsIURI* aURI,
|
||||
const nsAString& aPageTitle,
|
||||
const nsACString& aGUID)
|
||||
{
|
||||
ENUMERATE_HISTORY_OBSERVERS(OnTitleChanged(aURI, aPageTitle));
|
||||
ENUMERATE_HISTORY_OBSERVERS(OnTitleChanged(aURI, aPageTitle, aGUID));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNavHistoryResult::OnBeforeDeleteURI(nsIURI *aURI, const nsACString& aGUID)
|
||||
nsNavHistoryResult::OnBeforeDeleteURI(nsIURI *aURI,
|
||||
const nsACString& aGUID,
|
||||
PRUint16 aReason)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNavHistoryResult::OnDeleteURI(nsIURI *aURI, const nsACString& aGUID)
|
||||
nsNavHistoryResult::OnDeleteURI(nsIURI *aURI,
|
||||
const nsACString& aGUID,
|
||||
PRUint16 aReason)
|
||||
{
|
||||
ENUMERATE_HISTORY_OBSERVERS(OnDeleteURI(aURI, aGUID));
|
||||
ENUMERATE_HISTORY_OBSERVERS(OnDeleteURI(aURI, aGUID, aReason));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -5159,10 +5171,12 @@ nsNavHistoryResult::OnClearHistory()
|
|||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNavHistoryResult::OnPageChanged(nsIURI *aURI,
|
||||
PRUint32 aWhat, const nsAString &aValue)
|
||||
nsNavHistoryResult::OnPageChanged(nsIURI* aURI,
|
||||
PRUint32 aChangedAttribute,
|
||||
const nsAString& aValue,
|
||||
const nsACString& aGUID)
|
||||
{
|
||||
ENUMERATE_HISTORY_OBSERVERS(OnPageChanged(aURI, aWhat, aValue));
|
||||
ENUMERATE_HISTORY_OBSERVERS(OnPageChanged(aURI, aChangedAttribute, aValue, aGUID));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -5171,9 +5185,11 @@ nsNavHistoryResult::OnPageChanged(nsIURI *aURI,
|
|||
* Don't do anything when visits expire.
|
||||
*/
|
||||
NS_IMETHODIMP
|
||||
nsNavHistoryResult::OnDeleteVisits(nsIURI* aURI, PRTime aVisitTime,
|
||||
const nsACString& aGUID)
|
||||
nsNavHistoryResult::OnDeleteVisits(nsIURI* aURI,
|
||||
PRTime aVisitTime,
|
||||
const nsACString& aGUID,
|
||||
PRUint16 aReason)
|
||||
{
|
||||
ENUMERATE_HISTORY_OBSERVERS(OnDeleteVisits(aURI, aVisitTime, aGUID));
|
||||
ENUMERATE_HISTORY_OBSERVERS(OnDeleteVisits(aURI, aVisitTime, aGUID, aReason));
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -100,14 +100,18 @@ private:
|
|||
PRInt64 aSessionId, PRInt64 aReferringId, \
|
||||
PRUint32 aTransitionType, const nsACString& aGUID, \
|
||||
PRUint32* aAdded); \
|
||||
NS_IMETHOD OnTitleChanged(nsIURI* aURI, const nsAString& aPageTitle); \
|
||||
NS_IMETHOD OnBeforeDeleteURI(nsIURI *aURI, const nsACString& aGUID); \
|
||||
NS_IMETHOD OnDeleteURI(nsIURI *aURI, const nsACString& aGUID); \
|
||||
NS_IMETHOD OnTitleChanged(nsIURI* aURI, const nsAString& aPageTitle, \
|
||||
const nsACString& aGUID); \
|
||||
NS_IMETHOD OnBeforeDeleteURI(nsIURI *aURI, const nsACString& aGUID, \
|
||||
PRUint16 aReason); \
|
||||
NS_IMETHOD OnDeleteURI(nsIURI *aURI, const nsACString& aGUID, \
|
||||
PRUint16 aReason); \
|
||||
NS_IMETHOD OnClearHistory(); \
|
||||
NS_IMETHOD OnPageChanged(nsIURI *aURI, PRUint32 aWhat, \
|
||||
const nsAString &aValue); \
|
||||
NS_IMETHOD OnPageChanged(nsIURI *aURI, PRUint32 aChangedAttribute, \
|
||||
const nsAString &aNewValue, \
|
||||
const nsACString &aGUID); \
|
||||
NS_IMETHOD OnDeleteVisits(nsIURI* aURI, PRTime aVisitTime, \
|
||||
const nsACString& aGUID);
|
||||
const nsACString& aGUID, PRUint16 aReason);
|
||||
|
||||
// nsNavHistoryResult
|
||||
//
|
||||
|
|
|
@ -49,7 +49,7 @@ interface nsIURI;
|
|||
*
|
||||
* @note See also: nsINavHistoryObserver
|
||||
*/
|
||||
[scriptable, uuid(eb2ec8a9-c764-4abe-b076-b122d7aa8a3b)]
|
||||
[scriptable, uuid(3b0953cd-f483-4908-8d91-282b6bda0453)]
|
||||
interface nsPIPlacesHistoryListenersNotifier : nsISupports
|
||||
{
|
||||
/**
|
||||
|
@ -64,9 +64,13 @@ interface nsPIPlacesHistoryListenersNotifier : nsISupports
|
|||
* Indicates if this is the last visit for this URI.
|
||||
* @param aGUID
|
||||
* The unique ID associated with the page.
|
||||
* @param aReason
|
||||
* Indicates the reason for the removal.
|
||||
* See nsINavHistoryObserver::REASON_* constants.
|
||||
*/
|
||||
void notifyOnPageExpired(in nsIURI aURI,
|
||||
in PRTime aVisitTime,
|
||||
in boolean aWholeEntry,
|
||||
in ACString aGUID);
|
||||
in ACString aGUID,
|
||||
in unsigned short aReason);
|
||||
};
|
||||
|
|
|
@ -658,7 +658,8 @@ nsPlacesExpiration.prototype = {
|
|||
let visitDate = row.getResultByName("visit_date");
|
||||
let wholeEntry = row.getResultByName("whole_entry");
|
||||
// Dispatch expiration notifications to history.
|
||||
this._hsn.notifyOnPageExpired(uri, visitDate, wholeEntry, guid);
|
||||
this._hsn.notifyOnPageExpired(uri, visitDate, wholeEntry, guid,
|
||||
Ci.nsINavHistoryObserver.REASON_EXPIRED);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -55,9 +55,9 @@ function test() {
|
|||
// Create and add history observer.
|
||||
var historyObserver = {
|
||||
visitCount: Array(),
|
||||
onBeginUpdateBatch: function() {},
|
||||
onEndUpdateBatch: function() {},
|
||||
onVisit: function(aURI, aVisitID, aTime, aSessionID, aReferringID,
|
||||
onBeginUpdateBatch: function () {},
|
||||
onEndUpdateBatch: function () {},
|
||||
onVisit: function (aURI, aVisitID, aTime, aSessionID, aReferringID,
|
||||
aTransitionType) {
|
||||
info("Received onVisit: " + aURI.spec);
|
||||
if (aURI.spec in this.visitCount)
|
||||
|
@ -65,12 +65,12 @@ function test() {
|
|||
else
|
||||
this.visitCount[aURI.spec] = 1;
|
||||
},
|
||||
onTitleChanged: function(aURI, aPageTitle) {},
|
||||
onBeforeDeleteURI: function(aURI) {},
|
||||
onDeleteURI: function(aURI) {},
|
||||
onClearHistory: function() {},
|
||||
onPageChanged: function(aURI, aWhat, aValue) {},
|
||||
onDeleteVisits: function() {},
|
||||
onTitleChanged: function () {},
|
||||
onBeforeDeleteURI: function () {},
|
||||
onDeleteURI: function () {},
|
||||
onClearHistory: function () {},
|
||||
onPageChanged: function () {},
|
||||
onDeleteVisits: function () {},
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsINavHistoryObserver])
|
||||
};
|
||||
hs.addObserver(historyObserver, false);
|
||||
|
|
|
@ -79,8 +79,8 @@ function test()
|
|||
onVisit: function(aURI, aVisitID, aTime, aSessionID, aReferringID,
|
||||
aTransitionType) {
|
||||
},
|
||||
onTitleChanged: function(aURI, aPageTitle) {
|
||||
this.data.push({ uri: aURI, title: aPageTitle });
|
||||
onTitleChanged: function(aURI, aPageTitle, aGUID) {
|
||||
this.data.push({ uri: aURI, title: aPageTitle, guid: aGUID });
|
||||
|
||||
// We only expect one title change.
|
||||
//
|
||||
|
@ -107,6 +107,7 @@ function test()
|
|||
function confirmResults(data) {
|
||||
is(data[0].uri.spec, "http://example.com/tests/toolkit/components/places/tests/browser/title2.html");
|
||||
is(data[0].title, "Some title");
|
||||
is(data[0].guid, getColumn("moz_places", "guid", "url", data[0].uri.spec));
|
||||
|
||||
data.forEach(function(item) {
|
||||
var title = getColumn("moz_places", "title", "url", data[0].uri.spec);
|
||||
|
|
|
@ -123,10 +123,12 @@ function run_next_test() {
|
|||
onVisit: function() {},
|
||||
onTitleChanged: function() {},
|
||||
onBeforeDeleteURI: function() {},
|
||||
onDeleteURI: function(aURI) {
|
||||
onDeleteURI: function(aURI, aGUID, aReason) {
|
||||
gCurrentTest.receivedNotifications++;
|
||||
// Check this uri was not bookmarked.
|
||||
do_check_eq(gCurrentTest.bookmarks.indexOf(aURI.spec), -1);
|
||||
do_check_valid_places_guid(aGUID);
|
||||
do_check_eq(aReason, Ci.nsINavHistoryObserver.REASON_EXPIRED);
|
||||
},
|
||||
onPageChanged: function() {},
|
||||
onDeleteVisits: function(aURI, aTime) { },
|
||||
|
|
|
@ -142,13 +142,17 @@ function run_next_test() {
|
|||
onVisit: function() {},
|
||||
onTitleChanged: function() {},
|
||||
onBeforeDeleteURI: function() {},
|
||||
onDeleteURI: function(aURI) {
|
||||
onDeleteURI: function(aURI, aGUID, aReason) {
|
||||
// Check this uri was not bookmarked.
|
||||
do_check_eq(gCurrentTest.bookmarks.indexOf(aURI.spec), -1);
|
||||
do_check_valid_places_guid(aGUID);
|
||||
do_check_eq(aReason, Ci.nsINavHistoryObserver.REASON_EXPIRED);
|
||||
},
|
||||
onPageChanged: function() {},
|
||||
onDeleteVisits: function(aURI, aTime) {
|
||||
onDeleteVisits: function(aURI, aTime, aGUID, aReason) {
|
||||
gCurrentTest.receivedNotifications++;
|
||||
do_check_guid_for_uri(aURI, aGUID);
|
||||
do_check_eq(aReason, Ci.nsINavHistoryObserver.REASON_EXPIRED);
|
||||
},
|
||||
};
|
||||
hs.addObserver(historyObserver, false);
|
||||
|
|
|
@ -123,9 +123,7 @@
|
|||
catch (exc) {}
|
||||
|
||||
try {
|
||||
var str = Cc["@mozilla.org/supports-string;1"].
|
||||
createInstance(Ci.nsISupportsString);
|
||||
str.data = "foo";
|
||||
var str = PlacesUtils.toISupportsString("foo");
|
||||
query = PlacesUtils.history.getNewQuery();
|
||||
query.tags = str;
|
||||
do_throw("Passing nsISupportsString to SetTags should fail");
|
||||
|
|
|
@ -48,19 +48,19 @@ function DummyObserver() {
|
|||
|
||||
DummyObserver.prototype = {
|
||||
// history observer
|
||||
onBeginUpdateBatch: function() {},
|
||||
onEndUpdateBatch: function() {},
|
||||
onVisit: function(aURI, aVisitID, aTime, aSessionID, aReferringID, aTransitionType) {
|
||||
onBeginUpdateBatch: function () {},
|
||||
onEndUpdateBatch: function () {},
|
||||
onVisit: function (aURI, aVisitID, aTime, aSessionID, aReferringID, aTransitionType) {
|
||||
let os = Cc["@mozilla.org/observer-service;1"].
|
||||
getService(Ci.nsIObserverService);
|
||||
os.notifyObservers(null, "dummy-observer-visited", null);
|
||||
},
|
||||
onTitleChanged: function(aURI, aPageTitle) {},
|
||||
onBeforeDeleteURI: function(aURI) {},
|
||||
onDeleteURI: function(aURI) {},
|
||||
onClearHistory: function() {},
|
||||
onPageChanged: function(aURI, aWhat, aValue) {},
|
||||
onDeleteVisits: function(aURI, aVisitTime) {},
|
||||
onTitleChanged: function () {},
|
||||
onBeforeDeleteURI: function () {},
|
||||
onDeleteURI: function () {},
|
||||
onClearHistory: function () {},
|
||||
onPageChanged: function () {},
|
||||
onDeleteVisits: function () {},
|
||||
|
||||
// bookmark observer
|
||||
//onBeginUpdateBatch: function() {},
|
||||
|
|
|
@ -61,19 +61,15 @@ var observer = {
|
|||
dump("onVisit: " + aURI.spec + "\n");
|
||||
confirm_results();
|
||||
},
|
||||
onTitleChanged: function(aURI, aPageTitle) {},
|
||||
onBeforeDeleteURI: function(aURI) {},
|
||||
onDeleteURI: function(aURI) {},
|
||||
onClearHistory: function() {},
|
||||
onPageChanged: function(aURI, aWhat, aValue) {},
|
||||
onDeleteVisits: function() {},
|
||||
QueryInterface: function(iid) {
|
||||
if (iid.equals(Ci.nsINavHistoryObserver) ||
|
||||
iid.equals(Ci.nsISupports)) {
|
||||
return this;
|
||||
}
|
||||
throw Cr.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
onTitleChanged: function () {},
|
||||
onBeforeDeleteURI: function () {},
|
||||
onDeleteURI: function () {},
|
||||
onClearHistory: function () {},
|
||||
onPageChanged: function () {},
|
||||
onDeleteVisits: function () {},
|
||||
QueryInterface: XPCOMUtils.generateQI([
|
||||
Ci.nsINavHistoryObserver
|
||||
])
|
||||
};
|
||||
|
||||
histsvc.addObserver(observer, false);
|
||||
|
|
|
@ -86,13 +86,15 @@ function TitleChangedObserver(aURI,
|
|||
TitleChangedObserver.prototype = {
|
||||
__proto__: NavHistoryObserver.prototype,
|
||||
onTitleChanged: function(aURI,
|
||||
aTitle)
|
||||
aTitle,
|
||||
aGUID)
|
||||
{
|
||||
do_log_info("onTitleChanged(" + aURI.spec + ", " + aTitle + ")");
|
||||
do_log_info("onTitleChanged(" + aURI.spec + ", " + aTitle + ", " + aGUID + ")");
|
||||
if (!this.uri.equals(aURI)) {
|
||||
return;
|
||||
}
|
||||
do_check_eq(aTitle, this.expectedTitle);
|
||||
do_check_guid_for_uri(aURI, aGUID);
|
||||
this.callback();
|
||||
},
|
||||
};
|
||||
|
|
|
@ -161,10 +161,12 @@ var historyObserver = {
|
|||
onClearHistory: function() {},
|
||||
onDeleteVisits: function() {},
|
||||
|
||||
onPageChanged: function historyObserver_onPageChanged(pageURI, what, value) {
|
||||
onPageChanged: function historyObserver_onPageChanged(pageURI, what, value, guid) {
|
||||
if (what != Ci.nsINavHistoryObserver.ATTRIBUTE_FAVICON)
|
||||
return;
|
||||
|
||||
do_check_guid_for_uri(pageURI, guid);
|
||||
|
||||
if (pageURI.equals(tests[currentTestIndex].pageURI)) {
|
||||
tests[currentTestIndex].check();
|
||||
currentTestIndex++;
|
||||
|
|
|
@ -143,7 +143,7 @@ let historyObserver = {
|
|||
onClearHistory: function() {},
|
||||
onDeleteVisits: function() {},
|
||||
|
||||
onPageChanged: function historyObserver_onPageChanged(pageURI, what, value) {
|
||||
onPageChanged: function historyObserver_onPageChanged(pageURI, what, value, guid) {
|
||||
if (what != Ci.nsINavHistoryObserver.ATTRIBUTE_FAVICON)
|
||||
return;
|
||||
|
||||
|
@ -151,6 +151,8 @@ let historyObserver = {
|
|||
//dump_table("moz_places");
|
||||
//dump_table("moz_favicons");
|
||||
|
||||
do_check_guid_for_uri(pageURI, guid);
|
||||
|
||||
// Ensure we have been called by the last test.
|
||||
do_check_true(pageURI.equals(NetUtil.newURI("http://testfinal.bar/")));
|
||||
|
||||
|
|
|
@ -67,9 +67,10 @@ add_test(function test_onVisit() {
|
|||
});
|
||||
|
||||
add_test(function test_onBeforeDeleteURI() {
|
||||
onNotify(function onBeforeDeleteURI(aURI, aGUID) {
|
||||
onNotify(function onBeforeDeleteURI(aURI, aGUID, aReason) {
|
||||
do_check_true(aURI.equals(testuri));
|
||||
do_check_guid_for_uri(aURI, aGUID);
|
||||
do_check_eq(aReason, Ci.nsINavHistoryObserver.REASON_DELETED);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
@ -78,10 +79,11 @@ add_test(function test_onBeforeDeleteURI() {
|
|||
});
|
||||
|
||||
add_test(function test_onDeleteURI() {
|
||||
onNotify(function onDeleteURI(aURI, aGUID) {
|
||||
onNotify(function onDeleteURI(aURI, aGUID, aReason) {
|
||||
do_check_true(aURI.equals(testuri));
|
||||
// Can't use do_check_guid_for_uri() here because the visit is already gone.
|
||||
do_check_eq(aGUID, testguid);
|
||||
do_check_eq(aReason, Ci.nsINavHistoryObserver.REASON_DELETED);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
@ -89,3 +91,59 @@ add_test(function test_onDeleteURI() {
|
|||
let testguid = do_get_guid_for_uri(testuri);
|
||||
PlacesUtils.bhistory.removePage(testuri);
|
||||
});
|
||||
|
||||
add_test(function test_onDeleteVisits() {
|
||||
onNotify(function onDeleteVisits(aURI, aVisitTime, aGUID, aReason) {
|
||||
do_check_true(aURI.equals(testuri));
|
||||
// Can't use do_check_guid_for_uri() here because the visit is already gone.
|
||||
do_check_eq(aGUID, testguid);
|
||||
do_check_eq(aReason, Ci.nsINavHistoryObserver.REASON_DELETED);
|
||||
do_check_eq(aVisitTime, 0); // All visits have been removed.
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
let msecs24hrsAgo = Date.now() - (86400 * 1000);
|
||||
let [testuri] = add_visit(undefined, msecs24hrsAgo * 1000);
|
||||
// Add a bookmark so the page is not removed.
|
||||
PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
|
||||
testuri,
|
||||
PlacesUtils.bookmarks.DEFAULT_INDEX,
|
||||
"test");
|
||||
let testguid = do_get_guid_for_uri(testuri);
|
||||
PlacesUtils.bhistory.removePage(testuri);
|
||||
});
|
||||
|
||||
add_test(function test_onTitleChanged() {
|
||||
onNotify(function onTitleChanged(aURI, aTitle, aGUID) {
|
||||
do_check_true(aURI.equals(testuri));
|
||||
do_check_eq(aTitle, title);
|
||||
do_check_guid_for_uri(aURI, aGUID);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
let [testuri] = add_visit();
|
||||
let title = "test-title";
|
||||
PlacesUtils.history.setPageTitle(testuri, title);
|
||||
});
|
||||
|
||||
add_test(function test_onPageChanged() {
|
||||
onNotify(function onPageChanged(aURI, aChangedAttribute, aNewValue, aGUID) {
|
||||
do_check_eq(aChangedAttribute, Ci.nsINavHistoryObserver.ATTRIBUTE_FAVICON);
|
||||
do_check_true(aURI.equals(testuri));
|
||||
do_check_eq(aNewValue, iconurl);
|
||||
do_check_guid_for_uri(aURI, aGUID);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
let [testuri] = add_visit();
|
||||
|
||||
let iconurl = "file:///favicon-normal32.png";
|
||||
let data = readFileData(do_get_file("favicon-normal32.png"));
|
||||
PlacesUtils.favicons.setFaviconData(NetUtil.newURI(iconurl),
|
||||
data, data.length, "image/png",
|
||||
Number.MAX_VALUE);
|
||||
|
||||
PlacesUtils.favicons.setFaviconUrlForPage(testuri, NetUtil.newURI(iconurl));
|
||||
});
|
||||
|
|
|
@ -100,25 +100,15 @@ var observer = {
|
|||
if (this._visitCount == gVisits.length)
|
||||
do_test_finished();
|
||||
},
|
||||
onTitleChanged: function(aURI, aPageTitle) {
|
||||
},
|
||||
onBeforeDeleteURI: function(aURI) {
|
||||
},
|
||||
onDeleteURI: function(aURI) {
|
||||
},
|
||||
onClearHistory: function() {
|
||||
},
|
||||
onPageChanged: function(aURI, aWhat, aValue) {
|
||||
},
|
||||
onDeleteVisits: function() {
|
||||
},
|
||||
QueryInterface: function(iid) {
|
||||
if (iid.equals(Ci.nsINavHistoryObserver) ||
|
||||
iid.equals(Ci.nsISupports)) {
|
||||
return this;
|
||||
}
|
||||
throw Cr.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
onTitleChanged: function () {},
|
||||
onBeforeDeleteURI: function () {},
|
||||
onDeleteURI: function () {},
|
||||
onClearHistory: function () {},
|
||||
onPageChanged: function () {},
|
||||
onDeleteVisits: function () {},
|
||||
QueryInterface: XPCOMUtils.generateQI([
|
||||
Ci.nsINavHistoryObserver
|
||||
])
|
||||
};
|
||||
|
||||
histsvc.addObserver(observer, false);
|
||||
|
|
|
@ -57,43 +57,28 @@ function Observer()
|
|||
Observer.prototype =
|
||||
{
|
||||
checked: false,
|
||||
onBeginUpdateBatch: function() {
|
||||
},
|
||||
onEndUpdateBatch: function() {
|
||||
},
|
||||
onVisit: function(aURI, aVisitID, aTime, aSessionId, aReferringId,
|
||||
aTransitionType, _added)
|
||||
{
|
||||
},
|
||||
onTitleChanged: function(aURI, aPageTable)
|
||||
{
|
||||
},
|
||||
onBeforeDeleteURI: function(aURI, aGUID)
|
||||
onBeginUpdateBatch: function () {},
|
||||
onEndUpdateBatch: function () {},
|
||||
onVisit: function () {},
|
||||
onTitleChanged: function () {},
|
||||
onBeforeDeleteURI: function (aURI, aGUID)
|
||||
{
|
||||
this.removedURI = aURI;
|
||||
this.removedGUID = aGUID;
|
||||
do_check_guid_for_uri(aURI, aGUID);
|
||||
},
|
||||
onDeleteURI: function(aURI, aGUID)
|
||||
onDeleteURI: function (aURI, aGUID)
|
||||
{
|
||||
do_check_false(this.checked);
|
||||
do_check_true(this.removedURI.equals(aURI));
|
||||
do_check_eq(this.removedGUID, aGUID);
|
||||
this.checked = true;
|
||||
},
|
||||
onPageChanged: function(aURI, aWhat, aValue)
|
||||
{
|
||||
},
|
||||
onDeleteVisits: function()
|
||||
{
|
||||
},
|
||||
QueryInterface: function(iid) {
|
||||
if (iid.equals(Ci.nsINavHistoryObserver) ||
|
||||
iid.equals(Ci.nsISupports)) {
|
||||
return this;
|
||||
}
|
||||
throw Cr.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
onPageChanged: function () {},
|
||||
onDeleteVisits: function () {},
|
||||
QueryInterface: XPCOMUtils.generateQI([
|
||||
Ci.nsINavHistoryObserver
|
||||
])
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -77,6 +77,7 @@
|
|||
#include "prprf.h"
|
||||
#include "prnetdb.h"
|
||||
#include "zlib.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
// Needed to interpert mozIStorageConnection::GetLastError
|
||||
#include <sqlite3.h>
|
||||
|
@ -1798,7 +1799,6 @@ nsUrlClassifierDBServiceWorker::GetTables(nsIUrlClassifierCallback* c)
|
|||
|
||||
nsresult rv = OpenDb();
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_ERROR("Unable to open database");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
|
@ -2913,7 +2913,6 @@ nsUrlClassifierDBServiceWorker::BeginUpdate(nsIUrlClassifierUpdateObserver *obse
|
|||
|
||||
nsresult rv = OpenDb();
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_ERROR("Unable to open database");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
|
@ -3061,7 +3060,6 @@ nsUrlClassifierDBServiceWorker::UpdateStream(const nsACString& chunk)
|
|||
LOG(("Update from Stream."));
|
||||
nsresult rv = OpenDb();
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_ERROR("Unable to open database");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
|
@ -3367,6 +3365,15 @@ nsUrlClassifierDBServiceWorker::OpenDb()
|
|||
if (mConnection)
|
||||
return NS_OK;
|
||||
|
||||
// If we're turned off, refuse to open the DB
|
||||
PRBool openDB =
|
||||
Preferences::GetBool(CHECK_MALWARE_PREF, CHECK_MALWARE_DEFAULT) ||
|
||||
Preferences::GetBool(CHECK_PHISHING_PREF, CHECK_PHISHING_DEFAULT);
|
||||
if (!openDB) {
|
||||
NS_WARNING("Not opening url-classifier DB");
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
LOG(("Opening db\n"));
|
||||
|
||||
nsresult rv;
|
||||
|
|
Загрузка…
Ссылка в новой задаче