Merge mozilla-central to mozilla-inbound

This commit is contained in:
Carsten "Tomcat" Book 2016-03-03 11:57:42 +01:00
Родитель f61d05c3cf 82cf3c3383
Коммит 78ab08e8be
52 изменённых файлов: 988 добавлений и 480 удалений

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

@ -1379,44 +1379,37 @@ var BookmarkingUI = {
aHeaderItem.nextSibling.remove(); aHeaderItem.nextSibling.remove();
} }
PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase) let onItemCommand = function (aEvent) {
.asyncExecuteLegacyQueries([query], 1, options, { let item = aEvent.target;
handleResult: function (aResultSet) { openUILink(item.getAttribute("targetURI"), aEvent);
let onItemCommand = function (aEvent) { CustomizableUI.hidePanelForNode(item);
let item = aEvent.target; };
openUILink(item.getAttribute("targetURI"), aEvent);
CustomizableUI.hidePanelForNode(item);
};
let fragment = document.createDocumentFragment(); let fragment = document.createDocumentFragment();
let row; let root = PlacesUtils.history.executeQuery(query, options).root;
while ((row = aResultSet.getNextRow())) { root.containerOpen = true;
let uri = row.getResultByIndex(1); for (let i = 0; i < root.childCount; i++) {
let title = row.getResultByIndex(2); let node = root.getChild(i);
let icon = row.getResultByIndex(6); let uri = node.uri;
let title = node.title;
let icon = node.icon;
let item = let item =
document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
"menuitem"); "menuitem");
item.setAttribute("label", title || uri); item.setAttribute("label", title || uri);
item.setAttribute("targetURI", uri); item.setAttribute("targetURI", uri);
item.setAttribute("class", "menuitem-iconic menuitem-with-favicon bookmark-item " + item.setAttribute("class", "menuitem-iconic menuitem-with-favicon bookmark-item " +
extraCSSClass); extraCSSClass);
item.addEventListener("command", onItemCommand); item.addEventListener("command", onItemCommand);
if (icon) { if (icon) {
let iconURL = "moz-anno:favicon:" + icon; let iconURL = "moz-anno:favicon:" + icon;
item.setAttribute("image", iconURL); item.setAttribute("image", iconURL);
} }
fragment.appendChild(item); fragment.appendChild(item);
} }
aHeaderItem.parentNode.insertBefore(fragment, aHeaderItem.nextSibling); root.containerOpen = false;
}, aHeaderItem.parentNode.insertBefore(fragment, aHeaderItem.nextSibling);
handleError: function (aError) {
Cu.reportError("Error while attempting to show recent bookmarks: " + aError);
},
handleCompletion: function (aReason) {
},
});
}, },
/** /**

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

@ -252,7 +252,8 @@ ContentSearchUIController.prototype = {
let searchText = this.input; let searchText = this.input;
let searchTerms; let searchTerms;
if (this._table.hidden || if (this._table.hidden ||
aEvent.originalTarget.id == "contentSearchDefaultEngineHeader") { aEvent.originalTarget.id == "contentSearchDefaultEngineHeader" ||
aEvent instanceof KeyboardEvent) {
searchTerms = searchText.value; searchTerms = searchText.value;
} }
else { else {

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

@ -290,7 +290,6 @@ skip-if = os == 'win' || e10s # Bug 1159268 - Need a content-process safe versio
[browser_bug1070778.js] [browser_bug1070778.js]
[browser_accesskeys.js] [browser_accesskeys.js]
[browser_canonizeURL.js] [browser_canonizeURL.js]
skip-if = e10s # Bug 1094510 - test hits the network in e10s mode only
[browser_clipboard.js] [browser_clipboard.js]
[browser_contentAreaClick.js] [browser_contentAreaClick.js]
[browser_contextmenu.js] [browser_contextmenu.js]

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

@ -1,8 +1,3 @@
function test() {
waitForExplicitFinish();
testNext();
}
var pairs = [ var pairs = [
["example", "http://www.example.net/"], ["example", "http://www.example.net/"],
["ex-ample", "http://www.ex-ample.net/"], ["ex-ample", "http://www.ex-ample.net/"],
@ -20,37 +15,56 @@ var pairs = [
["ex ample", Services.search.defaultEngine.getSubmission("ex ample", null, "keyword").uri.spec], ["ex ample", Services.search.defaultEngine.getSubmission("ex ample", null, "keyword").uri.spec],
]; ];
function testNext() { add_task(function*() {
if (!pairs.length) { for (let [inputValue, expectedURL] of pairs) {
finish(); let focusEventPromise = BrowserTestUtils.waitForEvent(gURLBar, "focus");
return; let messagePromise = BrowserTestUtils.waitForMessage(gBrowser.selectedBrowser.messageManager,
} "browser_canonizeURL:start");
let [inputValue, expectedURL] = pairs.shift(); let stoppedLoadPromise = ContentTask.spawn(gBrowser.selectedBrowser, [inputValue, expectedURL],
function([inputValue, expectedURL]) {
return new Promise(resolve => {
let wpl = {
onStateChange(aWebProgress, aRequest, aStateFlags, aStatus) {
if (aStateFlags & Ci.nsIWebProgressListener.STATE_START &&
aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK) {
if (!aRequest || !(aRequest instanceof Ci.nsIChannel)) {
return;
}
aRequest.QueryInterface(Ci.nsIChannel);
is(aRequest.originalURI.spec, expectedURL,
"entering '" + inputValue + "' loads expected URL");
gBrowser.addProgressListener({ webProgress.removeProgressListener(filter);
onStateChange: function onStateChange(aWebProgress, aRequest, aStateFlags, aStatus) { filter.removeProgressListener(wpl);
if (aStateFlags & Ci.nsIWebProgressListener.STATE_START && docShell.QueryInterface(Ci.nsIWebNavigation);
aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK) { docShell.stop(docShell.STOP_ALL);
is(aRequest.originalURI.spec, expectedURL, resolve();
"entering '" + inputValue + "' loads expected URL"); }
},
};
let filter = Cc["@mozilla.org/appshell/component/browser-status-filter;1"]
.createInstance(Ci.nsIWebProgress);
filter.addProgressListener(wpl, Ci.nsIWebProgress.NOTIFY_ALL);
gBrowser.removeProgressListener(this); let webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
gBrowser.stop(); .getInterface(Ci.nsIWebProgress);
webProgress.addProgressListener(filter, Ci.nsIWebProgress.NOTIFY_ALL);
executeSoon(testNext); // We're sending this off to trigger the start of the this test, when all the
// listeners are in place:
sendAsyncMessage("browser_canonizeURL:start");
});
} }
} );
});
gBrowser.selectedBrowser.focus();
gURLBar.focus();
yield Promise.all([focusEventPromise, messagePromise]);
gURLBar.addEventListener("focus", function onFocus() {
gURLBar.removeEventListener("focus", onFocus);
gURLBar.inputField.value = inputValue.slice(0, -1); gURLBar.inputField.value = inputValue.slice(0, -1);
EventUtils.synthesizeKey(inputValue.slice(-1) , {}); EventUtils.synthesizeKey(inputValue.slice(-1) , {});
EventUtils.synthesizeKey("VK_RETURN", { shiftKey: true }); EventUtils.synthesizeKey("VK_RETURN", { shiftKey: true });
}); yield stoppedLoadPromise;
}
gBrowser.selectedBrowser.focus(); });
gURLBar.focus();
}

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

@ -105,7 +105,7 @@
when-connection="secure secure-ev"/> when-connection="secure secure-ev"/>
</vbox> </vbox>
<vbox id="identity-popup-securityView-body"> <vbox id="identity-popup-securityView-body" flex="1">
<!-- (EV) Certificate Information --> <!-- (EV) Certificate Information -->
<description id="identity-popup-content-verified-by" <description id="identity-popup-content-verified-by"
when-connection="secure-ev">&identity.connectionVerified1;</description> when-connection="secure-ev">&identity.connectionVerified1;</description>
@ -168,7 +168,9 @@
label="&identity.enableMixedContentBlocking.label;" label="&identity.enableMixedContentBlocking.label;"
accesskey="&identity.enableMixedContentBlocking.accesskey;" accesskey="&identity.enableMixedContentBlocking.accesskey;"
oncommand="gIdentityHandler.enableMixedContentProtection()"/> oncommand="gIdentityHandler.enableMixedContentProtection()"/>
</vbox>
<vbox id="identity-popup-securityView-footer">
<!-- More Security Information --> <!-- More Security Information -->
<button label="&identity.moreInfoLinkText2;" <button label="&identity.moreInfoLinkText2;"
oncommand="gIdentityHandler.handleMoreInfoClick(event);"/> oncommand="gIdentityHandler.handleMoreInfoClick(event);"/>

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

@ -346,11 +346,47 @@ DistributionCustomizer.prototype = {
Cu.reportError(e); Cu.reportError(e);
} }
var usedPreferences = [];
if (sections["Preferences-" + this._locale]) {
for (let key of enumerate(this._ini.getKeys("Preferences-" + this._locale))) {
try {
let value = this._ini.getString("Preferences-" + this._locale, key);
if (value) {
Preferences.set(key, parseValue(value));
}
usedPreferences.push(key);
} catch (e) { /* ignore bad prefs and move on */ }
}
}
if (sections["Preferences-" + this._language]) {
for (let key of enumerate(this._ini.getKeys("Preferences-" + this._language))) {
if (usedPreferences.indexOf(key) > -1) {
continue;
}
try {
let value = this._ini.getString("Preferences-" + this._language, key);
if (value) {
Preferences.set(key, parseValue(value));
}
usedPreferences.push(key);
} catch (e) { /* ignore bad prefs and move on */ }
}
}
if (sections["Preferences"]) { if (sections["Preferences"]) {
for (let key of enumerate(this._ini.getKeys("Preferences"))) { for (let key of enumerate(this._ini.getKeys("Preferences"))) {
if (usedPreferences.indexOf(key) > -1) {
continue;
}
try { try {
let value = parseValue(this._ini.getString("Preferences", key)); let value = this._ini.getString("Preferences", key);
Preferences.set(key, value); if (value) {
value = value.replace(/%LOCALE%/g, this._locale);
value = value.replace(/%LANGUAGE%/g, this._language);
Preferences.set(key, parseValue(value));
}
} catch (e) { /* ignore bad prefs and move on */ } } catch (e) { /* ignore bad prefs and move on */ }
} }
} }
@ -363,8 +399,9 @@ DistributionCustomizer.prototype = {
if (sections["LocalizablePreferences-" + this._locale]) { if (sections["LocalizablePreferences-" + this._locale]) {
for (let key of enumerate(this._ini.getKeys("LocalizablePreferences-" + this._locale))) { for (let key of enumerate(this._ini.getKeys("LocalizablePreferences-" + this._locale))) {
try { try {
let value = parseValue(this._ini.getString("LocalizablePreferences-" + this._locale, key)); let value = this._ini.getString("LocalizablePreferences-" + this._locale, key);
if (value !== undefined) { if (value) {
value = parseValue(value);
localizedStr.data = "data:text/plain," + key + "=" + value; localizedStr.data = "data:text/plain," + key + "=" + value;
defaults._prefBranch.setComplexValue(key, Ci.nsIPrefLocalizedString, localizedStr); defaults._prefBranch.setComplexValue(key, Ci.nsIPrefLocalizedString, localizedStr);
} }
@ -379,8 +416,9 @@ DistributionCustomizer.prototype = {
continue; continue;
} }
try { try {
let value = parseValue(this._ini.getString("LocalizablePreferences-" + this._language, key)); let value = this._ini.getString("LocalizablePreferences-" + this._language, key);
if (value !== undefined) { if (value) {
value = parseValue(value);
localizedStr.data = "data:text/plain," + key + "=" + value; localizedStr.data = "data:text/plain," + key + "=" + value;
defaults._prefBranch.setComplexValue(key, Ci.nsIPrefLocalizedString, localizedStr); defaults._prefBranch.setComplexValue(key, Ci.nsIPrefLocalizedString, localizedStr);
} }
@ -395,13 +433,14 @@ DistributionCustomizer.prototype = {
continue; continue;
} }
try { try {
let value = parseValue(this._ini.getString("LocalizablePreferences", key)); let value = this._ini.getString("LocalizablePreferences", key);
if (value !== undefined) { if (value) {
value = parseValue(value);
value = value.replace(/%LOCALE%/g, this._locale); value = value.replace(/%LOCALE%/g, this._locale);
value = value.replace(/%LANGUAGE%/g, this._language); value = value.replace(/%LANGUAGE%/g, this._language);
localizedStr.data = "data:text/plain," + key + "=" + value; localizedStr.data = "data:text/plain," + key + "=" + value;
defaults._prefBranch.setComplexValue(key, Ci.nsIPrefLocalizedString, localizedStr);
} }
defaults._prefBranch.setComplexValue(key, Ci.nsIPrefLocalizedString, localizedStr);
} catch (e) { /* ignore bad prefs and move on */ } } catch (e) { /* ignore bad prefs and move on */ }
} }
} }

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

@ -125,6 +125,19 @@ global.makeWidgetId = id => {
return id.replace(/[^a-z0-9_-]/g, "_"); return id.replace(/[^a-z0-9_-]/g, "_");
}; };
function promisePopupShown(popup) {
return new Promise(resolve => {
if (popup.state == "open") {
resolve();
} else {
popup.addEventListener("popupshown", function onPopupShown(event) {
popup.removeEventListener("popupshown", onPopupShown);
resolve();
});
}
});
}
class BasePopup { class BasePopup {
constructor(extension, viewNode, popupURL) { constructor(extension, viewNode, popupURL) {
let popupURI = Services.io.newURI(popupURL, null, extension.baseURI); let popupURI = Services.io.newURI(popupURL, null, extension.baseURI);
@ -254,6 +267,10 @@ class BasePopup {
// Resizes the browser to match the preferred size of the content. // Resizes the browser to match the preferred size of the content.
resizeBrowser() { resizeBrowser() {
if (!this.browser) {
return;
}
let width, height; let width, height;
try { try {
let w = {}, h = {}; let w = {}, h = {};
@ -310,7 +327,12 @@ global.PanelPopup = class PanelPopup extends BasePopup {
} }
closePopup() { closePopup() {
this.viewNode.hidePopup(); promisePopupShown(this.viewNode).then(() => {
// Make sure we're not already destroyed.
if (this.viewNode) {
this.viewNode.hidePopup();
}
});
} }
}; };

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

@ -3,6 +3,8 @@
"use strict"; "use strict";
function* testInArea(area) { function* testInArea(area) {
let scriptPage = url => `<html><head><meta charset="utf-8"><script src="${url}"></script></head></html>`;
let extension = ExtensionTestUtils.loadExtension({ let extension = ExtensionTestUtils.loadExtension({
manifest: { manifest: {
"background": { "background": {
@ -14,17 +16,22 @@ function* testInArea(area) {
}, },
files: { files: {
"popup-a.html": `<script src="popup-a.js"></script>`, "popup-a.html": scriptPage("popup-a.js"),
"popup-a.js": function() { "popup-a.js": function() {
browser.runtime.sendMessage("from-popup-a"); browser.runtime.sendMessage("from-popup-a");
browser.runtime.onMessage.addListener(msg => {
if (msg == "close-popup") {
window.close();
}
});
}, },
"data/popup-b.html": `<script src="popup-b.js"></script>`, "data/popup-b.html": scriptPage("popup-b.js"),
"data/popup-b.js": function() { "data/popup-b.js": function() {
browser.runtime.sendMessage("from-popup-b"); browser.runtime.sendMessage("from-popup-b");
}, },
"data/background.html": `<script src="background.js"></script>`, "data/background.html": scriptPage("background.js"),
"data/background.js": function() { "data/background.js": function() {
let sendClick; let sendClick;
@ -51,26 +58,36 @@ function* testInArea(area) {
}, },
() => { () => {
browser.browserAction.setPopup({popup: "/popup-a.html"}); browser.browserAction.setPopup({popup: "/popup-a.html"});
sendClick({expectEvent: false, expectPopup: "a"}); sendClick({expectEvent: false, expectPopup: "a", runNextTest: true});
},
() => {
browser.test.sendMessage("next-test", {expectClosed: true});
}, },
]; ];
let expect = {}; let expect = {};
sendClick = ({expectEvent, expectPopup}) => { sendClick = ({expectEvent, expectPopup, runNextTest}) => {
expect = {event: expectEvent, popup: expectPopup}; expect = {event: expectEvent, popup: expectPopup, runNextTest};
browser.test.sendMessage("send-click"); browser.test.sendMessage("send-click");
}; };
browser.runtime.onMessage.addListener(msg => { browser.runtime.onMessage.addListener(msg => {
if (expect.popup) { if (msg == "close-popup") {
return;
} else if (expect.popup) {
browser.test.assertEq(msg, `from-popup-${expect.popup}`, browser.test.assertEq(msg, `from-popup-${expect.popup}`,
"expected popup opened"); "expected popup opened");
} else { } else {
browser.test.fail("unexpected popup"); browser.test.fail(`unexpected popup: ${msg}`);
} }
expect.popup = null; expect.popup = null;
browser.test.sendMessage("next-test"); if (expect.runNextTest) {
expect.runNextTest = false;
tests.shift()();
} else {
browser.test.sendMessage("next-test");
}
}); });
browser.browserAction.onClicked.addListener(() => { browser.browserAction.onClicked.addListener(() => {
@ -85,6 +102,11 @@ function* testInArea(area) {
}); });
browser.test.onMessage.addListener((msg) => { browser.test.onMessage.addListener((msg) => {
if (msg == "close-popup") {
browser.runtime.sendMessage("close-popup");
return;
}
if (msg != "next-test") { if (msg != "next-test") {
browser.test.fail("Expecting 'next-test' message"); browser.test.fail("Expecting 'next-test' message");
} }
@ -107,13 +129,23 @@ function* testInArea(area) {
}); });
let widget; let widget;
extension.onMessage("next-test", Task.async(function* () { extension.onMessage("next-test", Task.async(function* (expecting = {}) {
if (!widget) { if (!widget) {
widget = getBrowserActionWidget(extension); widget = getBrowserActionWidget(extension);
CustomizableUI.addWidgetToArea(widget.id, area); CustomizableUI.addWidgetToArea(widget.id, area);
} }
if (expecting.expectClosed) {
let panel = getBrowserActionPopup(extension);
ok(panel, "Expect panel to exist");
yield promisePopupShown(panel);
yield closeBrowserAction(extension); extension.sendMessage("close-popup");
yield promisePopupHidden(panel);
ok(true, "Panel is closed");
} else {
yield closeBrowserAction(extension);
}
extension.sendMessage("next-test"); extension.sendMessage("next-test");
})); }));

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

@ -19,6 +19,11 @@ add_task(function* testPageActionPopup() {
"popup-a.html": scriptPage("popup-a.js"), "popup-a.html": scriptPage("popup-a.js"),
"popup-a.js": function() { "popup-a.js": function() {
browser.runtime.sendMessage("from-popup-a"); browser.runtime.sendMessage("from-popup-a");
browser.runtime.onMessage.addListener(msg => {
if (msg == "close-popup") {
window.close();
}
});
}, },
"data/popup-b.html": scriptPage("popup-b.js"), "data/popup-b.html": scriptPage("popup-b.js"),
@ -55,26 +60,36 @@ add_task(function* testPageActionPopup() {
}, },
() => { () => {
browser.pageAction.setPopup({tabId, popup: "/popup-a.html"}); browser.pageAction.setPopup({tabId, popup: "/popup-a.html"});
sendClick({expectEvent: false, expectPopup: "a"}); sendClick({expectEvent: false, expectPopup: "a", runNextTest: true});
},
() => {
browser.test.sendMessage("next-test", {expectClosed: true});
}, },
]; ];
let expect = {}; let expect = {};
sendClick = ({expectEvent, expectPopup}) => { sendClick = ({expectEvent, expectPopup, runNextTest}) => {
expect = {event: expectEvent, popup: expectPopup}; expect = {event: expectEvent, popup: expectPopup, runNextTest};
browser.test.sendMessage("send-click"); browser.test.sendMessage("send-click");
}; };
browser.runtime.onMessage.addListener(msg => { browser.runtime.onMessage.addListener(msg => {
if (expect.popup) { if (msg == "close-popup") {
return;
} else if (expect.popup) {
browser.test.assertEq(msg, `from-popup-${expect.popup}`, browser.test.assertEq(msg, `from-popup-${expect.popup}`,
"expected popup opened"); "expected popup opened");
} else { } else {
browser.test.fail("unexpected popup"); browser.test.fail(`unexpected popup: ${msg}`);
} }
expect.popup = null; expect.popup = null;
browser.test.sendMessage("next-test"); if (expect.runNextTest) {
expect.runNextTest = false;
tests.shift()();
} else {
browser.test.sendMessage("next-test");
}
}); });
browser.pageAction.onClicked.addListener(() => { browser.pageAction.onClicked.addListener(() => {
@ -89,6 +104,11 @@ add_task(function* testPageActionPopup() {
}); });
browser.test.onMessage.addListener((msg) => { browser.test.onMessage.addListener((msg) => {
if (msg == "close-popup") {
browser.runtime.sendMessage("close-popup");
return;
}
if (msg != "next-test") { if (msg != "next-test") {
browser.test.fail("Expecting 'next-test' message"); browser.test.fail("Expecting 'next-test' message");
} }
@ -118,12 +138,22 @@ add_task(function* testPageActionPopup() {
clickPageAction(extension); clickPageAction(extension);
}); });
extension.onMessage("next-test", Task.async(function* () { extension.onMessage("next-test", Task.async(function* (expecting = {}) {
let panel = document.getElementById(panelId); let panel = document.getElementById(panelId);
if (panel) { if (expecting.expectClosed) {
ok(panel, "Expect panel to exist");
yield promisePopupShown(panel);
extension.sendMessage("close-popup");
yield promisePopupHidden(panel);
ok(true, `Panel is closed`);
} else if (panel) {
yield promisePopupShown(panel); yield promisePopupShown(panel);
panel.hidePopup(); panel.hidePopup();
}
if (panel) {
panel = document.getElementById(panelId); panel = document.getElementById(panelId);
is(panel, null, "panel successfully removed from document after hiding"); is(panel, null, "panel successfully removed from document after hiding");
} }

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

@ -138,6 +138,9 @@ add_task(function* testWebNavigationFrames() {
is(getAllFramesDetails.length, collectedDetails.length, is(getAllFramesDetails.length, collectedDetails.length,
"number of frames found should equal the number onCompleted events collected"); "number of frames found should equal the number onCompleted events collected");
is(getAllFramesDetails[0].frameId, 0, "the root frame has the expected frameId");
is(getAllFramesDetails[0].parentFrameId, -1, "the root frame has the expected parentFrameId");
// ordered by frameId // ordered by frameId
let sortByFrameId = (el1, el2) => { let sortByFrameId = (el1, el2) => {
let val1 = el1 ? el1.frameId : -1; let val1 = el1 ? el1.frameId : -1;

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

@ -7,7 +7,7 @@
* clickBrowserAction clickPageAction * clickBrowserAction clickPageAction
* getBrowserActionPopup getPageActionPopup * getBrowserActionPopup getPageActionPopup
* closeBrowserAction closePageAction * closeBrowserAction closePageAction
* promisePopupShown * promisePopupShown promisePopupHidden
*/ */
var {AppConstants} = Cu.import("resource://gre/modules/AppConstants.jsm"); var {AppConstants} = Cu.import("resource://gre/modules/AppConstants.jsm");
@ -59,6 +59,16 @@ function promisePopupShown(popup) {
}); });
} }
function promisePopupHidden(popup) {
return new Promise(resolve => {
let onPopupHidden = event => {
popup.removeEventListener("popuphidden", onPopupHidden);
resolve();
};
popup.addEventListener("popuphidden", onPopupHidden);
});
}
function getBrowserActionWidget(extension) { function getBrowserActionWidget(extension) {
return CustomizableUI.getWidget(makeWidgetId(extension.id) + "-browser-action"); return CustomizableUI.getWidget(makeWidgetId(extension.id) + "-browser-action");
} }
@ -68,6 +78,8 @@ function getBrowserActionPopup(extension, win = window) {
if (group.areaType == CustomizableUI.TYPE_TOOLBAR) { if (group.areaType == CustomizableUI.TYPE_TOOLBAR) {
return win.document.getElementById("customizationui-widget-panel"); return win.document.getElementById("customizationui-widget-panel");
} else {
return win.PanelUI.panel;
} }
return null; return null;
} }

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

@ -46,7 +46,6 @@ skip-if = e10s # Bug ?????? - test fails - "Number of dragged items should be th
[browser_library_search.js] [browser_library_search.js]
[browser_library_views_liveupdate.js] [browser_library_views_liveupdate.js]
[browser_markPageAsFollowedLink.js] [browser_markPageAsFollowedLink.js]
skip-if = e10s # Bug 933103 - mochitest's EventUtils.synthesizeMouse functions not e10s friendly (test does EventUtils.sendMouseEvent...)
[browser_sidebarpanels_click.js] [browser_sidebarpanels_click.js]
skip-if = true # temporarily disabled for breaking the treeview - bug 658744 skip-if = true # temporarily disabled for breaking the treeview - bug 658744
[browser_sort_in_library.js] [browser_sort_in_library.js]

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

@ -1,7 +1,3 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/** /**
* Tests that visits across frames are correctly represented in the database. * Tests that visits across frames are correctly represented in the database.
*/ */
@ -11,76 +7,61 @@ const PAGE_URL = BASE_URL + "/framedPage.html";
const LEFT_URL = BASE_URL + "/frameLeft.html"; const LEFT_URL = BASE_URL + "/frameLeft.html";
const RIGHT_URL = BASE_URL + "/frameRight.html"; const RIGHT_URL = BASE_URL + "/frameRight.html";
var gTabLoaded = false; add_task(function* test() {
var gLeftFrameVisited = false; // We must wait for both frames to be loaded and the visits to be registered.
let deferredLeftFrameVisit = PromiseUtils.defer();
let deferredRightFrameVisit = PromiseUtils.defer();
var observer = { Services.obs.addObserver(function observe(subject) {
observe: function(aSubject, aTopic, aData) Task.spawn(function* () {
{ let url = subject.QueryInterface(Ci.nsIURI).spec;
let url = aSubject.QueryInterface(Ci.nsIURI).spec; if (url == LEFT_URL ) {
if (url == LEFT_URL ) { is((yield getTransitionForUrl(url)), null,
is(getTransitionForUrl(url), null, "Embed visits should not get a database entry.");
"Embed visits should not get a database entry."); deferredLeftFrameVisit.resolve();
gLeftFrameVisited = true; }
maybeClickLink(); else if (url == RIGHT_URL ) {
} is((yield getTransitionForUrl(url)),
else if (url == RIGHT_URL ) { PlacesUtils.history.TRANSITION_FRAMED_LINK,
is(getTransitionForUrl(url), PlacesUtils.history.TRANSITION_FRAMED_LINK, "User activated visits should get a FRAMED_LINK transition.");
"User activated visits should get a FRAMED_LINK transition."); Services.obs.removeObserver(observe, "uri-visit-saved");
finish(); deferredRightFrameVisit.resolve();
} }
}, });
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]) }, "uri-visit-saved", false);
};
Services.obs.addObserver(observer, "uri-visit-saved", false);
function test() // Open a tab and wait for all the subframes to load.
{ let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, PAGE_URL);
waitForExplicitFinish();
gBrowser.selectedTab = gBrowser.addTab(PAGE_URL);
let frameCount = 0;
gBrowser.selectedBrowser.addEventListener("DOMContentLoaded",
function (event)
{
// Wait for all the frames.
if (frameCount++ < 2)
return;
gBrowser.selectedBrowser.removeEventListener("DOMContentLoaded", arguments.callee, false)
gTabLoaded = true;
maybeClickLink();
}, false
);
}
function maybeClickLink() { // Wait for the left frame visit to be registered.
if (gTabLoaded && gLeftFrameVisited) { info("Waiting left frame visit");
// Click on the link in the left frame to cause a page load in the yield deferredLeftFrameVisit.promise;
// right frame.
EventUtils.sendMouseEvent({type: "click"}, "clickme", content.frames[0]); // Click on the link in the left frame to cause a page load in the
// right frame.
info("Clicking link");
yield ContentTask.spawn(tab.linkedBrowser, {}, function* () {
content.frames[0].document.getElementById("clickme").click();
});
// Wait for the right frame visit to be registered.
info("Waiting right frame visit");
yield deferredRightFrameVisit.promise;
yield BrowserTestUtils.removeTab(tab);
});
function* getTransitionForUrl(url) {
// Ensure all the transactions completed.
yield PlacesTestUtils.promiseAsyncUpdates();
let db = yield PlacesUtils.promiseDBConnection();
let rows = yield db.execute(`
SELECT visit_type
FROM moz_historyvisits
WHERE place_id = (SELECT id FROM moz_places WHERE url = :url)`,
{ url });
if (rows.length) {
return rows[0].getResultByName("visit_type");
} }
return null;
} }
function getTransitionForUrl(aUrl)
{
let dbConn = PlacesUtils.history
.QueryInterface(Ci.nsPIPlacesDatabase).DBConnection;
let stmt = dbConn.createStatement(
"SELECT visit_type FROM moz_historyvisits WHERE place_id = " +
"(SELECT id FROM moz_places WHERE url = :page_url)");
stmt.params.page_url = aUrl;
try {
if (!stmt.executeStep()) {
return null;
}
return stmt.row.visit_type;
}
finally {
stmt.finalize();
}
}
registerCleanupFunction(function ()
{
gBrowser.removeTab(gBrowser.selectedTab);
Services.obs.removeObserver(observer, "uri-visit-saved");
})

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

@ -13,6 +13,28 @@ distribution.test.string.noquotes=Test String
distribution.test.int=777 distribution.test.int=777
distribution.test.bool.true=true distribution.test.bool.true=true
distribution.test.bool.false=false distribution.test.bool.false=false
distribution.test.empty=
distribution.test.pref.locale="%LOCALE%"
distribution.test.pref.language.reset="Preference Set"
distribution.test.pref.locale.reset="Preference Set"
distribution.test.pref.locale.set="Preference Set"
distribution.test.pref.language.set="Preference Set"
[Preferences-en]
distribution.test.pref.language.en="en"
distribution.test.pref.language.reset=
distribution.test.pref.language.set="Language Set"
distribution.test.pref.locale.set="Language Set"
[Preferences-en-US]
distribution.test.pref.locale.en-US="en-US"
distribution.test.pref.locale.reset=
distribution.test.pref.locale.set="Locale Set"
[Preferences-de]
distribution.test.pref.language.de="de"
[LocalizablePreferences] [LocalizablePreferences]
distribution.test.locale="%LOCALE%" distribution.test.locale="%LOCALE%"
@ -33,4 +55,4 @@ distribution.test.locale.reset=
distribution.test.locale.set="Locale Set" distribution.test.locale.set="Locale Set"
[LocalizablePreferences-de] [LocalizablePreferences-de]
distribution.test.locale.de="de" distribution.test.language.de="de"

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

@ -71,10 +71,30 @@ add_task(function* () {
Assert.equal(Services.prefs.getIntPref("distribution.test.int"), 777); Assert.equal(Services.prefs.getIntPref("distribution.test.int"), 777);
Assert.equal(Services.prefs.getBoolPref("distribution.test.bool.true"), true); Assert.equal(Services.prefs.getBoolPref("distribution.test.bool.true"), true);
Assert.equal(Services.prefs.getBoolPref("distribution.test.bool.false"), false); Assert.equal(Services.prefs.getBoolPref("distribution.test.bool.false"), false);
Assert.throws(() => Services.prefs.getCharPref("distribution.test.empty"));
Assert.throws(() => Services.prefs.getIntPref("distribution.test.empty"));
Assert.throws(() => Services.prefs.getBoolPref("distribution.test.empty"));
Assert.equal(Services.prefs.getCharPref("distribution.test.pref.locale"), "en-US");
Assert.equal(Services.prefs.getCharPref("distribution.test.pref.language.en"), "en");
Assert.equal(Services.prefs.getCharPref("distribution.test.pref.locale.en-US"), "en-US");
Assert.throws(() => Services.prefs.getCharPref("distribution.test.pref.language.de"));
// This value was never set because of the empty language specific pref
Assert.throws(() => Services.prefs.getCharPref("distribution.test.pref.language.reset"));
// This value was never set because of the empty locale specific pref
Assert.throws(() => Services.prefs.getCharPref("distribution.test.pref.locale.reset"));
// This value was overridden by a locale specific setting
Assert.equal(Services.prefs.getCharPref("distribution.test.pref.locale.set"), "Locale Set");
// This value was overridden by a language specific setting
Assert.equal(Services.prefs.getCharPref("distribution.test.pref.language.set"), "Language Set");
// Language should not override locale
Assert.notEqual(Services.prefs.getCharPref("distribution.test.pref.locale.set"), "Language Set");
Assert.equal(Services.prefs.getComplexValue("distribution.test.locale", Ci.nsIPrefLocalizedString).data, "en-US"); Assert.equal(Services.prefs.getComplexValue("distribution.test.locale", Ci.nsIPrefLocalizedString).data, "en-US");
Assert.equal(Services.prefs.getComplexValue("distribution.test.language.en", Ci.nsIPrefLocalizedString).data, "en"); Assert.equal(Services.prefs.getComplexValue("distribution.test.language.en", Ci.nsIPrefLocalizedString).data, "en");
Assert.equal(Services.prefs.getComplexValue("distribution.test.locale.en-US", Ci.nsIPrefLocalizedString).data, "en-US"); Assert.equal(Services.prefs.getComplexValue("distribution.test.locale.en-US", Ci.nsIPrefLocalizedString).data, "en-US");
Assert.throws(() => Services.prefs.getComplexValue("distribution.test.locale.de", Ci.nsIPrefLocalizedString)); Assert.throws(() => Services.prefs.getComplexValue("distribution.test.language.de", Ci.nsIPrefLocalizedString));
// This value was never set because of the empty language specific pref // This value was never set because of the empty language specific pref
Assert.throws(() => Services.prefs.getComplexValue("distribution.test.language.reset", Ci.nsIPrefLocalizedString)); Assert.throws(() => Services.prefs.getComplexValue("distribution.test.language.reset", Ci.nsIPrefLocalizedString));
// This value was never set because of the empty locale specific pref // This value was never set because of the empty locale specific pref

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

@ -61,6 +61,15 @@ var ContentClick = {
// Note: We don't need the sidebar code here. // Note: We don't need the sidebar code here.
// Mark the page as a user followed link. This is done so that history can
// distinguish automatic embed visits from user activated ones. For example
// pages loaded in frames are embed visits and lost with the session, while
// visits across frames should be preserved.
try {
if (!PrivateBrowsingUtils.isWindowPrivate(window))
PlacesUIUtils.markPageAsFollowedLink(json.href);
} catch (ex) { /* Skip invalid URIs. */ }
// This part is based on handleLinkClick. // This part is based on handleLinkClick.
var where = window.whereToOpenLink(json); var where = window.whereToOpenLink(json);
if (where == "current") if (where == "current")
@ -73,14 +82,5 @@ var ContentClick = {
referrerPolicy: json.referrerPolicy, referrerPolicy: json.referrerPolicy,
noReferrer: json.noReferrer }; noReferrer: json.noReferrer };
window.openLinkIn(json.href, where, params); window.openLinkIn(json.href, where, params);
// Mark the page as a user followed link. This is done so that history can
// distinguish automatic embed visits from user activated ones. For example
// pages loaded in frames are embed visits and lost with the session, while
// visits across frames should be preserved.
try {
if (!PrivateBrowsingUtils.isWindowPrivate(window))
PlacesUIUtils.markPageAsFollowedLink(json.href);
} catch (ex) { /* Skip invalid URIs. */ }
} }
}; };

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

@ -17,6 +17,15 @@
@hudButtonFocused@ @hudButtonFocused@
} }
#identity-popup-multiView > .panel-viewcontainer > .panel-viewstack > .panel-subviews {
border-bottom-right-radius: 3.5px;
}
#identity-popup-multiView > .panel-viewcontainer > .panel-viewstack > .panel-subviews:-moz-locale-dir(rtl) {
border-bottom-right-radius: 0;
border-bottom-left-radius: 3.5px;
}
#tracking-action-block, #tracking-action-block,
#tracking-action-unblock, #tracking-action-unblock,
#tracking-action-unblock-private, #tracking-action-unblock-private,

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

@ -83,15 +83,9 @@
#identity-popup-multiView > .panel-viewcontainer > .panel-viewstack > .panel-subviews { #identity-popup-multiView > .panel-viewcontainer > .panel-viewstack > .panel-subviews {
background: var(--panel-arrowcontent-background); background: var(--panel-arrowcontent-background);
border-bottom-right-radius: 3.5px;
padding: 0; padding: 0;
} }
#identity-popup-multiView > .panel-viewcontainer > .panel-viewstack > .panel-subviews:-moz-locale-dir(rtl) {
border-bottom-right-radius: 0;
border-bottom-left-radius: 3.5px;
}
.identity-popup-section:not(:first-child) { .identity-popup-section:not(:first-child) {
border-top: 1px solid var(--panel-separator-color); border-top: 1px solid var(--panel-separator-color);
} }
@ -100,14 +94,19 @@
#identity-popup-security-content, #identity-popup-security-content,
#identity-popup-permissions-content, #identity-popup-permissions-content,
#tracking-protection-content { #tracking-protection-content {
padding: 0.5em 0 1em;
-moz-padding-start: calc(2em + 24px);
-moz-padding-end: 1em;
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: 1em 1em; background-position: 1em 1em;
background-size: 24px auto; background-size: 24px auto;
} }
#identity-popup-security-content,
#identity-popup-permissions-content,
#tracking-protection-content {
padding: 0.5em 0 1em;
-moz-padding-start: calc(2em + 24px);
-moz-padding-end: 1em;
}
#identity-popup-securityView:-moz-locale-dir(rtl), #identity-popup-securityView:-moz-locale-dir(rtl),
#identity-popup-security-content:-moz-locale-dir(rtl), #identity-popup-security-content:-moz-locale-dir(rtl),
#identity-popup-permissions-content:-moz-locale-dir(rtl), #identity-popup-permissions-content:-moz-locale-dir(rtl),
@ -208,7 +207,6 @@
} }
#identity-popup-securityView { #identity-popup-securityView {
padding-bottom: 2em;
overflow: hidden; overflow: hidden;
} }
@ -252,7 +250,14 @@
color: Graytext; color: Graytext;
} }
#identity-popup-securityView-header,
#identity-popup-securityView-body {
-moz-margin-start: calc(2em + 24px);
-moz-margin-end: 1em;
}
#identity-popup-securityView-header { #identity-popup-securityView-header {
margin-top: 0.5em;
border-bottom: 1px solid var(--panel-separator-color); border-bottom: 1px solid var(--panel-separator-color);
padding-bottom: 1em; padding-bottom: 1em;
} }
@ -261,6 +266,30 @@
-moz-padding-end: 1em; -moz-padding-end: 1em;
} }
#identity-popup-securityView-footer {
margin-top: 1em;
background-color: hsla(210,4%,10%,.07);
}
#identity-popup-securityView-footer > button {
-moz-appearance: none;
margin: 0;
border: none;
border-top: 1px solid #ccc;
padding: 8px 20px;
color: ButtonText;
background-color: transparent;
}
#identity-popup-securityView-footer > button:hover,
#identity-popup-securityView-footer > button:focus {
background-color: hsla(210,4%,10%,.07);
}
#identity-popup-securityView-footer > button:hover:active {
background-color: hsla(210,4%,10%,.12);
}
#identity-popup-content-verifier ~ description { #identity-popup-content-verifier ~ description {
margin-top: 1em; margin-top: 1em;
color: Graytext; color: Graytext;

13
devtools/bootstrap.js поставляемый
Просмотреть файл

@ -8,6 +8,13 @@ const Cu = Components.utils;
const Ci = Components.interfaces; const Ci = Components.interfaces;
const {Services} = Cu.import("resource://gre/modules/Services.jsm", {}); const {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
function actionOccurred(id) {
let {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
let Telemetry = require("devtools/client/shared/telemetry");;
let telemetry = new Telemetry();
telemetry.actionOccurred(id);
}
// Helper to listen to a key on all windows // Helper to listen to a key on all windows
function MultiWindowKeyListener({ keyCode, ctrlKey, altKey, callback }) { function MultiWindowKeyListener({ keyCode, ctrlKey, altKey, callback }) {
let keyListener = function (event) { let keyListener = function (event) {
@ -150,6 +157,8 @@ function reload(event) {
gDevTools.showToolbox(target); gDevTools.showToolbox(target);
}, 1000); }, 1000);
} }
actionOccurred("reloadAddonReload");
} }
let listener; let listener;
@ -165,5 +174,7 @@ function shutdown() {
listener.stop(); listener.stop();
listener = null; listener = null;
} }
function install() {} function install() {
actionOccurred("reloadAddonInstalled");
}
function uninstall() {} function uninstall() {}

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

@ -82,7 +82,10 @@ const EVENTS = {
OPTIONS_POPUP_HIDDEN: "Debugger:OptionsPopupHidden", OPTIONS_POPUP_HIDDEN: "Debugger:OptionsPopupHidden",
// When the widgets layout has been changed. // When the widgets layout has been changed.
LAYOUT_CHANGED: "Debugger:LayoutChanged" LAYOUT_CHANGED: "Debugger:LayoutChanged",
// When a worker has been selected.
WORKER_SELECTED: "Debugger::WorkerSelected"
}; };
// Descriptions for what a stack frame represents after the debugger pauses. // Descriptions for what a stack frame represents after the debugger pauses.
@ -108,7 +111,7 @@ Cu.import("resource://devtools/client/shared/widgets/ViewHelpers.jsm");
var L10N = new ViewHelpers.L10N(DBG_STRINGS_URI); var L10N = new ViewHelpers.L10N(DBG_STRINGS_URI);
Cu.import("resource://devtools/client/shared/browser-loader.js"); Cu.import("resource://devtools/client/shared/browser-loader.js");
const require = BrowserLoader("resource://devtools/client/debugger/", this).require; const require = BrowserLoader("resource://devtools/client/debugger/", window).require;
XPCOMUtils.defineConstant(this, "require", require); XPCOMUtils.defineConstant(this, "require", require);
const { gDevTools } = require("devtools/client/framework/devtools"); const { gDevTools } = require("devtools/client/framework/devtools");
@ -491,8 +494,8 @@ Workers.prototype = {
for (let workerActor in this._workerForms) { for (let workerActor in this._workerForms) {
if (!(workerActor in workerForms)) { if (!(workerActor in workerForms)) {
DebuggerView.Workers.removeWorker(this._workerForms[workerActor]);
delete this._workerForms[workerActor]; delete this._workerForms[workerActor];
DebuggerView.Workers.removeWorker(workerActor);
} }
} }
@ -500,7 +503,7 @@ Workers.prototype = {
if (!(workerActor in this._workerForms)) { if (!(workerActor in this._workerForms)) {
let workerForm = workerForms[workerActor]; let workerForm = workerForms[workerActor];
this._workerForms[workerActor] = workerForm; this._workerForms[workerActor] = workerForm;
DebuggerView.Workers.addWorker(workerActor, workerForm.url); DebuggerView.Workers.addWorker(workerForm);
} }
} }
}); });
@ -510,10 +513,11 @@ Workers.prototype = {
this._updateWorkerList(); this._updateWorkerList();
}, },
_onWorkerSelect: function (workerActor) { _onWorkerSelect: function (workerForm) {
DebuggerController.client.attachWorker(workerActor, (response, workerClient) => { DebuggerController.client.attachWorker(workerForm.actor, (response, workerClient) => {
gDevTools.showToolbox(TargetFactory.forWorker(workerClient), let toolbox = gDevTools.showToolbox(TargetFactory.forWorker(workerClient),
"jsdebugger", Toolbox.HostType.WINDOW); "jsdebugger", Toolbox.HostType.WINDOW);
window.emit(EVENTS.WORKER_SELECTED, toolbox);
}); });
} }
}; };

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

@ -45,6 +45,9 @@ support-files =
code_ugly-7.js code_ugly-7.js
code_ugly-8 code_ugly-8
code_ugly-8^headers^ code_ugly-8^headers^
code_worker-source-map.coffee
code_worker-source-map.js
code_worker-source-map.js.map
code_WorkerActor.attach-worker1.js code_WorkerActor.attach-worker1.js
code_WorkerActor.attach-worker2.js code_WorkerActor.attach-worker2.js
code_WorkerActor.attachThread-worker.js code_WorkerActor.attachThread-worker.js
@ -112,6 +115,7 @@ support-files =
doc_watch-expressions.html doc_watch-expressions.html
doc_watch-expression-button.html doc_watch-expression-button.html
doc_with-frame.html doc_with-frame.html
doc_worker-source-map.html
doc_WorkerActor.attach-tab1.html doc_WorkerActor.attach-tab1.html
doc_WorkerActor.attach-tab2.html doc_WorkerActor.attach-tab2.html
doc_WorkerActor.attachThread-tab.html doc_WorkerActor.attachThread-tab.html
@ -592,6 +596,8 @@ skip-if = e10s && debug
skip-if = e10s && debug skip-if = e10s && debug
[browser_dbg_worker-console.js] [browser_dbg_worker-console.js]
skip-if = e10s && debug skip-if = e10s && debug
[browser_dbg_worker-source-map.js]
skip-if = e10s && debug
[browser_dbg_worker-window.js] [browser_dbg_worker-window.js]
skip-if = e10s && debug skip-if = e10s && debug
[browser_dbg_WorkerActor.attach.js] [browser_dbg_WorkerActor.attach.js]

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

@ -0,0 +1,85 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
const TAB_URL = EXAMPLE_URL + "doc_worker-source-map.html";
const WORKER_URL = "code_worker-source-map.js";
const COFFEE_URL = EXAMPLE_URL + "code_worker-source-map.coffee";
function selectWorker(aPanel, aURL) {
let panelWin = aPanel.panelWin;
let promise = waitForDebuggerEvents(aPanel, panelWin.EVENTS.WORKER_SELECTED);
let Workers = panelWin.DebuggerView.Workers;
let item = Workers.getItemForAttachment((workerForm) => {
return workerForm.url === aURL;
});
Workers.selectedItem = item;
return promise;
}
function test() {
return Task.spawn(function* () {
yield pushPrefs(["devtools.debugger.workers", true]);
let [tab,, panel] = yield initDebugger(TAB_URL);
let toolbox = yield selectWorker(panel, WORKER_URL);
let workerPanel = toolbox.getCurrentPanel();
yield waitForSourceShown(workerPanel, ".coffee");
let panelWin = workerPanel.panelWin;
let Sources = panelWin.DebuggerView.Sources;
let editor = panelWin.DebuggerView.editor;
let threadClient = panelWin.gThreadClient;
isnot(Sources.selectedItem.attachment.source.url.indexOf(".coffee"), -1,
"The debugger should show the source mapped coffee source file.");
is(Sources.selectedValue.indexOf(".js"), -1,
"The debugger should not show the generated js source file.");
is(editor.getText().indexOf("isnt"), 211,
"The debugger's editor should have the coffee source source displayed.");
is(editor.getText().indexOf("function"), -1,
"The debugger's editor should not have the JS source displayed.");
yield threadClient.interrupt();
let sourceForm = getSourceForm(Sources, COFFEE_URL);
let source = threadClient.source(sourceForm);
let response = yield source.setBreakpoint({ line: 5 });
ok(!response.error,
"Should be able to set a breakpoint in a coffee source file.");
ok(!response.actualLocation,
"Should be able to set a breakpoint on line 5.");
let promise = new Promise((resolve) => {
threadClient.addOneTimeListener("paused", (event, packet) => {
is(packet.type, "paused",
"We should now be paused again.");
is(packet.why.type, "breakpoint",
"and the reason we should be paused is because we hit a breakpoint.");
// Check that we stopped at the right place, by making sure that the
// environment is in the state that we expect.
is(packet.frame.environment.bindings.variables.start.value, 0,
"'start' is 0.");
is(packet.frame.environment.bindings.variables.stop.value.type, "undefined",
"'stop' hasn't been assigned to yet.");
is(packet.frame.environment.bindings.variables.pivot.value.type, "undefined",
"'pivot' hasn't been assigned to yet.");
waitForCaretUpdated(workerPanel, 5).then(resolve);
});
});
// This will cause the breakpoint to be hit, and put us back in the
// paused state.
yield threadClient.resume();
callInTab(tab, "binary_search", [0, 2, 3, 5, 7, 10], 5);
yield promise;
yield threadClient.resume();
yield toolbox.destroy();
yield closeDebuggerAndFinish(panel);
yield popPrefs();
});
}

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

@ -0,0 +1,22 @@
# Uses a binary search algorithm to locate a value in the specified array.
binary_search = (items, value) ->
start = 0
stop = items.length - 1
pivot = Math.floor (start + stop) / 2
while items[pivot] isnt value and start < stop
# Adjust the search area.
stop = pivot - 1 if value < items[pivot]
start = pivot + 1 if value > items[pivot]
# Recalculate the pivot.
pivot = Math.floor (stop + start) / 2
# Make sure we've found the correct value.
if items[pivot] is value then pivot else -1
self.onmessage = (event) ->
data = event.data
binary_search(data.items, data.value)

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

@ -0,0 +1,35 @@
// Generated by CoffeeScript 1.10.0
(function() {
var binary_search;
binary_search = function(items, value) {
var pivot, start, stop;
start = 0;
stop = items.length - 1;
pivot = Math.floor((start + stop) / 2);
while (items[pivot] !== value && start < stop) {
if (value < items[pivot]) {
stop = pivot - 1;
}
if (value > items[pivot]) {
start = pivot + 1;
}
pivot = Math.floor((stop + start) / 2);
}
if (items[pivot] === value) {
return pivot;
} else {
return -1;
}
};
self.onmessage = function(event) {
console.log("EUTA");
var data;
data = event.data;
return binary_search(data.items, data.value);
};
}).call(this);
//# sourceMappingURL=code_worker-source-map.js.map

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

@ -0,0 +1,10 @@
{
"version": 3,
"file": "code_worker-source-map.js",
"sourceRoot": "",
"sources": [
"code_worker-source-map.coffee"
],
"names": [],
"mappings": ";AACA;AAAA,MAAA;;EAAA,aAAA,GAAgB,SAAC,KAAD,EAAQ,KAAR;AAEd,QAAA;IAAA,KAAA,GAAQ;IACR,IAAA,GAAQ,KAAK,CAAC,MAAN,GAAe;IACvB,KAAA,GAAQ,IAAI,CAAC,KAAL,CAAW,CAAC,KAAA,GAAQ,IAAT,CAAA,GAAiB,CAA5B;AAER,WAAM,KAAM,CAAA,KAAA,CAAN,KAAkB,KAAlB,IAA4B,KAAA,GAAQ,IAA1C;MAGE,IAAqB,KAAA,GAAQ,KAAM,CAAA,KAAA,CAAnC;QAAA,IAAA,GAAQ,KAAA,GAAQ,EAAhB;;MACA,IAAqB,KAAA,GAAQ,KAAM,CAAA,KAAA,CAAnC;QAAA,KAAA,GAAQ,KAAA,GAAQ,EAAhB;;MAGA,KAAA,GAAQ,IAAI,CAAC,KAAL,CAAW,CAAC,IAAA,GAAO,KAAR,CAAA,GAAiB,CAA5B;IAPV;IAUA,IAAG,KAAM,CAAA,KAAA,CAAN,KAAgB,KAAnB;aAA8B,MAA9B;KAAA,MAAA;aAAyC,CAAC,EAA1C;;EAhBc;;EAkBhB,IAAI,CAAC,SAAL,GAAiB,SAAC,KAAD;AACf,QAAA;IAAA,IAAA,GAAO,KAAK,CAAC;WACb,aAAA,CAAc,IAAI,CAAC,KAAnB,EAA0B,IAAI,CAAC,KAA/B;EAFe;AAlBjB"
}

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

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<script>
var worker = new Worker("code_worker-source-map.js");
function binary_search(items, value) {
worker.postMessage({
items: items,
value: value
});
}
</script>
</head>
<body>
</body>
</html>

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

@ -28,22 +28,24 @@ WorkersView.prototype = Heritage.extend(WidgetMethods, {
this.widget.addEventListener("select", this._onWorkerSelect, false); this.widget.addEventListener("select", this._onWorkerSelect, false);
}, },
addWorker: function (actor, name) { addWorker: function (workerForm) {
let element = document.createElement("label"); let element = document.createElement("label");
element.className = "plain dbg-worker-item"; element.className = "plain dbg-worker-item";
element.setAttribute("value", name); element.setAttribute("value", workerForm.url);
element.setAttribute("flex", "1"); element.setAttribute("flex", "1");
this.push([element, actor], {}); this.push([element, workerForm.actor], {
attachment: workerForm
});
}, },
removeWorker: function (actor) { removeWorker: function (workerForm) {
this.remove(this.getItemByValue(actor)); this.remove(this.getItemByValue(workerForm.actor));
}, },
_onWorkerSelect: function () { _onWorkerSelect: function () {
if (this.selectedItem !== null) { if (this.selectedItem !== null) {
DebuggerController.Workers._onWorkerSelect(this.selectedItem.value); DebuggerController.Workers._onWorkerSelect(this.selectedItem.attachment);
this.selectedItem = null; this.selectedItem = null;
} }
} }

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

@ -912,6 +912,10 @@ Toolbox.prototype = {
if (!this.target.hasActor("gcli")) { if (!this.target.hasActor("gcli")) {
return promise.resolve(); return promise.resolve();
} }
// Disable gcli in browser toolbox until there is usages of it
if (this.target.chrome) {
return promise.resolve();
}
const options = { const options = {
environment: CommandUtils.createEnvironment(this, '_target') environment: CommandUtils.createEnvironment(this, '_target')

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

@ -233,7 +233,15 @@ Telemetry.prototype = {
histogram: "DEVTOOLS_CUSTOM_OPENED_COUNT", histogram: "DEVTOOLS_CUSTOM_OPENED_COUNT",
userHistogram: "DEVTOOLS_CUSTOM_OPENED_PER_USER_FLAG", userHistogram: "DEVTOOLS_CUSTOM_OPENED_PER_USER_FLAG",
timerHistogram: "DEVTOOLS_CUSTOM_TIME_ACTIVE_SECONDS" timerHistogram: "DEVTOOLS_CUSTOM_TIME_ACTIVE_SECONDS"
} },
reloadAddonInstalled: {
histogram: "DEVTOOLS_RELOAD_ADDON_INSTALLED_COUNT",
userHistogram: "DEVTOOLS_RELOAD_ADDON_INSTALLED_PER_USER_FLAG",
},
reloadAddonReload: {
histogram: "DEVTOOLS_RELOAD_ADDON_RELOAD_COUNT",
userHistogram: "DEVTOOLS_RELOAD_ADDON_RELOAD_PER_USER_FLAG",
},
}, },
/** /**

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

@ -1150,6 +1150,8 @@ public final class BrowserDatabaseHelper extends SQLiteOpenHelper {
upgradeDatabaseFrom25to26(db); upgradeDatabaseFrom25to26(db);
break; break;
// case 27 occurs in UrlMetadataTable.onUpgrade
case 28: case 28:
upgradeDatabaseFrom27to28(db); upgradeDatabaseFrom27to28(db);
break; break;

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

@ -12,6 +12,7 @@ import java.util.Map;
import org.mozilla.gecko.AboutPages; import org.mozilla.gecko.AboutPages;
import org.mozilla.gecko.GeckoProfile; import org.mozilla.gecko.GeckoProfile;
import org.mozilla.gecko.R;
import org.mozilla.gecko.db.BrowserContract.Bookmarks; import org.mozilla.gecko.db.BrowserContract.Bookmarks;
import org.mozilla.gecko.db.BrowserContract.Combined; import org.mozilla.gecko.db.BrowserContract.Combined;
import org.mozilla.gecko.db.BrowserContract.FaviconColumns; import org.mozilla.gecko.db.BrowserContract.FaviconColumns;
@ -694,21 +695,25 @@ public class BrowserProvider extends SharedBrowserDatabaseProvider {
final String TABLE_TOPSITES = "topsites"; final String TABLE_TOPSITES = "topsites";
final String totalLimit = uri.getQueryParameter(BrowserContract.PARAM_LIMIT); final String limitParam = uri.getQueryParameter(BrowserContract.PARAM_LIMIT);
final String suggestedGridLimit = uri.getQueryParameter(BrowserContract.PARAM_SUGGESTEDSITES_LIMIT); final String gridLimitParam = uri.getQueryParameter(BrowserContract.PARAM_SUGGESTEDSITES_LIMIT);
final String[] suggestedGridLimitArgs = new String[] { final int totalLimit;
suggestedGridLimit final int suggestedGridLimit;
};
final String[] totalLimitArgs = new String[] { if (limitParam == null) {
totalLimit totalLimit = 50;
}; } else {
totalLimit = Integer.parseInt(limitParam, 10);
}
final String pinnedSitesFromClause = "FROM " + TABLE_BOOKMARKS + " WHERE " + Bookmarks.PARENT + " == ?"; if (gridLimitParam == null) {
final String[] pinnedSitesArgs = new String[] { suggestedGridLimit = getContext().getResources().getInteger(R.integer.number_of_top_sites);
String.valueOf(Bookmarks.FIXED_PINNED_LIST_ID) } else {
}; suggestedGridLimit = Integer.parseInt(gridLimitParam, 10);
}
final String pinnedSitesFromClause = "FROM " + TABLE_BOOKMARKS + " WHERE " + Bookmarks.PARENT + " == " + Bookmarks.FIXED_PINNED_LIST_ID;
// Ideally we'd use a recursive CTE to generate our sequence, e.g. something like this worked at one point: // Ideally we'd use a recursive CTE to generate our sequence, e.g. something like this worked at one point:
// " WITH RECURSIVE" + // " WITH RECURSIVE" +
@ -725,12 +730,7 @@ public class BrowserProvider extends SharedBrowserDatabaseProvider {
" ON numbers.position > free_ids.position" + " ON numbers.position > free_ids.position" +
" GROUP BY numbers.position" + " GROUP BY numbers.position" +
" ORDER BY numbers.position ASC" + " ORDER BY numbers.position ASC" +
" LIMIT ?"; " LIMIT " + suggestedGridLimit;
final String[] freeIDArgs = DBUtils.concatenateSelectionArgs(
pinnedSitesArgs,
pinnedSitesArgs,
suggestedGridLimitArgs);
// Filter out: unvisited pages (history_id == -1) pinned (and other special) sites, deleted sites, // Filter out: unvisited pages (history_id == -1) pinned (and other special) sites, deleted sites,
// and about: pages. // and about: pages.
@ -739,17 +739,15 @@ public class BrowserProvider extends SharedBrowserDatabaseProvider {
" AND " + " AND " +
Combined.URL + " NOT IN (SELECT " + Combined.URL + " NOT IN (SELECT " +
Bookmarks.URL + " FROM bookmarks WHERE " + Bookmarks.URL + " FROM bookmarks WHERE " +
DBUtils.qualifyColumn("bookmarks", Bookmarks.PARENT) + " < ? AND " + DBUtils.qualifyColumn("bookmarks", Bookmarks.PARENT) + " < " + Bookmarks.FIXED_ROOT_ID + " AND " +
DBUtils.qualifyColumn("bookmarks", Bookmarks.IS_DELETED) + " == 0)" + DBUtils.qualifyColumn("bookmarks", Bookmarks.IS_DELETED) + " == 0)" +
" AND " + " AND " +
"(" + Combined.URL + " NOT LIKE ?)"; "(" + Combined.URL + " NOT LIKE ?)";
final String[] ignoreForTopSitesArgs = new String[] { final String[] ignoreForTopSitesArgs = new String[] {
String.valueOf(Bookmarks.FIXED_ROOT_ID),
AboutPages.URL_FILTER AboutPages.URL_FILTER
}; };
// Stuff the suggested sites into SQL: this allows us to filter pinned and topsites out of the suggested // Stuff the suggested sites into SQL: this allows us to filter pinned and topsites out of the suggested
// sites list as part of the final query (as opposed to walking cursors in java) // sites list as part of the final query (as opposed to walking cursors in java)
final SuggestedSites suggestedSites = GeckoProfile.get(getContext(), uri.getQueryParameter(BrowserContract.PARAM_PROFILE)).getDB().getSuggestedSites(); final SuggestedSites suggestedSites = GeckoProfile.get(getContext(), uri.getQueryParameter(BrowserContract.PARAM_PROFILE)).getDB().getSuggestedSites();
@ -759,7 +757,7 @@ public class BrowserProvider extends SharedBrowserDatabaseProvider {
// sites list, which means we'd need to process the lists within SuggestedSites in any case. If we're doing // sites list, which means we'd need to process the lists within SuggestedSites in any case. If we're doing
// that processing, there is little real between us using a MatrixCursor, or a Map (or List) instead of the // that processing, there is little real between us using a MatrixCursor, or a Map (or List) instead of the
// MatrixCursor. // MatrixCursor.
final Cursor suggestedSitesCursor = suggestedSites.get(Integer.parseInt(suggestedGridLimit)); final Cursor suggestedSitesCursor = suggestedSites.get(suggestedGridLimit);
String[] suggestedSiteArgs = new String[0]; String[] suggestedSiteArgs = new String[0];
@ -791,11 +789,8 @@ public class BrowserProvider extends SharedBrowserDatabaseProvider {
// To restrict suggested sites to the grid, we simply subtract the number of topsites (which have already had // To restrict suggested sites to the grid, we simply subtract the number of topsites (which have already had
// the pinned sites filtered out), and the number of pinned sites. // the pinned sites filtered out), and the number of pinned sites.
// SQLite completely ignores negative limits, hence we need to manually totalLimit to 0 in this case. // SQLite completely ignores negative limits, hence we need to manually limit to 0 in this case.
final String suggestedLimitClause = " LIMIT MAX(0, (? - (SELECT COUNT(*) FROM " + TABLE_TOPSITES + ") - (SELECT COUNT(*) " + pinnedSitesFromClause + "))) "; final String suggestedLimitClause = " LIMIT MAX(0, (" + suggestedGridLimit + " - (SELECT COUNT(*) FROM " + TABLE_TOPSITES + ") - (SELECT COUNT(*) " + pinnedSitesFromClause + "))) ";
final String[] suggestedLimitArgs = DBUtils.concatenateSelectionArgs(suggestedGridLimitArgs,
pinnedSitesArgs);
db.beginTransaction(); db.beginTransaction();
try { try {
@ -813,10 +808,9 @@ public class BrowserProvider extends SharedBrowserDatabaseProvider {
" FROM " + Combined.VIEW_NAME + " FROM " + Combined.VIEW_NAME +
" WHERE " + ignoreForTopSitesWhereClause + " WHERE " + ignoreForTopSitesWhereClause +
" ORDER BY " + BrowserContract.getFrecencySortOrder(true, false) + " ORDER BY " + BrowserContract.getFrecencySortOrder(true, false) +
" LIMIT ?", " LIMIT " + totalLimit,
DBUtils.appendSelectionArgs(ignoreForTopSitesArgs, ignoreForTopSitesArgs);
totalLimitArgs));
if (!hasProcessedAnySuggestedSites) { if (!hasProcessedAnySuggestedSites) {
db.execSQL("INSERT INTO " + TABLE_TOPSITES + db.execSQL("INSERT INTO " + TABLE_TOPSITES +
@ -838,11 +832,17 @@ public class BrowserProvider extends SharedBrowserDatabaseProvider {
Bookmarks.URL + " NOT IN (SELECT url " + pinnedSitesFromClause + ")" + Bookmarks.URL + " NOT IN (SELECT url " + pinnedSitesFromClause + ")" +
suggestedLimitClause + " )", suggestedLimitClause + " )",
DBUtils.concatenateSelectionArgs(suggestedSiteArgs, suggestedSiteArgs);
pinnedSitesArgs,
suggestedLimitArgs));
} }
// If we retrieve more topsites than we have free positions for in the freeIdSubquery,
// we will have topsites that don't receive a position when joining TABLE_TOPSITES
// with freeIdSubquery. Hence we need to coalesce the position with a generated position.
// We know that the difference in positions will be at most suggestedGridLimit, hence we
// can add that to the rowid to generate a safe position.
// I.e. if we have 6 pinned sites then positions 0..5 are filled, the JOIN results in
// the first N rows having positions 6..(N+6), so row N+1 should receive a position that is at
// least N+1+6, which is equal to rowid + 6.
final SQLiteCursor c = (SQLiteCursor) db.rawQuery( final SQLiteCursor c = (SQLiteCursor) db.rawQuery(
"SELECT " + "SELECT " +
Bookmarks._ID + ", " + Bookmarks._ID + ", " +
@ -850,7 +850,9 @@ public class BrowserProvider extends SharedBrowserDatabaseProvider {
TopSites.HISTORY_ID + ", " + TopSites.HISTORY_ID + ", " +
Bookmarks.URL + ", " + Bookmarks.URL + ", " +
Bookmarks.TITLE + ", " + Bookmarks.TITLE + ", " +
Bookmarks.POSITION + ", " + "COALESCE(" + Bookmarks.POSITION + ", " +
DBUtils.qualifyColumn(TABLE_TOPSITES, "rowid") + " + " + suggestedGridLimit +
")" + " AS " + Bookmarks.POSITION + ", " +
Combined.HISTORY_ID + ", " + Combined.HISTORY_ID + ", " +
TopSites.TYPE + TopSites.TYPE +
" FROM " + TABLE_TOPSITES + " FROM " + TABLE_TOPSITES +
@ -871,12 +873,11 @@ public class BrowserProvider extends SharedBrowserDatabaseProvider {
"NULL AS " + Combined.HISTORY_ID + ", " + "NULL AS " + Combined.HISTORY_ID + ", " +
TopSites.TYPE_PINNED + " as " + TopSites.TYPE + TopSites.TYPE_PINNED + " as " + TopSites.TYPE +
" FROM " + TABLE_BOOKMARKS + " FROM " + TABLE_BOOKMARKS +
" WHERE " + Bookmarks.PARENT + " == ? " + " WHERE " + Bookmarks.PARENT + " == " + Bookmarks.FIXED_PINNED_LIST_ID +
" ORDER BY " + Bookmarks.POSITION, " ORDER BY " + Bookmarks.POSITION,
DBUtils.appendSelectionArgs(freeIDArgs, null);
pinnedSitesArgs));
c.setNotificationUri(getContext().getContentResolver(), c.setNotificationUri(getContext().getContentResolver(),
BrowserContract.AUTHORITY_URI); BrowserContract.AUTHORITY_URI);

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

@ -18,6 +18,7 @@ import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import org.mozilla.gecko.GeckoAppShell; import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.Telemetry; import org.mozilla.gecko.Telemetry;
import org.mozilla.gecko.favicons.Favicons;
import org.mozilla.gecko.util.ThreadUtils; import org.mozilla.gecko.util.ThreadUtils;
import android.content.ContentResolver; import android.content.ContentResolver;
@ -79,7 +80,6 @@ public class LocalURLMetadata implements URLMetadata {
if (obj.has("touchIconList") && if (obj.has("touchIconList") &&
(icons = obj.getJSONObject("touchIconList")).length() > 0) { (icons = obj.getJSONObject("touchIconList")).length() > 0) {
int preferredSize = GeckoAppShell.getPreferredIconSize(); int preferredSize = GeckoAppShell.getPreferredIconSize();
int bestSizeFound = -1;
Iterator<String> keys = icons.keys(); Iterator<String> keys = icons.keys();
@ -88,21 +88,8 @@ public class LocalURLMetadata implements URLMetadata {
sizes.add(new Integer(keys.next())); sizes.add(new Integer(keys.next()));
} }
Collections.sort(sizes); final int bestSize = Favicons.selectBestSizeFromList(sizes, preferredSize);
for (int size : sizes) { final String iconURL = icons.getString(Integer.toString(bestSize));
if (size >= preferredSize) {
bestSizeFound = size;
break;
}
}
// If all icons are smaller than the preferred size then we don't have an icon
// selected yet (bestSizeFound == -1), therefore just take the largest (last) icon.
if (bestSizeFound == -1) {
bestSizeFound = sizes.get(sizes.size() - 1);
}
String iconURL = icons.getString(Integer.toString(bestSizeFound));
data.put(URLMetadataTable.TOUCH_ICON_COLUMN, iconURL); data.put(URLMetadataTable.TOUCH_ICON_COLUMN, iconURL);
} }

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

@ -144,6 +144,32 @@ public class Favicons {
private static FaviconCache faviconsCache; private static FaviconCache faviconsCache;
/**
* Select the closest icon size from a list of icon sizes.
* We just find the first icon that is larger than the preferred size if available, or otherwise select the
* largest icon (if all icons are smaller than the preferred size).
*
* @return The closes icon size, or -1 if no sizes are supplied.
*/
public static int selectBestSizeFromList(final List<Integer> sizes, final int preferredSize) {
Collections.sort(sizes);
for (int size : sizes) {
if (size >= preferredSize) {
return size;
}
}
// If all icons are smaller than the preferred size then we don't have an icon
// selected yet, therefore just take the largest (last) icon.
if (sizes.size() > 0) {
return sizes.get(sizes.size() - 1);
} else {
// This isn't ideal, however current code assumes this as an error value for now.
return -1;
}
}
/** /**
* Returns either NOT_LOADING, or LOADED if the onFaviconLoaded call could * Returns either NOT_LOADING, or LOADED if the onFaviconLoaded call could
* be made on the main thread. * be made on the main thread.
@ -584,6 +610,6 @@ public class Favicons {
*/ */
public static void getPreferredSizeFaviconForPage(Context context, String url, String iconURL, OnFaviconLoadedListener onFaviconLoadedListener) { public static void getPreferredSizeFaviconForPage(Context context, String url, String iconURL, OnFaviconLoadedListener onFaviconLoadedListener) {
int preferredSize = GeckoAppShell.getPreferredIconSize(); int preferredSize = GeckoAppShell.getPreferredIconSize();
loadUncachedFavicon(context, url, iconURL, 0, preferredSize, onFaviconLoadedListener); loadUncachedFavicon(context, url, iconURL, LoadFaviconTask.FLAG_BYPASS_CACHE_WHEN_DOWNLOADING_ICONS, preferredSize, onFaviconLoadedListener);
} }
} }

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

@ -25,12 +25,14 @@ import org.mozilla.gecko.util.IOUtils;
import org.mozilla.gecko.util.ThreadUtils; import org.mozilla.gecko.util.ThreadUtils;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
@ -50,6 +52,14 @@ public class LoadFaviconTask {
private static final HashMap<String, LoadFaviconTask> loadsInFlight = new HashMap<>(); private static final HashMap<String, LoadFaviconTask> loadsInFlight = new HashMap<>();
public static final int FLAG_PERSIST = 1; public static final int FLAG_PERSIST = 1;
/**
* Bypass all caches - this is used to directly retrieve the requested icon. Without this flag,
* favicons will first be pushed into the memory cache (and possibly permanent cache if using FLAG_PERSIST),
* where they will be downscaled to the maximum cache size, before being retrieved from the cache (resulting
* in a possibly smaller icon size).
*/
public static final int FLAG_BYPASS_CACHE_WHEN_DOWNLOADING_ICONS = 2;
private static final int MAX_REDIRECTS_TO_FOLLOW = 5; private static final int MAX_REDIRECTS_TO_FOLLOW = 5;
// The default size of the buffer to use for downloading Favicons in the event no size is given // The default size of the buffer to use for downloading Favicons in the event no size is given
// by the server. // by the server.
@ -417,10 +427,13 @@ public class LoadFaviconTask {
return null; return null;
} }
LoadFaviconResult loadedBitmaps = null;
// If there are no valid bitmaps decoded, the returned LoadFaviconResult is null. // If there are no valid bitmaps decoded, the returned LoadFaviconResult is null.
LoadFaviconResult loadedBitmaps = loadFaviconFromDb(db); if ((flags & FLAG_BYPASS_CACHE_WHEN_DOWNLOADING_ICONS) == 0) {
if (loadedBitmaps != null) { loadedBitmaps = loadFaviconFromDb(db);
return pushToCacheAndGetResult(loadedBitmaps); if (loadedBitmaps != null) {
return pushToCacheAndGetResult(loadedBitmaps);
}
} }
if (onlyFromLocal || isCancelled()) { if (onlyFromLocal || isCancelled()) {
@ -445,11 +458,25 @@ public class LoadFaviconTask {
} }
if (loadedBitmaps != null) { if (loadedBitmaps != null) {
// Fetching bytes to store can fail. saveFaviconToDb will if ((flags & FLAG_BYPASS_CACHE_WHEN_DOWNLOADING_ICONS) == 0) {
// do the right thing, but we still choose to cache the // Fetching bytes to store can fail. saveFaviconToDb will
// downloaded icon in memory. // do the right thing, but we still choose to cache the
saveFaviconToDb(db, loadedBitmaps.getBytesForDatabaseStorage()); // downloaded icon in memory.
return pushToCacheAndGetResult(loadedBitmaps); saveFaviconToDb(db, loadedBitmaps.getBytesForDatabaseStorage());
return pushToCacheAndGetResult(loadedBitmaps);
} else {
final Map<Integer, Bitmap> iconMap = new HashMap<>();
final List<Integer> sizes = new ArrayList<>();
while (loadedBitmaps.getBitmaps().hasNext()) {
final Bitmap b = loadedBitmaps.getBitmaps().next();
iconMap.put(b.getWidth(), b);
sizes.add(b.getWidth());
}
int bestSize = Favicons.selectBestSizeFromList(sizes, targetWidth);
return iconMap.get(bestSize);
}
} }
if (isUsingDefaultURL) { if (isUsingDefaultURL) {
@ -545,11 +572,15 @@ public class LoadFaviconTask {
private void processResult(Bitmap image) { private void processResult(Bitmap image) {
Favicons.removeLoadTask(id); Favicons.removeLoadTask(id);
Bitmap scaled = image; final Bitmap scaled;
// Notify listeners, scaling if required. // Notify listeners, scaling if required.
if (targetWidth != -1 && image != null && image.getWidth() != targetWidth) { if ((flags & FLAG_BYPASS_CACHE_WHEN_DOWNLOADING_ICONS) != 0) {
scaled = Bitmap.createScaledBitmap(image, targetWidth, targetWidth, true);
} else if (targetWidth != -1 && image != null && image.getWidth() != targetWidth) {
scaled = Favicons.getSizedFaviconFromCache(faviconURL, targetWidth); scaled = Favicons.getSizedFaviconFromCache(faviconURL, targetWidth);
} else {
scaled = image;
} }
Favicons.dispatchResult(pageUrl, faviconURL, scaled, listener); Favicons.dispatchResult(pageUrl, faviconURL, scaled, listener);

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

@ -25,6 +25,7 @@ import android.text.TextUtils;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.Gravity; import android.view.Gravity;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.widget.ImageView;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
@ -35,9 +36,9 @@ public class TwoLinePageRow extends LinearLayout
private final TextView mTitle; private final TextView mTitle;
private final TextView mUrl; private final TextView mUrl;
private final ImageView mStatusIcon;
private int mSwitchToTabIconId; private int mSwitchToTabIconId;
private int mPageTypeIconId;
private final FaviconView mFavicon; private final FaviconView mFavicon;
@ -90,11 +91,14 @@ public class TwoLinePageRow extends LinearLayout
setGravity(Gravity.CENTER_VERTICAL); setGravity(Gravity.CENTER_VERTICAL);
LayoutInflater.from(context).inflate(R.layout.two_line_page_row, this); LayoutInflater.from(context).inflate(R.layout.two_line_page_row, this);
// Merge layouts lose their padding, so set it dynamically.
setPadding(0, 0, (int) getResources().getDimension(R.dimen.page_row_padding_right), 0);
mTitle = (TextView) findViewById(R.id.title); mTitle = (TextView) findViewById(R.id.title);
mUrl = (TextView) findViewById(R.id.url); mUrl = (TextView) findViewById(R.id.url);
mStatusIcon = (ImageView) findViewById(R.id.status_icon_bookmark);
mSwitchToTabIconId = NO_ICON; mSwitchToTabIconId = NO_ICON;
mPageTypeIconId = NO_ICON;
mShowIcons = true; mShowIcons = true;
mFavicon = (FaviconView) findViewById(R.id.icon); mFavicon = (FaviconView) findViewById(R.id.icon);
@ -173,16 +177,12 @@ public class TwoLinePageRow extends LinearLayout
} }
mSwitchToTabIconId = iconId; mSwitchToTabIconId = iconId;
mUrl.setCompoundDrawablesWithIntrinsicBounds(mSwitchToTabIconId, 0, mPageTypeIconId, 0); mUrl.setCompoundDrawablesWithIntrinsicBounds(mSwitchToTabIconId, 0, 0, 0);
} }
private void setPageTypeIcon(int iconId) { private void showBookmarkIcon(boolean toShow) {
if (mPageTypeIconId == iconId) { final int visibility = toShow ? VISIBLE : GONE;
return; mStatusIcon.setVisibility(visibility);
}
mPageTypeIconId = iconId;
mUrl.setCompoundDrawablesWithIntrinsicBounds(mSwitchToTabIconId, 0, mPageTypeIconId, 0);
} }
/** /**
@ -231,13 +231,10 @@ public class TwoLinePageRow extends LinearLayout
if (mShowIcons) { if (mShowIcons) {
// The bookmark id will be 0 (null in database) when the url // The bookmark id will be 0 (null in database) when the url
// is not a bookmark. // is not a bookmark.
if (bookmarkId == 0) { final boolean isBookmark = bookmarkId != 0;
setPageTypeIcon(NO_ICON); showBookmarkIcon(isBookmark);
} else {
setPageTypeIcon(R.drawable.ic_url_bar_star);
}
} else { } else {
setPageTypeIcon(NO_ICON); showBookmarkIcon(false);
} }
// Use the URL instead of an empty title for consistency with the normal URL // Use the URL instead of an empty title for consistency with the normal URL

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 277 B

Двоичные данные
mobile/android/base/resources/drawable-nodpi/bookmarked_star.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 600 B

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 368 B

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

@ -14,29 +14,38 @@
android:layout_margin="16dp" android:layout_margin="16dp"
tools:background="@drawable/favicon_globe"/> tools:background="@drawable/favicon_globe"/>
<LinearLayout android:layout_width="match_parent" <LinearLayout android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
android:orientation="vertical" android:paddingRight="10dp"
android:paddingRight="25dp"> android:orientation="vertical">
<org.mozilla.gecko.widget.FadedSingleColorTextView <org.mozilla.gecko.widget.FadedSingleColorTextView
android:id="@+id/title" android:id="@+id/title"
style="@style/Widget.TwoLinePageRow.Title" style="@style/Widget.TwoLinePageRow.Title"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
gecko:fadeWidth="30dp" gecko:fadeWidth="90dp"
tools:text="This is a long test title"/> tools:text="This is a long test title"/>
<TextView android:id="@+id/url" <org.mozilla.gecko.widget.FadedSingleColorTextView android:id="@+id/url"
style="@style/Widget.TwoLinePageRow.Url" style="@style/Widget.TwoLinePageRow.Url"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:drawablePadding="5dp" android:drawablePadding="5dp"
android:maxLength="1024" android:maxLength="1024"
gecko:fadeWidth="90dp"
tools:text="http://test.com/test" tools:text="http://test.com/test"
tools:drawableLeft="@drawable/ic_url_bar_tab" tools:drawableLeft="@drawable/ic_url_bar_tab"/>
tools:drawableRight="@drawable/ic_url_bar_star"/>
</LinearLayout> </LinearLayout>
<ImageView android:id="@+id/status_icon_bookmark"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_gravity="center"
android:visibility="gone"
android:src="@drawable/bookmarked_star"/>
</merge> </merge>

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

@ -79,6 +79,8 @@
<dimen name="site_security_unknown_inset_top">1dp</dimen> <dimen name="site_security_unknown_inset_top">1dp</dimen>
<dimen name="site_security_unknown_inset_bottom">-1dp</dimen> <dimen name="site_security_unknown_inset_bottom">-1dp</dimen>
<dimen name="page_row_padding_right">15dp</dimen>
<!-- Regular page row on about:home --> <!-- Regular page row on about:home -->
<dimen name="page_row_height">64dp</dimen> <dimen name="page_row_height">64dp</dimen>

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

@ -126,7 +126,6 @@
<item name="android:textAppearance">@style/TextAppearance.Widget.Home.ItemDescription</item> <item name="android:textAppearance">@style/TextAppearance.Widget.Home.ItemDescription</item>
<item name="android:includeFontPadding">false</item> <item name="android:includeFontPadding">false</item>
<item name="android:singleLine">true</item> <item name="android:singleLine">true</item>
<item name="android:ellipsize">middle</item>
</style> </style>
<style name="Widget.ReadingListRow" /> <style name="Widget.ReadingListRow" />
@ -413,7 +412,9 @@
<item name="android:textColor">?android:attr/textColorPrimary</item> <item name="android:textColor">?android:attr/textColorPrimary</item>
</style> </style>
<style name="TextAppearance.Widget.Home.ItemTitle" parent="TextAppearance.Medium"/> <style name="TextAppearance.Widget.Home.ItemTitle" parent="TextAppearance">
<item name="android:textSize">16dp</item>
</style>
<style name="TextAppearance.Widget.Home.ItemDescription" parent="TextAppearance.Micro"> <style name="TextAppearance.Widget.Home.ItemDescription" parent="TextAppearance.Micro">
<item name="android:textColor">@color/tabs_tray_icon_grey</item> <item name="android:textColor">@color/tabs_tray_icon_grey</item>

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

@ -63,8 +63,9 @@ var ActionBarHandler = {
// Else, update an open ActionBar. // Else, update an open ActionBar.
if (this._selectionID) { if (this._selectionID) {
if ([this._targetElement, this._contentWindow] === let [element, win] = this._getSelectionTargets();
[Services.focus.focusedElement, Services.focus.focusedWindow]) { if (this._targetElement === element &&
this._contentWindow === win) {
// We have the same focused window/element as before. Trigger "TextSelection:ActionbarStatus" // We have the same focused window/element as before. Trigger "TextSelection:ActionbarStatus"
// message only if available actions differ from when last we checked. // message only if available actions differ from when last we checked.
this._sendActionBarActions(); this._sendActionBarActions();
@ -225,8 +226,14 @@ var ActionBarHandler = {
*/ */
_sendActionBarActions: function(sendAlways) { _sendActionBarActions: function(sendAlways) {
let actions = this._getActionBarActions(); let actions = this._getActionBarActions();
let actionCountUnchanged = this._actionBarActions &&
actions.length === this._actionBarActions.length;
let actionsMatch = actionCountUnchanged &&
this._actionBarActions.every((e,i) => {
return e.id === actions[i].id;
});
if (sendAlways || actions !== this._actionBarActions) { if (sendAlways || !actionsMatch) {
Messaging.sendRequest({ Messaging.sendRequest({
type: "TextSelection:ActionbarStatus", type: "TextSelection:ActionbarStatus",
actions: actions, actions: actions,

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

@ -208,6 +208,9 @@ let SyncedTabsInternal = {
Preferences.reset("services.sync.lastTabFetch"); Preferences.reset("services.sync.lastTabFetch");
Services.obs.notifyObservers(null, TOPIC_TABS_CHANGED, null); Services.obs.notifyObservers(null, TOPIC_TABS_CHANGED, null);
break; break;
case "nsPref:changed":
Services.obs.notifyObservers(null, TOPIC_TABS_CHANGED, null);
break;
default: default:
break; break;
} }
@ -232,6 +235,10 @@ let SyncedTabsInternal = {
Services.obs.addObserver(SyncedTabsInternal, "weave:engine:sync:finish", false); Services.obs.addObserver(SyncedTabsInternal, "weave:engine:sync:finish", false);
Services.obs.addObserver(SyncedTabsInternal, "weave:service:start-over", false); Services.obs.addObserver(SyncedTabsInternal, "weave:service:start-over", false);
// Observe the pref the indicates the state of the tabs engine has changed.
// This will force consumers to re-evaluate the state of sync and update
// accordingly.
Services.prefs.addObserver("services.sync.engine.tabs", SyncedTabsInternal, false);
// The public interface. // The public interface.
this.SyncedTabs = { this.SyncedTabs = {

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

@ -591,6 +591,27 @@ this.BrowserTestUtils = {
}); });
}, },
/**
* Wait for a message to be fired from a particular message manager
*
* @param {nsIMessageManager} messageManager
* The message manager that should be used.
* @param {String} message
* The message we're waiting for.
* @param {Function} checkFn (optional)
* Optional function to invoke to check the message.
*/
waitForMessage(messageManager, message, checkFn) {
return new Promise(resolve => {
messageManager.addMessageListener(message, function onMessage(msg) {
if (!checkFn || checkFn(msg)) {
messageManager.removeMessageListener(message, onMessage);
resolve();
}
});
});
},
/** /**
* Version of synthesizeMouse that uses the center of the target as the mouse * Version of synthesizeMouse that uses the center of the target as the mouse
* location. Arguments and the return value are the same. * location. Arguments and the return value are the same.

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

@ -7021,6 +7021,20 @@
"description": "Number of times a custom developer tool has been opened.", "description": "Number of times a custom developer tool has been opened.",
"releaseChannelCollection": "opt-out" "releaseChannelCollection": "opt-out"
}, },
"DEVTOOLS_RELOAD_ADDON_INSTALLED_COUNT": {
"alert_emails": ["dev-developer-tools@lists.mozilla.org"],
"expires_in_version": "55",
"kind": "count",
"description": "Number of times the reload addon has been installed.",
"bug_numbers": [1248435]
},
"DEVTOOLS_RELOAD_ADDON_RELOAD_COUNT": {
"alert_emails": ["dev-developer-tools@lists.mozilla.org"],
"expires_in_version": "55",
"kind": "count",
"description": "Number of times the tools have been reloaded by the reload addon.",
"bug_numbers": [1248435]
},
"DEVTOOLS_TOOLBOX_OPENED_PER_USER_FLAG": { "DEVTOOLS_TOOLBOX_OPENED_PER_USER_FLAG": {
"expires_in_version": "never", "expires_in_version": "never",
"kind": "flag", "kind": "flag",
@ -7204,6 +7218,20 @@
"kind": "flag", "kind": "flag",
"description": "Number of users that have opened a custom developer tool via the toolbox button." "description": "Number of users that have opened a custom developer tool via the toolbox button."
}, },
"DEVTOOLS_RELOAD_ADDON_INSTALLED_PER_USER_FLAG": {
"alert_emails": ["dev-developer-tools@lists.mozilla.org"],
"expires_in_version": "55",
"kind": "flag",
"description": "Records once per browser version if the reload add-on is installed.",
"bug_numbers": [1248435]
},
"DEVTOOLS_RELOAD_ADDON_RELOAD_PER_USER_FLAG": {
"alert_emails": ["dev-developer-tools@lists.mozilla.org"],
"expires_in_version": "55",
"kind": "flag",
"description": "Records once per browser version if the tools have been reloaded via the reload add-on.",
"bug_numbers": [1248435]
},
"DEVTOOLS_TOOLBOX_TIME_ACTIVE_SECONDS": { "DEVTOOLS_TOOLBOX_TIME_ACTIVE_SECONDS": {
"expires_in_version": "never", "expires_in_version": "never",
"kind": "exponential", "kind": "exponential",
@ -8452,6 +8480,15 @@
"releaseChannelCollection": "opt-out", "releaseChannelCollection": "opt-out",
"description": "Number of sessions where at least one chat message was exchanged" "description": "Number of sessions where at least one chat message was exchanged"
}, },
"LOOP_INFOBAR_ACTION_BUTTONS": {
"alert_emails": ["firefox-dev@mozilla.org", "mbanner@mozilla.com"],
"expires_in_version": "51",
"kind": "enumerated",
"n_values": 4,
"releaseChannelCollection": "opt-out",
"bug_numbers": [1245486],
"description": "Number times info bar buttons are clicked (0=PAUSED, 1=CREATED)"
},
"E10S_STATUS": { "E10S_STATUS": {
"alert_emails": ["firefox-dev@mozilla.org"], "alert_emails": ["firefox-dev@mozilla.org"],
"expires_in_version": "never", "expires_in_version": "never",

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

@ -0,0 +1,38 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
function doUpdate(update) {
const { classes: Cc, interfaces: Ci, results: Cr } = Components;
let listener = {
QueryInterface: function(iid)
{
if (iid.equals(Ci.nsISupports) ||
iid.equals(Ci.nsIUrlClassifierUpdateObserver))
return this;
throw Cr.NS_ERROR_NO_INTERFACE;
},
updateUrlRequested: function(url) { },
streamFinished: function(status) { },
updateError: function(errorCode) {
sendAsyncMessage("updateError", { errorCode });
},
updateSuccess: function(requestedTimeout) {
sendAsyncMessage("loadTestFrame");
}
};
let dbService = Cc["@mozilla.org/url-classifier/dbservice;1"]
.getService(Ci.nsIUrlClassifierDBService);
dbService.beginUpdate(listener, "test-malware-simple,test-unwanted-simple", "");
dbService.beginStream("", "");
dbService.updateStream(update);
dbService.finishStream();
dbService.finishUpdate();
}
addMessageListener("doUpdate", ({ testUpdate }) => {
doUpdate(testUpdate);
});

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

@ -1,7 +1,8 @@
[DEFAULT] [DEFAULT]
skip-if = buildapp == 'b2g' || e10s skip-if = buildapp == 'b2g'
support-files = support-files =
classifiedAnnotatedPBFrame.html classifiedAnnotatedPBFrame.html
classifierCommon.js
classifierFrame.html classifierFrame.html
cleanWorker.js cleanWorker.js
good.js good.js

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

@ -13,8 +13,6 @@
<script class="testbody" type="text/javascript"> <script class="testbody" type="text/javascript">
var Cc = SpecialPowers.Cc;
var Ci = SpecialPowers.Ci;
var firstLoad = true; var firstLoad = true;
// Add some URLs to the malware database. // Add some URLs to the malware database.
@ -30,51 +28,33 @@ testUpdate +=
"a:524:32:" + testData.length + "\n" + "a:524:32:" + testData.length + "\n" +
testData; testData;
var dbService = Cc["@mozilla.org/url-classifier/dbservice;1"]
.getService(Ci.nsIUrlClassifierDBService);
function loadTestFrame() { function loadTestFrame() {
document.getElementById("testFrame").src = "classifierFrame.html"; document.getElementById("testFrame").src = "classifierFrame.html";
} }
function doUpdate(update) { const CLASSIFIER_COMMON_URL = SimpleTest.getTestFileURL("classifierCommon.js");
var listener = { let classifierCommonScript = SpecialPowers.loadChromeScript(CLASSIFIER_COMMON_URL);
QueryInterface: SpecialPowers.wrapCallback(function(iid)
{
if (iid.equals(Ci.nsISupports) ||
iid.equals(Ci.nsIUrlClassifierUpdateObserver))
return this;
throw Cr.NS_ERROR_NO_INTERFACE; // Expected finish() call is in "classifierFrame.html".
}), SimpleTest.waitForExplicitFinish();
updateUrlRequested: function(url) { },
streamFinished: function(status) { },
updateError: function(errorCode) {
ok(false, "Couldn't update classifier.");
// Abort test.
SimpleTest.finish();
},
updateSuccess: function(requestedTimeout) {
SpecialPowers.pushPrefEnv(
{"set" : [["browser.safebrowsing.malware.enabled", true]]},
loadTestFrame);
}
};
dbService.beginUpdate(listener, "test-malware-simple,test-unwanted-simple", ""); classifierCommonScript.addMessageListener("loadTestFrame", () => {
dbService.beginStream("", ""); SpecialPowers.pushPrefEnv(
dbService.updateStream(update); {"set" : [["browser.safebrowsing.malware.enabled", true]]},
dbService.finishStream(); loadTestFrame);
dbService.finishUpdate(); });
} classifierCommonScript.addMessageListener("updateError", ({ errorCode }) => {
ok(false, "Couldn't update classifier. Error code: " + errorCode);
// Abort test.
SimpleTest.finish();
});
SpecialPowers.pushPrefEnv( SpecialPowers.pushPrefEnv(
{"set" : [["urlclassifier.malwareTable", "test-malware-simple,test-unwanted-simple"], {"set" : [["urlclassifier.malwareTable", "test-malware-simple,test-unwanted-simple"],
["urlclassifier.phishTable", "test-phish-simple"]]}, ["urlclassifier.phishTable", "test-phish-simple"]]},
function() { doUpdate(testUpdate); }); function() {
classifierCommonScript.sendAsyncMessage("doUpdate", { testUpdate });
// Expected finish() call is in "classifierFrame.html". });
SimpleTest.waitForExplicitFinish();
</script> </script>

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

@ -13,9 +13,6 @@
<script class="testbody" type="text/javascript"> <script class="testbody" type="text/javascript">
var Cc = SpecialPowers.Cc;
var Ci = SpecialPowers.Ci;
// Add some URLs to the malware database. // Add some URLs to the malware database.
var testData = "example.com/tests/toolkit/components/url-classifier/tests/mochitest/evilWorker.js"; var testData = "example.com/tests/toolkit/components/url-classifier/tests/mochitest/evilWorker.js";
var testUpdate = var testUpdate =
@ -29,42 +26,9 @@ testUpdate +=
"a:550:32:" + testData.length + "\n" + "a:550:32:" + testData.length + "\n" +
testData; testData;
var dbService = Cc["@mozilla.org/url-classifier/dbservice;1"] function loadTestFrame() {
.getService(Ci.nsIUrlClassifierDBService); document.getElementById("testFrame").src =
"http://example.com/tests/toolkit/components/url-classifier/tests/mochitest/workerFrame.html";
function doUpdate(update) {
var listener = {
QueryInterface: SpecialPowers.wrapCallback(function(iid)
{
if (iid.equals(Ci.nsISupports) ||
iid.equals(Ci.nsIUrlClassifierUpdateObserver))
return this;
throw Cr.NS_ERROR_NO_INTERFACE;
}),
updateUrlRequested: function(url) { },
streamFinished: function(status) { },
updateError: function(errorCode) {
ok(false, "Couldn't update classifier.");
// Abort test.
SimpleTest.finish();
},
updateSuccess: function(requestedTimeout) {
SpecialPowers.pushPrefEnv(
{"set" : [["browser.safebrowsing.malware.enabled", true]]},
function loadTestFrame() {
document.getElementById("testFrame").src =
"http://example.com/tests/toolkit/components/url-classifier/tests/mochitest/workerFrame.html";
}
);
}
};
dbService.beginUpdate(listener, "test-malware-simple,test-unwanted-simple", "");
dbService.beginStream("", "");
dbService.updateStream(update);
dbService.finishStream();
dbService.finishUpdate();
} }
function onmessage(event) function onmessage(event)
@ -78,10 +42,26 @@ function onmessage(event)
is(pieces[0], "success", pieces[1]); is(pieces[0], "success", pieces[1]);
} }
const CLASSIFIER_COMMON_URL = SimpleTest.getTestFileURL("classifierCommon.js");
let classifierCommonScript = SpecialPowers.loadChromeScript(CLASSIFIER_COMMON_URL);
classifierCommonScript.addMessageListener("loadTestFrame", () => {
SpecialPowers.pushPrefEnv(
{"set" : [["browser.safebrowsing.malware.enabled", true]]},
loadTestFrame);
});
classifierCommonScript.addMessageListener("updateError", ({ errorCode }) => {
ok(false, "Couldn't update classifier. Error code: " + errorCode);
// Abort test.
SimpleTest.finish();
});
SpecialPowers.pushPrefEnv( SpecialPowers.pushPrefEnv(
{"set" : [["urlclassifier.malwareTable", "test-malware-simple,test-unwanted-simple"], {"set" : [["urlclassifier.malwareTable", "test-malware-simple,test-unwanted-simple"],
["urlclassifier.phishTable", "test-phish-simple"]]}, ["urlclassifier.phishTable", "test-phish-simple"]]},
function() { doUpdate(testUpdate); }); function() {
classifierCommonScript.sendAsyncMessage("doUpdate", { testUpdate });
});
window.addEventListener("message", onmessage, false); window.addEventListener("message", onmessage, false);

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

@ -3,10 +3,10 @@ skip-if = buildapp == 'b2g'
support-files = support-files =
handlerApp.xhtml handlerApp.xhtml
handlerApps.js handlerApps.js
unsafeBidi_chromeScript.js
unsafeBidiFileName.sjs unsafeBidiFileName.sjs
[test_badMimeType.html] [test_badMimeType.html]
[test_handlerApps.xhtml] [test_handlerApps.xhtml]
skip-if = (toolkit == 'android' || os == 'mac') || e10s # OS X: bug 786938 skip-if = (toolkit == 'android' || os == 'mac') || e10s # OS X: bug 786938
[test_unsafeBidiChars.xhtml] [test_unsafeBidiChars.xhtml]
skip-if = e10s

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

@ -2,21 +2,22 @@
<head> <head>
<title>Test for Handling of unsafe bidi chars</title> <title>Test for Handling of unsafe bidi chars</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head> </head>
<body onload="load();"> <body>
<p id="display"></p> <p id="display"></p>
<iframe id="test"></iframe> <iframe id="test"></iframe>
<script type="text/javascript"> <script type="text/javascript">
<![CDATA[ <![CDATA[
var unsafeBidiChars = { var unsafeBidiChars = [
LRE: "\xe2\x80\xaa", "\xe2\x80\xaa", // LRE
RLE: "\xe2\x80\xab", "\xe2\x80\xab", // RLE
PDF: "\xe2\x80\xac", "\xe2\x80\xac", // PDF
LRO: "\xe2\x80\xad", "\xe2\x80\xad", // LRO
RLO: "\xe2\x80\xae" "\xe2\x80\xae" // RLO
}; ];
var tests = [ var tests = [
"{1}.test", "{1}.test",
@ -37,100 +38,40 @@ function sanitize(name) {
return replace(name, '_'); return replace(name, '_');
} }
var gTests = []; add_task(function* () {
function make_test(param, expected) { let url = SimpleTest.getTestFileURL("unsafeBidi_chromeScript.js");
gTests.push({ let chromeScript = SpecialPowers.loadChromeScript(url);
param: param,
expected: expected, for (let test of tests) {
for (let char of unsafeBidiChars) {
let promiseName = new Promise(function(resolve) {
chromeScript.addMessageListener("suggestedFileName",
function listener(data) {
chromeScript.removeMessageListener("suggestedFileName", listener);
resolve(data);
});
});
let name = replace(test, char);
let expected = sanitize(test);
document.getElementById("test").src =
"unsafeBidiFileName.sjs?name=" + encodeURIComponent(name);
is((yield promiseName), expected, "got the expected sanitized name");
}
}
let promise = new Promise(function(resolve) {
chromeScript.addMessageListener("unregistered", function listener() {
chromeScript.removeMessageListener("unregistered", listener);
resolve();
});
}); });
} chromeScript.sendAsyncMessage("unregister");
yield promise;
SimpleTest.waitForExplicitFinish(); chromeScript.destroy();
});
function load() {
var iframe = document.getElementById("test");
var gCallback = null;
function run_test(test, cb) {
var url = "unsafeBidiFileName.sjs?name=" + encodeURIComponent(test.param);
gCallback = cb;
iframe.src = url;
}
var gCounter = -1;
function run_next_test() {
if (++gCounter == gTests.length)
finish_test();
else
run_test(gTests[gCounter], run_next_test);
}
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
const HELPERAPP_DIALOG_CONTRACT = "@mozilla.org/helperapplauncherdialog;1";
const HELPERAPP_DIALOG_CID = SpecialPowers.wrap(SpecialPowers.Components).ID(SpecialPowers.Cc[HELPERAPP_DIALOG_CONTRACT].number);
const FAKE_CID = SpecialPowers.Cc["@mozilla.org/uuid-generator;1"].
getService(SpecialPowers.Ci.nsIUUIDGenerator).generateUUID();
function HelperAppLauncherDialog() {}
HelperAppLauncherDialog.prototype = {
REASON_CANTHANDLE: 0,
REASON_SERVERREQUEST: 1,
REASON_TYPESNIFFED: 2,
show: function(aLauncher, aWindowContext, aReason) {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
var test = gTests[gCounter];
is(aLauncher.suggestedFileName, test.expected,
"The filename should be correctly sanitized");
gCallback();
},
QueryInterface: function(aIID) {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
if (aIID.equals(SpecialPowers.Ci.nsISupports) ||
aIID.equals(SpecialPowers.Ci.nsIHelperAppLauncherDialog))
return this;
throw SpecialPowers.Cr.NS_ERROR_NO_INTERFACE;
}
};
var factory = {
createInstance: function(aOuter, aIID) {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
if (aOuter != null)
throw SpecialPowers.Cr.NS_ERROR_NO_AGGREGATION;
return new HelperAppLauncherDialog().QueryInterface(aIID);
}
};
SpecialPowers.wrap(SpecialPowers.Components).manager
.QueryInterface(SpecialPowers.Ci.nsIComponentRegistrar)
.registerFactory(FAKE_CID, "",
HELPERAPP_DIALOG_CONTRACT,
factory);
function finish_test() {
SpecialPowers.wrap(SpecialPowers.Components).manager
.QueryInterface(SpecialPowers.Ci.nsIComponentRegistrar)
.registerFactory(HELPERAPP_DIALOG_CID, "",
HELPERAPP_DIALOG_CONTRACT,
null);
SimpleTest.finish();
}
var i,j;
for (i = 0; i < tests.length; ++i) {
for (j in unsafeBidiChars) {
make_test(replace(tests[i], unsafeBidiChars[j]),
sanitize(tests[i]));
}
}
run_next_test();
}
]]> ]]>
</script> </script>
</body> </body>
</html> </html>

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

@ -0,0 +1,28 @@
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
const HELPERAPP_DIALOG_CONTRACT = "@mozilla.org/helperapplauncherdialog;1";
const HELPERAPP_DIALOG_CID =
Components.ID(Cc[HELPERAPP_DIALOG_CONTRACT].number);
const FAKE_CID = Cc["@mozilla.org/uuid-generator;1"].
getService(Ci.nsIUUIDGenerator).generateUUID();
function HelperAppLauncherDialog() {}
HelperAppLauncherDialog.prototype = {
show: function(aLauncher, aWindowContext, aReason) {
sendAsyncMessage("suggestedFileName", aLauncher.suggestedFileName);
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIHelperAppLauncherDialog])
};
var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
registrar.registerFactory(FAKE_CID, "", HELPERAPP_DIALOG_CONTRACT,
XPCOMUtils._getFactory(HelperAppLauncherDialog));
addMessageListener("unregister", function() {
registrar.registerFactory(HELPERAPP_DIALOG_CID, "",
HELPERAPP_DIALOG_CONTRACT, null);
sendAsyncMessage("unregistered");
});