Merge m-c to fx-team

This commit is contained in:
Matt Brubeck 2013-08-08 21:54:44 -07:00
commit 19ae0473d9
67 changed files with 790 additions and 343 deletions

View File

@ -36,15 +36,15 @@ exports.testPlainTextConsole = function(test) {
test.pass("PlainTextConsole instantiates");
con.log('testing', 1, [2, 3, 4]);
test.assertEqual(lastPrint(), "console.log: " + name + ": testing, 1, Array [2,3,4]\n",
test.assertEqual(lastPrint(), "console.log: " + name + ": testing 1 Array [2,3,4]\n",
"PlainTextConsole.log() must work.");
con.info('testing', 1, [2, 3, 4]);
test.assertEqual(lastPrint(), "console.info: " + name + ": testing, 1, Array [2,3,4]\n",
test.assertEqual(lastPrint(), "console.info: " + name + ": testing 1 Array [2,3,4]\n",
"PlainTextConsole.info() must work.");
con.warn('testing', 1, [2, 3, 4]);
test.assertEqual(lastPrint(), "console.warn: " + name + ": testing, 1, Array [2,3,4]\n",
test.assertEqual(lastPrint(), "console.warn: " + name + ": testing 1 Array [2,3,4]\n",
"PlainTextConsole.warn() must work.");
con.error('testing', 1, [2, 3, 4]);
@ -64,20 +64,20 @@ exports.testPlainTextConsole = function(test) {
prints = [];
con.log('testing', undefined);
test.assertEqual(lastPrint(), "console.log: " + name + ": testing, undefined\n",
test.assertEqual(lastPrint(), "console.log: " + name + ": testing undefined\n",
"PlainTextConsole.log() must stringify undefined.");
con.log('testing', null);
test.assertEqual(lastPrint(), "console.log: " + name + ": testing, null\n",
test.assertEqual(lastPrint(), "console.log: " + name + ": testing null\n",
"PlainTextConsole.log() must stringify null.");
// TODO: Fix console.jsm to detect custom toString.
con.log("testing", { toString: function() "obj.toString()" });
test.assertEqual(lastPrint(), "console.log: " + name + ": testing, {}\n",
test.assertEqual(lastPrint(), "console.log: " + name + ": testing {}\n",
"PlainTextConsole.log() doesn't printify custom toString.");
con.log("testing", { toString: function() { throw "fail!"; } });
test.assertEqual(lastPrint(), "console.log: " + name + ": testing, {}\n",
test.assertEqual(lastPrint(), "console.log: " + name + ": testing {}\n",
"PlainTextConsole.log() must stringify custom bad toString.");

View File

@ -756,7 +756,6 @@ var gBrowserInit = {
// initialize observers and listeners
// and give C++ access to gBrowser
gBrowser.init();
XULBrowserWindow.init();
window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(nsIWebNavigation)

View File

@ -2956,7 +2956,17 @@
filter.addProgressListener(tabListener, nsIWebProgress.NOTIFY_ALL);
this.mTabListeners[0] = tabListener;
this.mTabFilters[0] = filter;
this.init();
try {
// We assume this can only fail because mCurrentBrowser's docShell
// hasn't been created, yet. This may be caused by code accessing
// gBrowser before the window has finished loading.
this._addProgressListenerForInitialTab();
} catch (e) {
// The binding was constructed too early, wait until the initial
// tab's document is ready, then add the progress listener.
this._waitForInitialContentDocument();
}
this.style.backgroundColor =
Services.prefs.getBoolPref("browser.display.use_system_colors") ?
@ -2970,17 +2980,28 @@
]]>
</constructor>
<method name="init">
<method name="_addProgressListenerForInitialTab">
<body><![CDATA[
if (!this._initialProgressListenerAdded) {
this._initialProgressListenerAdded = true;
try {
this.webProgress.addProgressListener(this.mTabFilters[0], Components.interfaces.nsIWebProgress.NOTIFY_ALL);
} catch (e) {
// The binding was constructed too early, need to try this again later. See bug 463384.
this._initialProgressListenerAdded = false;
}
this.webProgress.addProgressListener(this.mTabFilters[0], Ci.nsIWebProgress.NOTIFY_ALL);
]]></body>
</method>
<method name="_waitForInitialContentDocument">
<body><![CDATA[
let obs = (subject, topic) => {
if (this.browsers[0].contentWindow == subject) {
Services.obs.removeObserver(obs, topic);
this._addProgressListenerForInitialTab();
}
};
// We use content-document-global-created as an approximation for
// "docShell is initialized". We can do this because in the
// mTabProgressListener we care most about the STATE_STOP notification
// that will reset mBlank. That means it's important to at least add
// the progress listener before the initial about:blank load stops
// if we can't do it before the load starts.
Services.obs.addObserver(obs, "content-document-global-created", false);
]]></body>
</method>

View File

@ -184,6 +184,7 @@ MOCHITEST_BROWSER_FILES = \
browser_bug822367.js \
browser_bug832435.js \
browser_bug839103.js \
browser_bug880101.js \
browser_bug882977.js \
browser_bug887515.js \
browser_canonizeURL.js \

View File

@ -0,0 +1,50 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
const URL = "about:robots";
function test() {
let win;
let listener = {
onLocationChange: (webProgress, request, uri, flags) => {
ok(webProgress.isTopLevel, "Received onLocationChange from top frame");
is(uri.spec, URL, "Received onLocationChange for correct URL");
finish();
}
};
waitForExplicitFinish();
// Remove the listener and window when we're done.
registerCleanupFunction(() => {
win.gBrowser.removeProgressListener(listener);
win.close();
});
// Wait for the newly opened window.
whenNewWindowOpened(w => win = w);
// Open a link in a new window.
openLinkIn(URL, "window", {});
// On the next tick, but before the window has finished loading, access the
// window's gBrowser property to force the tabbrowser constructor early.
(function tryAddProgressListener() {
executeSoon(() => {
try {
win.gBrowser.addProgressListener(listener);
} catch (e) {
// win.gBrowser wasn't ready, yet. Try again in a tick.
tryAddProgressListener();
}
});
})();
}
function whenNewWindowOpened(cb) {
Services.obs.addObserver(function obs(win) {
Services.obs.removeObserver(obs, "domwindowopened");
cb(win);
}, "domwindowopened", false);
}

View File

@ -311,9 +311,6 @@ let SessionStoreInternal = {
// states for all recently closed windows
_closedWindows: [],
// not-"dirty" windows usually don't need to have their data updated
_dirtyWindows: {},
// collection of session states yet to be restored
_statesToRestore: {},
@ -488,8 +485,6 @@ let SessionStoreInternal = {
this._prefBranch.getBoolPref("sessionstore.resume_session_once"))
this._prefBranch.setBoolPref("sessionstore.resume_session_once", false);
this._initEncoding();
this._performUpgradeBackup();
this._sessionInitialized = true;
@ -524,13 +519,6 @@ let SessionStoreInternal = {
}.bind(this));
},
_initEncoding : function ssi_initEncoding() {
// The (UTF-8) encoder used to write to files.
XPCOMUtils.defineLazyGetter(this, "_writeFileEncoder", function () {
return new TextEncoder();
});
},
_initPrefs : function() {
this._prefBranch = Services.prefs.getBranch("browser.");
@ -1000,7 +988,7 @@ let SessionStoreInternal = {
var activeWindow = this._getMostRecentBrowserWindow();
if (activeWindow)
this.activeWindowSSiCache = activeWindow.__SSi || "";
this._dirtyWindows = [];
DirtyWindows.clear();
},
/**
@ -2544,14 +2532,14 @@ let SessionStoreInternal = {
this._forEachBrowserWindow(function(aWindow) {
if (!this._isWindowLoaded(aWindow)) // window data is still in _statesToRestore
return;
if (aUpdateAll || this._dirtyWindows[aWindow.__SSi] || aWindow == activeWindow) {
if (aUpdateAll || DirtyWindows.has(aWindow) || aWindow == activeWindow) {
this._collectWindowData(aWindow);
}
else { // always update the window features (whose change alone never triggers a save operation)
this._updateWindowFeatures(aWindow);
}
});
this._dirtyWindows = [];
DirtyWindows.clear();
}
// collect the data for all windows
@ -2682,7 +2670,7 @@ let SessionStoreInternal = {
this._windows[aWindow.__SSi].__lastSessionWindowID =
aWindow.__SS_lastSessionWindowID;
this._dirtyWindows[aWindow.__SSi] = false;
DirtyWindows.remove(aWindow);
},
/* ........ Restoring Functionality .............. */
@ -3010,7 +2998,7 @@ let SessionStoreInternal = {
// It's important to set the window state to dirty so that
// we collect their data for the first time when saving state.
this._dirtyWindows[aWindow.__SSi] = true;
DirtyWindows.add(aWindow);
}
if (aTabs.length == 0) {
@ -3701,7 +3689,7 @@ let SessionStoreInternal = {
*/
saveStateDelayed: function ssi_saveStateDelayed(aWindow = null, aDelay = 2000) {
if (aWindow) {
this._dirtyWindows[aWindow.__SSi] = true;
DirtyWindows.add(aWindow);
}
if (!this._saveTimer) {
@ -4689,6 +4677,28 @@ let DyingWindowCache = {
}
};
// A weak set of dirty windows. We use it to determine which windows we need to
// recollect data for when _getCurrentState() is called.
let DirtyWindows = {
_data: new WeakMap(),
has: function (window) {
return this._data.has(window);
},
add: function (window) {
return this._data.set(window, true);
},
remove: function (window) {
this._data.delete(window);
},
clear: function (window) {
this._data.clear();
}
};
// A map storing the number of tabs last closed per windoow. This only
// stores the most recent tab-close operation, and is used to undo
// batch tab-closing operations.

View File

@ -1920,7 +1920,6 @@ let GroupItems = {
minGroupHeight: 110,
minGroupWidth: 125,
_lastActiveList: null,
_lastGroupToUpdateTabBar: null,
// ----------
// Function: toString
@ -2286,10 +2285,6 @@ let GroupItems = {
});
this._lastActiveList.remove(groupItem);
if (this._lastGroupToUpdateTabBar == groupItem)
this._lastGroupToUpdateTabBar = null;
UI.updateTabButton();
},
@ -2423,13 +2418,8 @@ let GroupItems = {
Utils.assert(this._activeGroupItem, "There must be something to show in the tab bar!");
// Update list of visible tabs only once after switching to another group.
if (this._activeGroupItem == this._lastGroupToUpdateTabBar)
return;
let tabItems = this._activeGroupItem._children;
gBrowser.showOnlyTheseTabs(tabItems.map(function(item) item.tab));
this._lastGroupToUpdateTabBar = this._activeGroupItem;
},
// ----------
@ -2547,7 +2537,7 @@ let GroupItems = {
if (tab._tabViewTabItem.parent && tab._tabViewTabItem.parent.id == groupItemId)
return;
let shouldHideTab = false;
let shouldUpdateTabBar = false;
let shouldShowTabView = false;
let groupItem;
@ -2555,12 +2545,12 @@ let GroupItems = {
if (tab.selected) {
if (gBrowser.visibleTabs.length > 1) {
gBrowser._blurTab(tab);
shouldHideTab = true;
shouldUpdateTabBar = true;
} else {
shouldShowTabView = true;
}
} else {
shouldHideTab = true;
shouldUpdateTabBar = true
}
// remove tab item from a groupItem
@ -2583,8 +2573,8 @@ let GroupItems = {
new GroupItem([ tab._tabViewTabItem ], { bounds: box, immediately: true });
}
if (shouldHideTab)
gBrowser.hideTab(tab);
if (shouldUpdateTabBar)
this._updateTabBar();
else if (shouldShowTabView)
UI.showTabView();
},

View File

@ -99,14 +99,47 @@ function test() {
}, aWindow);
}
function testOnWindow(aCallback) {
let win = OpenBrowserWindow({private: false});
// [624102] check state after return from private browsing
let testPrivateBrowsing = function (aWindow) {
aWindow.gBrowser.loadOneTab('http://mochi.test:8888/#1', {inBackground: true});
aWindow.gBrowser.loadOneTab('http://mochi.test:8888/#2', {inBackground: true});
let cw = getContentWindow(aWindow);
let box = new cw.Rect(20, 20, 250, 200);
let groupItem = new cw.GroupItem([], {bounds: box, immediately: true});
cw.UI.setActive(groupItem);
aWindow.gBrowser.selectedTab = aWindow.gBrowser.loadOneTab('http://mochi.test:8888/#3', {inBackground: true});
aWindow.gBrowser.loadOneTab('http://mochi.test:8888/#4', {inBackground: true});
afterAllTabsLoaded(function () {
assertNumberOfVisibleTabs(aWindow, 2);
enterAndLeavePrivateBrowsing(function () {
assertNumberOfVisibleTabs(aWindow, 2);
aWindow.gBrowser.selectedTab = aWindow.gBrowser.tabs[0];
closeGroupItem(cw.GroupItems.groupItems[1], function() {
next(aWindow);
});
});
}, aWindow);
}
function testOnWindow(aIsPrivate, aCallback) {
let win = OpenBrowserWindow({private: aIsPrivate});
win.addEventListener("load", function onLoad() {
win.removeEventListener("load", onLoad, false);
executeSoon(function() { aCallback(win) });
}, false);
}
function enterAndLeavePrivateBrowsing(callback) {
testOnWindow(true, function (aWindow) {
aWindow.close();
callback();
});
}
waitForExplicitFinish();
// Tests for #624265
@ -116,7 +149,10 @@ function test() {
tests.push(testDuplicateTab);
tests.push(testBackForwardDuplicateTab);
testOnWindow(function(aWindow) {
// Tests for #624102
tests.push(testPrivateBrowsing);
testOnWindow(false, function(aWindow) {
loadTabView(function() {
next(aWindow);
}, aWindow);

View File

@ -134,7 +134,6 @@ const WebProgress = {
browser.messageManager.removeMessageListener(aMessage.name, arguments.callee);
aTab._firstPaint = true;
aTab.scrolledAreaChanged(true);
aTab.updateThumbnailSource();
});
},

View File

@ -17,7 +17,7 @@
<binding id="documenttab">
<content observes="bcast_urlbarState">
<xul:stack class="documenttab-container">
<xul:box anonid="thumbnail" class="documenttab-thumbnail" />
<html:canvas anonid="thumbnail-canvas" class="documenttab-thumbnail" />
<xul:image anonid="favicon" class="documenttab-favicon"
observes="bcast_urlbarState" width="26" height="26"/>
@ -36,12 +36,19 @@
</handlers>
<implementation>
<field name="_thumbnail" readonly="true">document.getAnonymousElementByAttribute(this, "anonid", "thumbnail");</field>
<field name="thumbnailCanvas" readonly="true">document.getAnonymousElementByAttribute(this, "anonid", "thumbnail-canvas");</field>
<field name="_close" readonly="true">document.getAnonymousElementByAttribute(this, "anonid", "close");</field>
<field name="_title" readonly="true">document.getAnonymousElementByAttribute(this, "anonid", "title");</field>
<field name="_favicon" readonly="true">document.getAnonymousElementByAttribute(this, "anonid", "favicon");</field>
<field name="_container" readonly="true">this.parentNode;</field>
<constructor>
<![CDATA[
this.thumbnailCanvas.mozOpaque = true;
this.thumbnailCanvas.mozImageSmoothingEnabled = true;
]]>
</constructor>
<method name="_onClick">
<body>
<![CDATA[
@ -90,14 +97,6 @@
</body>
</method>
<method name="updateThumbnailSource">
<parameter name="browser"/>
<body>
<![CDATA[
this._thumbnail.style.backgroundImage = "-moz-element(#" + browser.id + ")";
]]>
</body>
</method>
</implementation>
</binding>

View File

@ -8,6 +8,8 @@ let Ci = Components.interfaces;
let Cu = Components.utils;
let Cr = Components.results;
Cu.import("resource://gre/modules/PageThumbs.jsm");
const kBrowserViewZoomLevelPrecision = 10000;
// allow panning after this timeout on pages with registered touch listeners
@ -16,6 +18,8 @@ const kSetInactiveStateTimeout = 100;
const kDefaultMetadata = { autoSize: false, allowZoom: true, autoScale: true };
const kTabThumbnailDelayCapture = 500;
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
// Override sizeToContent in the main window. It breaks things (bug 565887)
@ -1454,6 +1458,7 @@ function Tab(aURI, aParams, aOwner) {
this._chromeTab = null;
this._metadata = null;
this._eventDeferred = null;
this._updateThumbnailTimeout = null;
this.owner = aOwner || null;
@ -1603,13 +1608,45 @@ Tab.prototype = {
self._eventDeferred = null;
}
browser.addEventListener("pageshow", onPageShowEvent, true);
browser.messageManager.addMessageListener("Content:StateChange", this);
Services.obs.addObserver(this, "metro_viewstate_changed", false);
if (aOwner)
this._copyHistoryFrom(aOwner);
this._loadUsingParams(browser, aURI, aParams);
},
receiveMessage: function(aMessage) {
switch (aMessage.name) {
case "Content:StateChange":
// update the thumbnail now...
this.updateThumbnail();
// ...and in a little while to capture page after load.
if (aMessage.json.stateFlags & Ci.nsIWebProgressListener.STATE_STOP) {
clearTimeout(this._updateThumbnailTimeout);
this._updateThumbnailTimeout = setTimeout(() => {
this.updateThumbnail();
}, kTabThumbnailDelayCapture);
}
break;
}
},
observe: function BrowserUI_observe(aSubject, aTopic, aData) {
switch (aTopic) {
case "metro_viewstate_changed":
if (aData !== "snapped") {
this.updateThumbnail();
}
break;
}
},
destroy: function destroy() {
this._browser.messageManager.removeMessageListener("Content:StateChange", this);
Services.obs.removeObserver(this, "metro_viewstate_changed", false);
clearTimeout(this._updateThumbnailTimeout);
Elements.tabList.removeTab(this._chromeTab);
this._chromeTab = null;
this._destroyBrowser();
@ -1818,8 +1855,8 @@ Tab.prototype = {
return this.metadata.allowZoom && !Util.isURLEmpty(this.browser.currentURI.spec);
},
updateThumbnailSource: function updateThumbnailSource() {
this._chromeTab.updateThumbnailSource(this._browser);
updateThumbnail: function updateThumbnail() {
PageThumbs.captureToCanvas(this.browser.contentWindow, this._chromeTab.thumbnailCanvas);
},
updateFavicon: function updateFavicon() {

View File

@ -228,10 +228,7 @@
<richgrid id="start-remotetabs-grid" set-name="remoteTabs" seltype="multiple" flex="1"/>
</vbox>
<!-- Spacer to take extra space in snapped mode. -->
<spacer flex="999"/>
</scrollbox>
</hbox>
</vbox> <!-- end tray -->

View File

@ -12,7 +12,7 @@ var AutofillMenuUI = {
get _panel() { return document.getElementById("autofill-container"); },
get _popup() { return document.getElementById("autofill-popup"); },
get _commands() { return this._popup.childNodes[0]; },
get commands() { return this._popup.childNodes[0]; },
get _menuPopup() {
if (!this.__menuPopup) {
@ -32,8 +32,8 @@ var AutofillMenuUI = {
},
_emptyCommands: function _emptyCommands() {
while (this._commands.firstChild)
this._commands.removeChild(this._commands.firstChild);
while (this.commands.firstChild)
this.commands.removeChild(this.commands.firstChild);
},
_positionOptions: function _positionOptions() {
@ -57,7 +57,7 @@ var AutofillMenuUI = {
label.setAttribute("value", aSuggestionsList[idx].label);
item.setAttribute("data", aSuggestionsList[idx].value);
item.appendChild(label);
this._commands.appendChild(item);
this.commands.appendChild(item);
}
this._menuPopup.show(this._positionOptions());
@ -65,7 +65,7 @@ var AutofillMenuUI = {
selectByIndex: function mn_selectByIndex(aIndex) {
this._menuPopup.hide();
FormHelperUI.doAutoComplete(this._commands.childNodes[aIndex].getAttribute("data"));
FormHelperUI.doAutoComplete(this.commands.childNodes[aIndex].getAttribute("data"));
},
hide: function hide () {
@ -85,7 +85,7 @@ var ContextMenuUI = {
get _panel() { return document.getElementById("context-container"); },
get _popup() { return document.getElementById("context-popup"); },
get _commands() { return this._popup.childNodes[0]; },
get commands() { return this._popup.childNodes[0]; },
get _menuPopup() {
if (!this.__menuPopup) {
@ -153,12 +153,12 @@ var ContextMenuUI = {
contentTypes.indexOf("selected-text") != -1))
multipleMediaTypes = true;
for (let command of Array.slice(this._commands.childNodes)) {
for (let command of Array.slice(this.commands.childNodes)) {
command.hidden = true;
}
let optionsAvailable = false;
for (let command of Array.slice(this._commands.childNodes)) {
for (let command of Array.slice(this.commands.childNodes)) {
let types = command.getAttribute("type").split(",");
let lowPriority = (command.hasAttribute("priority") &&
command.getAttribute("priority") == "low");
@ -221,7 +221,7 @@ var MenuControlUI = {
get _panel() { return document.getElementById("menucontrol-container"); },
get _popup() { return document.getElementById("menucontrol-popup"); },
get _commands() { return this._popup.childNodes[0]; },
get commands() { return this._popup.childNodes[0]; },
get _menuPopup() {
if (!this.__menuPopup) {
@ -240,8 +240,8 @@ var MenuControlUI = {
},
_emptyCommands: function _emptyCommands() {
while (this._commands.firstChild)
this._commands.removeChild(this._commands.firstChild);
while (this.commands.firstChild)
this.commands.removeChild(this.commands.firstChild);
},
_positionOptions: function _positionOptions() {
@ -314,7 +314,7 @@ var MenuControlUI = {
label.setAttribute("value", child.label);
item.appendChild(label);
this._commands.appendChild(item);
this.commands.appendChild(item);
}
this._menuPopup.show(this._positionOptions());
@ -338,84 +338,25 @@ function MenuPopup(aPanel, aPopup) {
this._panel = aPanel;
this._popup = aPopup;
this._wantTypeBehind = false;
this._willReshowPopup = false;
window.addEventListener('MozAppbarShowing', this, false);
}
MenuPopup.prototype = {
get _visible() { return !this._panel.hidden; },
get _commands() { return this._popup.childNodes[0]; },
get visible() { return !this._panel.hidden; },
get commands() { return this._popup.childNodes[0]; },
show: function (aPositionOptions) {
if (this._visible) {
this._willReshowPopup = true;
let self = this;
this._panel.addEventListener("transitionend", function () {
self._show(aPositionOptions);
self._panel.removeEventListener("transitionend", arguments.callee);
});
if (this.visible) {
this._animateHide().then(() => this._animateShow(aPositionOptions));
} else {
this._show(aPositionOptions);
this._animateShow(aPositionOptions);
}
},
_show: function (aPositionOptions) {
window.addEventListener("keypress", this, true);
window.addEventListener("mousedown", this, true);
Elements.stack.addEventListener("PopupChanged", this, false);
Elements.browsers.addEventListener("PanBegin", this, false);
this._panel.hidden = false;
this._position(aPositionOptions || {});
let self = this;
this._panel.addEventListener("transitionend", function () {
self._panel.removeEventListener("transitionend", arguments.callee);
self._panel.removeAttribute("showingfrom");
let eventName = self._willReshowPopup ? "popupmoved" : "popupshown";
let event = document.createEvent("Events");
event.initEvent(eventName, true, false);
self._panel.dispatchEvent(event);
self._willReshowPopup = false;
});
let popupFrom = !aPositionOptions.bottomAligned ? "above" : "below";
this._panel.setAttribute("showingfrom", popupFrom);
// Ensure the panel actually gets shifted before getting animated
setTimeout(function () {
self._panel.setAttribute("showing", "true");
}, 0);
},
hide: function () {
if (!this._visible)
return;
window.removeEventListener("keypress", this, true);
window.removeEventListener("mousedown", this, true);
Elements.stack.removeEventListener("PopupChanged", this, false);
Elements.browsers.removeEventListener("PanBegin", this, false);
let self = this;
this._panel.addEventListener("transitionend", function () {
self._panel.removeEventListener("transitionend", arguments.callee);
self._panel.removeAttribute("hiding");
self._panel.hidden = true;
self._popup.style.maxWidth = "none";
self._popup.style.maxHeight = "none";
if (!self._willReshowPopup) {
let event = document.createEvent("Events");
event.initEvent("popuphidden", true, false);
self._panel.dispatchEvent(event);
if (this.visible) {
this._animateHide();
}
});
this._panel.setAttribute("hiding", "true");
setTimeout(()=>this._panel.removeAttribute("showing"), 0);
},
_position: function _position(aPositionOptions) {
@ -440,7 +381,7 @@ MenuPopup.prototype = {
// Add padding on the side of the menu per the user's hand preference
let leftHand = MetroUtils.handPreference == MetroUtils.handPreferenceLeft;
if (aSource && aSource == Ci.nsIDOMMouseEvent.MOZ_SOURCE_TOUCH) {
this._commands.setAttribute("left-hand", leftHand);
this.commands.setAttribute("left-hand", leftHand);
}
if (aPositionOptions.rightAligned)
@ -486,6 +427,66 @@ MenuPopup.prototype = {
}
},
_animateShow: function (aPositionOptions) {
let deferred = Promise.defer();
window.addEventListener("keypress", this, true);
window.addEventListener("click", this, true);
Elements.stack.addEventListener("PopupChanged", this, false);
Elements.browsers.addEventListener("PanBegin", this, false);
this._panel.hidden = false;
let popupFrom = !aPositionOptions.bottomAligned ? "above" : "below";
this._panel.setAttribute("showingfrom", popupFrom);
// This triggers a reflow, which sets transitionability.
// All animation/transition setup must happen before here.
this._position(aPositionOptions || {});
let self = this;
this._panel.addEventListener("transitionend", function popupshown () {
self._panel.removeEventListener("transitionend", popupshown);
self._panel.removeAttribute("showingfrom");
self._dispatch("popupshown");
deferred.resolve();
});
this._panel.setAttribute("showing", "true");
return deferred.promise;
},
_animateHide: function () {
let deferred = Promise.defer();
window.removeEventListener("keypress", this, true);
window.removeEventListener("click", this, true);
Elements.stack.removeEventListener("PopupChanged", this, false);
Elements.browsers.removeEventListener("PanBegin", this, false);
let self = this;
this._panel.addEventListener("transitionend", function popuphidden() {
self._panel.removeEventListener("transitionend", popuphidden);
self._panel.removeAttribute("hiding");
self._panel.hidden = true;
self._popup.style.maxWidth = "none";
self._popup.style.maxHeight = "none";
self._dispatch("popuphidden");
deferred.resolve();
});
this._panel.setAttribute("hiding", "true");
this._panel.removeAttribute("showing");
return deferred.promise;
},
_dispatch: function _dispatch(aName) {
let event = document.createEvent("Events");
event.initEvent(aName, true, false);
this._panel.dispatchEvent(event);
},
handleEvent: function handleEvent(aEvent) {
switch (aEvent.type) {
case "keypress":
@ -497,7 +498,7 @@ MenuPopup.prototype = {
this.hide();
}
break;
case "mousedown":
case "click":
if (!this._popup.contains(aEvent.target)) {
aEvent.stopPropagation();
this.hide();

View File

@ -10,19 +10,17 @@ relativesrcdir = @relativesrcdir@
include $(DEPTH)/config/autoconf.mk
# Disabled for intermittent failures
# Bug 880739
# browser_context_menu_tests.js \
# browser_context_menu_tests_01.html \
# browser_context_menu_tests_02.html \
# browser_context_menu_tests_03.html \
MOCHITEST_METRO_FILES = \
head.js \
browser_urlbar.js \
browser_bookmarks.js \
browser_canonizeURL.js \
browser_circular_progress_indicator.js \
browser_context_menu_tests.js \
browser_context_menu_tests_01.html \
browser_context_menu_tests_02.html \
browser_context_menu_tests_03.html \
browser_context_menu_tests_04.html \
browser_context_ui.js \
browser_downloads.js \
browser_findbar.js \

View File

@ -58,7 +58,7 @@ gTests.push({
yield promise;
// should be visible
ok(ContextMenuUI._menuPopup._visible, "is visible");
ok(ContextMenuUI._menuPopup.visible, "is visible");
// selected text context:
checkContextUIMenuItemVisibility(["context-copy",
@ -91,7 +91,7 @@ gTests.push({
yield promise;
// should be visible
ok(ContextMenuUI._menuPopup._visible, "is visible");
ok(ContextMenuUI._menuPopup.visible, "is visible");
// selected text context:
checkContextUIMenuItemVisibility(["context-copy",
@ -113,7 +113,7 @@ gTests.push({
yield promise;
// should be visible
ok(ContextMenuUI._menuPopup._visible, "is visible");
ok(ContextMenuUI._menuPopup.visible, "is visible");
// selected text context:
checkContextUIMenuItemVisibility(["context-open-in-new-tab",
@ -135,7 +135,7 @@ gTests.push({
yield promise;
// should be visible
ok(ContextMenuUI._menuPopup._visible, "is visible");
ok(ContextMenuUI._menuPopup.visible, "is visible");
checkContextUIMenuItemVisibility(["context-select",
"context-select-all"]);
@ -159,7 +159,7 @@ gTests.push({
yield promise;
// should be visible
ok(ContextMenuUI._menuPopup._visible, "is visible");
ok(ContextMenuUI._menuPopup.visible, "is visible");
checkContextUIMenuItemVisibility(["context-cut",
"context-copy"]);
@ -191,7 +191,7 @@ gTests.push({
yield promise;
// should be visible
ok(ContextMenuUI._menuPopup._visible, "is visible");
ok(ContextMenuUI._menuPopup.visible, "is visible");
// selected text context:
checkContextUIMenuItemVisibility(["context-cut",
@ -212,7 +212,7 @@ gTests.push({
yield promise;
// should be visible
ok(ContextMenuUI._menuPopup._visible, "is visible");
ok(ContextMenuUI._menuPopup.visible, "is visible");
// selected text context:
checkContextUIMenuItemVisibility(["context-cut",
@ -236,7 +236,7 @@ gTests.push({
yield promise;
// should be visible
ok(ContextMenuUI._menuPopup._visible, "is visible");
ok(ContextMenuUI._menuPopup.visible, "is visible");
checkContextUIMenuItemVisibility(["context-cut",
"context-copy"]);
@ -272,7 +272,7 @@ gTests.push({
yield promise;
// should be visible
ok(ContextMenuUI._menuPopup._visible, "is visible");
ok(ContextMenuUI._menuPopup.visible, "is visible");
// selected text context:
checkContextUIMenuItemVisibility(["context-paste"]);
@ -295,7 +295,7 @@ gTests.push({
yield promise;
// should *not* be visible
ok(!ContextMenuUI._menuPopup._visible, "is visible");
ok(!ContextMenuUI._menuPopup.visible, "is visible");
// the test above will invoke the app bar
yield hideContextUI();
@ -336,7 +336,7 @@ gTests.push({
yield promise;
// should be visible and at a specific position
ok(ContextMenuUI._menuPopup._visible, "is visible");
ok(ContextMenuUI._menuPopup.visible, "is visible");
let notificationBox = Browser.getNotificationBox();
let notification = notificationBox.getNotificationWithValue("popup-blocked");
@ -352,6 +352,9 @@ gTests.push({
}
});
/*
XXX code used to diagnose bug 880739
var observeLogger = {
observe: function (aSubject, aTopic, aData) {
info("observeLogger: " + aTopic);
@ -383,15 +386,18 @@ var observeLogger = {
Services.obs.removeObserver(observeLogger, "dl-cancel");
}
}
*/
// Image context menu tests
gTests.push({
desc: "image context menu",
setUp: function() {
observeLogger.init();
// XXX code used to diagnose bug 880739
//observeLogger.init();
},
tearDown: function() {
observeLogger.shutdown();
// XXX code used to diagnose bug 880739
//observeLogger.shutdown();
},
run: function test() {
info(chromeRoot + "browser_context_menu_tests_01.html");
@ -419,7 +425,7 @@ gTests.push({
purgeEventQueue();
ok(ContextMenuUI._menuPopup._visible, "is visible");
ok(ContextMenuUI._menuPopup.visible, "is visible");
checkContextUIMenuItemVisibility(["context-save-image-lib",
"context-copy-image",
@ -465,7 +471,7 @@ gTests.push({
let promise = waitForEvent(document, "popupshown");
sendContextMenuClickToWindow(win, 20, 20);
yield promise;
ok(ContextMenuUI._menuPopup._visible, "is visible");
ok(ContextMenuUI._menuPopup.visible, "is visible");
let menuItem = document.getElementById("context-copy-image");
ok(menuItem, "menu item exists");
@ -486,7 +492,7 @@ gTests.push({
promise = waitForEvent(document, "popupshown");
sendContextMenuClickToWindow(win, 30, 30);
yield promise;
ok(ContextMenuUI._menuPopup._visible, "is visible");
ok(ContextMenuUI._menuPopup.visible, "is visible");
menuItem = document.getElementById("context-copy-image-loc");
ok(menuItem, "menu item exists");
@ -519,7 +525,7 @@ gTests.push({
promise = waitForEvent(document, "popupshown");
sendContextMenuClickToWindow(win, 40, 40);
yield promise;
ok(ContextMenuUI._menuPopup._visible, "is visible");
ok(ContextMenuUI._menuPopup.visible, "is visible");
menuItem = document.getElementById("context-open-image-tab");
ok(menuItem, "menu item exists");
@ -564,7 +570,7 @@ gTests.push({
yield promise;
// should be visible
ok(ContextMenuUI._menuPopup._visible, "is visible");
ok(ContextMenuUI._menuPopup.visible, "is visible");
checkContextMenuPositionRange(ContextMenuUI._panel, 265, 280, 175, 190);
@ -579,7 +585,7 @@ gTests.push({
yield promise;
// should be visible
ok(ContextMenuUI._menuPopup._visible, "is visible");
ok(ContextMenuUI._menuPopup.visible, "is visible");
checkContextMenuPositionRange(ContextMenuUI._panel, 265, 280, 95, 110);
@ -594,7 +600,7 @@ gTests.push({
yield promise;
// should be visible
ok(ContextMenuUI._menuPopup._visible, "is visible");
ok(ContextMenuUI._menuPopup.visible, "is visible");
checkContextMenuPositionRange(ContextMenuUI._panel, 295, 310, 540, 555);
@ -609,7 +615,7 @@ gTests.push({
yield promise;
// should be visible
ok(ContextMenuUI._menuPopup._visible, "is visible");
ok(ContextMenuUI._menuPopup.visible, "is visible");
checkContextMenuPositionRange(ContextMenuUI._panel, 295, 310, 340, 355);
@ -624,16 +630,87 @@ gTests.push({
yield promise;
// should be visible
ok(ContextMenuUI._menuPopup._visible, "is visible");
ok(ContextMenuUI._menuPopup.visible, "is visible");
checkContextMenuPositionRange(ContextMenuUI._panel, 265, 280, 110, 125);
promise = waitForEvent(document, "popuphidden");
ContextMenuUI.hide();
yield promise;
Browser.closeTab(Browser.selectedTab, { forceClose: true });
}
});
function reopenSetUp() {
info(chromeRoot + "browser_context_menu_tests_04.html");
yield addTab(chromeRoot + "browser_context_menu_tests_04.html");
// Sometimes the context UI won't actually show up.
// Since we're just normalizing, we don't want waitForCondition
// to cause an orange, so we're putting a try/catch here.
try {
yield waitForCondition(() => ContextUI.isVisible);
ContextUI.dismiss();
} catch(e) {}
}
function reopenTearDown() {
let promise = waitForEvent(document, "popuphidden")
ContextMenuUI.hide();
yield promise;
ok(!ContextMenuUI._menuPopup.visible, "popup is actually hidden");
Browser.closeTab(Browser.selectedTab, { forceClose: true });
}
function getReopenTest(aElementInputFn, aWindowInputFn) {
return function () {
let win = Browser.selectedTab.browser.contentWindow;
let panel = ContextMenuUI._menuPopup._panel;
let link1 = win.document.getElementById("text1-link");
let link2 = win.document.getElementById("text2-link");
// Show the menu on link 1
let showpromise = waitForEvent(panel, "popupshown");
aElementInputFn(win, link1);
ok((yield showpromise), "popupshown event fired");
ok(ContextMenuUI._menuPopup.visible, "initial popup is visible");
// Show the menu on link 2
let hidepromise = waitForEvent(panel, "popuphidden");
showpromise = waitForEvent(panel, "popupshown");
aElementInputFn(win, link2);
ok((yield hidepromise), "popuphidden event fired");
ok((yield showpromise), "popupshown event fired");
ok(ContextMenuUI._menuPopup.visible, "popup is still visible");
// Hide the menu
hidepromise = waitForEvent(panel, "popuphidden")
aWindowInputFn(win, 10, 10);
ok((yield hidepromise), "popuphidden event fired");
ok(!ContextMenuUI._menuPopup.visible, "popup is no longer visible");
}
}
gTests.push({
desc: "bug 856264 - mouse - context menu should reopen on other links",
setUp: reopenSetUp,
tearDown: reopenTearDown,
run: getReopenTest(sendContextMenuMouseClickToElement, sendMouseClick)
});
gTests.push({
desc: "bug 856264 - touch - context menu should reopen on other links",
setUp: reopenSetUp,
tearDown: reopenTearDown,
run: getReopenTest(sendContextMenuClickToElement, sendTap)
});
function test() {
runTests();
}

View File

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<head>
<style>
</style>
</head>
<body style="padding: 10px; margin: 10px;">
<div style="margin: 0; padding: 200px 0;">
<span id="text1">hello, I'm sorry but I <a id="text1-link" href="#test">must be going</a>.</span>
</div>
<div style="margin: 0; padding: 200px 0;">
<span id="text2"><a id="text2-link" href="#test">hello, I'm sorry but</a> I must be going.</span>
</div>
</body>
</html>

View File

@ -29,8 +29,8 @@ function checkAutofillMenuItemContents(aItemList)
{
let errors = 0;
let found = 0;
for (let idx = 0; idx < AutofillMenuUI._commands.childNodes.length; idx++) {
let item = AutofillMenuUI._commands.childNodes[idx];
for (let idx = 0; idx < AutofillMenuUI.commands.childNodes.length; idx++) {
let item = AutofillMenuUI.commands.childNodes[idx];
let label = item.firstChild.getAttribute("value");
let value = item.getAttribute("data");
if (aItemList.indexOf(value) == -1) {

View File

@ -138,7 +138,7 @@ gTests.push({
yield promise;
ok(promise && !(promise instanceof Error), "promise error");
ok(ContextMenuUI._menuPopup._visible, "is visible");
ok(ContextMenuUI._menuPopup.visible, "is visible");
let menuItem = document.getElementById("context-copy");
ok(menuItem, "menu item exists");

View File

@ -78,7 +78,7 @@ gTests.push({
sendContextMenuClickToElement(window, edit);
yield waitForEvent(document, "popupshown");
ok(ContextMenuUI._menuPopup._visible, "is visible");
ok(ContextMenuUI._menuPopup.visible, "is visible");
let paste = document.getElementById("context-paste");
ok(!paste.hidden, "paste item is visible");

View File

@ -39,8 +39,8 @@ function setDevPixelEqualToPx()
function checkContextUIMenuItemCount(aCount)
{
let visibleCount = 0;
for (let idx = 0; idx < ContextMenuUI._commands.childNodes.length; idx++) {
if (!ContextMenuUI._commands.childNodes[idx].hidden)
for (let idx = 0; idx < ContextMenuUI.commands.childNodes.length; idx++) {
if (!ContextMenuUI.commands.childNodes[idx].hidden)
visibleCount++;
}
is(visibleCount, aCount, "command list count");
@ -49,8 +49,8 @@ function checkContextUIMenuItemCount(aCount)
function checkContextUIMenuItemVisibility(aVisibleList)
{
let errors = 0;
for (let idx = 0; idx < ContextMenuUI._commands.childNodes.length; idx++) {
let item = ContextMenuUI._commands.childNodes[idx];
for (let idx = 0; idx < ContextMenuUI.commands.childNodes.length; idx++) {
let item = ContextMenuUI.commands.childNodes[idx];
if (aVisibleList.indexOf(item.id) != -1 && item.hidden) {
// item should be visible
errors++;
@ -551,6 +551,20 @@ function logicalCoordsForElement (aElement, aX, aY) {
return coords;
}
function sendContextMenuMouseClickToElement(aWindow, aElement, aX, aY) {
let utils = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
let coords = logicalCoordsForElement(aElement, aX, aY);
utils.sendMouseEventToWindow("mousedown", coords.x, coords.y, 2, 1, 0);
utils.sendMouseEventToWindow("mouseup", coords.x, coords.y, 2, 1, 0);
utils.sendMouseEventToWindow("contextmenu", coords.x, coords.y, 2, 1, 0);
}
function sendMouseClick(aWindow, aX, aY) {
EventUtils.synthesizeMouseAtPoint(aX, aY, {}, aWindow);
}
/*
* sendContextMenuClick - simulates a press-hold touch input event. Event
* is delivered to the main window of the application through the top-level

View File

@ -50,13 +50,65 @@ let ColorUtils = {
return textColor;
},
toCSSRgbColor: function toCSSRgbColor(r, g, b, a) {
var values = [Math.round(r), Math.round(g), Math.round(b)];
if(undefined !== a && a < 1) {
values.push(a);
return 'rgba('+values.join(',')+')';
}
return 'rgb('+values.join(',')+')';
},
/**
* converts a decimal(base10) number into rgb string
* converts a decimal(base10) number into CSS rgb color value string
*/
convertDecimalToRgbColor: function convertDecimalToRgbColor(aColor) {
let r = (aColor & 0xff0000) >> 16;
let g = (aColor & 0x00ff00) >> 8;
let b = (aColor & 0x0000ff);
return "rgb("+r+","+g+","+b+")";
let [r,g,b,a] = this.unpackDecimalColorWord(aColor);
return this.toCSSRgbColor(r,g,b,a);
},
/**
* unpack a decimal(base10) word for r,g,b,a values
*/
unpackDecimalColorWord: function unpackDecimalColorWord(aColor) {
let a = (aColor & 0xff000000) >> 24;
let r = (aColor & 0x00ff0000) >> 16;
let g = (aColor & 0x0000ff00) >> 8;
let b = (aColor & 0x000000ff);
// NB: falsy alpha treated as undefined, fully opaque
return a ? [r,g,b,a/255] : [r,g,b];
},
/**
* create a decimal(base10) word for r,g,b values
*/
createDecimalColorWord: function createDecimalColorWord(r, g, b, a) {
let rgb = 0;
rgb |= b;
rgb |= (g << 8);
rgb |= (r << 16);
// pack alpha value if one is given
if(undefined !== a && a < 1)
rgb |= (Math.round(a*255) << 24);
return rgb;
},
/**
* Add 2 rgb(a) colors to get a flat color
*/
addRgbColors: function addRgbColors(color1, color2) {
let [r1, g1, b1] = this.unpackDecimalColorWord(color1);
let [r2, g2, b2, alpha] = this.unpackDecimalColorWord(color2);
let color = {};
// early return if 2nd color is opaque
if (!alpha || alpha >= 1)
return color2;
return this.createDecimalColorWord(
Math.min(255, alpha * r2 + (1 - alpha) * r1),
Math.min(255, alpha * g2 + (1 - alpha) * g1),
Math.min(255, alpha * b2 + (1 - alpha) * b1)
);
}
};

View File

@ -127,6 +127,7 @@ documenttab[closing] > .documenttab-container {
margin: @metro_spacing_normal@ @metro_spacing_snormal@;
background: white none center top no-repeat;
background-size: cover;
min-width: @thumbnail_width@;
width: @thumbnail_width@;
height: @thumbnail_height@;
}
@ -234,17 +235,18 @@ documenttab[selected] .documenttab-selection {
#start-autocomplete[viewstate="snapped"] .richgrid-item-content {
-moz-box-orient: horizontal;
}
#start-container,
#start-autocomplete {
padding-left: 0;
padding-right: 0;
}
#start-container[viewstate="snapped"] #start-scrollbox > .meta-section {
margin: 0;
margin: 0 @metro_spacing_xnormal@;
min-width: @grid_double_column_width@;
-moz-box-flex: 1;
-moz-box-align: center;
}
#start-container[viewstate="snapped"] richgrid {
visibility: collapse;
}

View File

@ -581,6 +581,16 @@ arrowbox {
cursor: default;
}
#start-container[viewstate="snapped"] {
padding-top: 0;
}
#start-container[viewstate="snapped"] .meta-section-title,
#start-container[viewstate="snapped"] richgrid {
margin-top: @metro_spacing_xnormal@;
padding: 0;
}
#start-container[viewstate="snapped"] .meta-section-title.narrow-title,
#start-container:not([viewstate="snapped"]) .meta-section-title.wide-title {
display: block;

View File

@ -282,4 +282,13 @@ richgriditem[bending] > .tile-content {
background: #fff;
opacity: 1.0;
}
.tile-content {
left: 0;
right: 0;
}
richgriditem {
width: auto;
}
}

View File

@ -290,14 +290,7 @@ let HiddenBrowsers = {
function HiddenBrowser(width, height) {
this.resize(width, height);
HostFrame.get().then(aFrame => {
let doc = aFrame.document;
this._browser = doc.createElementNS(XUL_NS, "browser");
this._browser.setAttribute("type", "content");
this._browser.setAttribute("src", NEWTAB_URL);
doc.getElementById("win").appendChild(this._browser);
});
this._createBrowser();
}
HiddenBrowser.prototype = {
@ -317,7 +310,9 @@ HiddenBrowser.prototype = {
return false;
}
let tabbrowser = aTab.ownerDocument.defaultView.gBrowser;
let win = aTab.ownerDocument.defaultView;
let tabbrowser = win.gBrowser;
if (!tabbrowser) {
return false;
}
@ -325,6 +320,14 @@ HiddenBrowser.prototype = {
// Swap docShells.
tabbrowser.swapNewTabWithBrowser(aTab, this._browser);
// Load all default frame scripts attached to the target window.
let mm = aTab.linkedBrowser.messageManager;
let scripts = win.messageManager.getDelayedFrameScripts();
Array.forEach(scripts, script => mm.loadFrameScript(script, true));
// Remove the browser, it will be recreated by a timer.
this._removeBrowser();
// Start a timer that will kick off preloading the next newtab page.
this._timer = createTimer(this, PRELOADER_INTERVAL_MS);
@ -336,7 +339,7 @@ HiddenBrowser.prototype = {
this._timer = null;
// Start pre-loading the new tab page.
this._browser.loadURI(NEWTAB_URL);
this._createBrowser();
},
resize: function (width, height) {
@ -350,12 +353,25 @@ HiddenBrowser.prototype = {
},
destroy: function () {
this._removeBrowser();
this._timer = clearTimer(this._timer);
},
_createBrowser: function () {
HostFrame.get().then(aFrame => {
let doc = aFrame.document;
this._browser = doc.createElementNS(XUL_NS, "browser");
this._browser.setAttribute("type", "content");
this._browser.setAttribute("src", NEWTAB_URL);
doc.getElementById("win").appendChild(this._browser);
});
},
_removeBrowser: function () {
if (this._browser) {
this._browser.remove();
this._browser = null;
}
this._timer = clearTimer(this._timer);
}
};

View File

@ -5,6 +5,7 @@
#include "nsISupports.idl"
interface nsIDOMDOMStringList;
interface nsIDOMWindow;
interface nsIDocShell;
interface nsIContent;
@ -320,7 +321,7 @@ interface nsIInProcessContentFrameMessageManager : nsIContentFrameMessageManager
[notxpcom] nsIContent getOwnerContent();
};
[scriptable, builtinclass, uuid(a54acd34-4141-46f5-b71b-e2ca32879b08)]
[scriptable, builtinclass, uuid(ecebfb8c-ff51-11e2-9d65-7af553959281)]
interface nsIFrameScriptLoader : nsISupports
{
/**
@ -336,6 +337,12 @@ interface nsIFrameScriptLoader : nsISupports
* Removes aURL from the list of scripts which support delayed load.
*/
void removeDelayedFrameScript(in AString aURL);
/**
* Returns a list of all delayed scripts that will be loaded once
* a (remote) frame becomes available.
*/
nsIDOMDOMStringList getDelayedFrameScripts();
};
[scriptable, builtinclass, uuid(b37821ff-df79-44d4-821c-6d6ec4dfe1e9)]

View File

@ -33,6 +33,7 @@
#include "mozilla/dom/StructuredCloneUtils.h"
#include "JavaScriptChild.h"
#include "JavaScriptParent.h"
#include "nsDOMLists.h"
#include <algorithm>
#ifdef ANDROID
@ -316,6 +317,28 @@ nsFrameMessageManager::RemoveDelayedFrameScript(const nsAString& aURL)
return NS_OK;
}
NS_IMETHODIMP
nsFrameMessageManager::GetDelayedFrameScripts(nsIDOMDOMStringList** aList)
{
// Frame message managers may return an incomplete list because scripts
// that were loaded after it was connected are not added to the list.
if (!IsGlobal() && !IsWindowLevel()) {
NS_WARNING("Cannot retrieve list of pending frame scripts for frame"
"message managers as it may be incomplete");
return NS_ERROR_NOT_IMPLEMENTED;
}
nsRefPtr<nsDOMStringList> scripts = new nsDOMStringList();
for (uint32_t i = 0; i < mPendingScripts.Length(); ++i) {
scripts->Add(mPendingScripts[i]);
}
scripts.forget(aList);
return NS_OK;
}
static JSBool
JSONCreator(const jschar* aBuf, uint32_t aLen, void* aData)
{

View File

@ -96,7 +96,7 @@
"set": [
["dom.ipc.browser_frames.oop_by_default", true],
["dom.mozBrowserFramesEnabled", true],
["browser.pagethumbnails.capturing_disabled", false]
["browser.pagethumbnails.capturing_disabled", true]
]
}, runTests);
});

View File

@ -181,7 +181,7 @@
["dom.ipc.browser_frames.oop_by_default", true],
["dom.mozBrowserFramesEnabled", true],
["browser.pagethumbnails.capturing_disabled", false]
["browser.pagethumbnails.capturing_disabled", true]
]
}, runTests);
});

View File

@ -206,7 +206,7 @@ function expectMozbrowserEvent(iframe, eventName) {
// Set some prefs:
//
// * browser.pagethumbnails.capturing_disabled: false
// * browser.pagethumbnails.capturing_disabled: true
//
// Disable tab view; it seriously messes us up.
//
@ -244,7 +244,7 @@ function expectMozbrowserEvent(iframe, eventName) {
browserElementTestHelpers.lockTestReady();
SpecialPowers.setBoolPref("network.disable.ipc.security", true);
SpecialPowers.pushPrefEnv({set: [["browser.pagethumbnails.capturing_disabled", false],
SpecialPowers.pushPrefEnv({set: [["browser.pagethumbnails.capturing_disabled", true],
["dom.ipc.browser_frames.oop_by_default", oop],
["dom.ipc.tabs.disabled", false],
["security.mixed_content.block_active_content", false]]},

View File

@ -158,7 +158,7 @@
["dom.ipc.browser_frames.oop_by_default", true],
["dom.mozBrowserFramesEnabled", true],
["browser.pagethumbnails.capturing_disabled", false]
["browser.pagethumbnails.capturing_disabled", true]
]
}, runTests);
});

View File

@ -106,7 +106,7 @@ RefTestCmdLineHandler.prototype =
// Setting this pref makes tests run much faster there.
branch.setBoolPref("security.fileuri.strict_origin_policy", false);
// Disable the thumbnailing service
branch.setBoolPref("browser.pagethumbnails.capturing_disabled", false);
branch.setBoolPref("browser.pagethumbnails.capturing_disabled", true);
var wwatch = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
.getService(nsIWindowWatcher);

3
mach
View File

@ -33,8 +33,7 @@ for dir_path in ancestors(os.getcwd()):
# to look for a config file at the path in $MOZCONFIG rather than
# its default locations.
#
# Note: subprocess requires native strings in os.environ Python
# 2.7.2 and earlier on Windows.
# Note: subprocess requires native strings in os.environ on Windows
os.environ[b"MOZCONFIG"] = str(info["mozconfig"])
if "topsrcdir" in info:

View File

@ -478,10 +478,8 @@ pref("security.alternate_certificate_error_page", "certerror");
pref("security.warn_viewing_mixed", false); // Warning is disabled. See Bug 616712.
#ifdef NIGHTLY_BUILD
// Block insecure active content on https pages
pref("security.mixed_content.block_active_content", true);
#endif
// Override some named colors to avoid inverse OS themes
pref("ui.-moz-dialog", "#efebe7");

View File

@ -136,4 +136,13 @@ public class AppConstants {
#else
false;
#endif
// See this wiki page for more details about channel specific build defines:
// https://wiki.mozilla.org/Platform/Channel-specific_build_defines
public static final boolean RELEASE_BUILD =
#ifdef RELEASE_BUILD
true;
#else
false;
#endif
}

View File

@ -1988,8 +1988,7 @@ abstract public class BrowserApp extends GeckoApp
* @return true if update UI was launched.
*/
protected boolean handleUpdaterLaunch() {
if ("release".equals(AppConstants.MOZ_UPDATE_CHANNEL) ||
"beta".equals(AppConstants.MOZ_UPDATE_CHANNEL)) {
if (AppConstants.RELEASE_BUILD) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("market://details?id=" + getPackageName()));
startActivity(intent);

View File

@ -50,6 +50,7 @@ import android.view.Window;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.AlphaAnimation;
import android.view.animation.Interpolator;
import android.view.animation.TranslateAnimation;
@ -89,7 +90,7 @@ public class BrowserToolbar extends GeckoRelativeLayout
public ImageButton mStop;
public ImageButton mSiteSecurity;
public PageActionLayout mPageActionLayout;
private AnimationDrawable mProgressSpinner;
private Animation mProgressSpinner;
private TabCounter mTabsCounter;
private ImageView mShadow;
private GeckoImageButton mMenu;
@ -103,6 +104,7 @@ public class BrowserToolbar extends GeckoRelativeLayout
private boolean mShowSiteSecurity;
private boolean mShowReader;
private boolean mSpinnerVisible;
private boolean mAnimatingEntry;
@ -221,7 +223,7 @@ public class BrowserToolbar extends GeckoRelativeLayout
mSiteSecurityVisible = (mSiteSecurity.getVisibility() == View.VISIBLE);
mActivity.getSiteIdentityPopup().setAnchor(mSiteSecurity);
mProgressSpinner = (AnimationDrawable) res.getDrawable(R.drawable.progress_spinner);
mProgressSpinner = AnimationUtils.loadAnimation(mActivity, R.anim.progress_spinner);
mStop = (ImageButton) findViewById(R.id.stop);
mShadow = (ImageView) findViewById(R.id.shadow);
@ -787,16 +789,26 @@ public class BrowserToolbar extends GeckoRelativeLayout
// are needed by S1/S2 tests (http://mrcote.info/phonedash/#).
// See discussion in Bug 804457. Bug 805124 tracks paring these down.
if (visible) {
mFavicon.setImageDrawable(mProgressSpinner);
mProgressSpinner.start();
mFavicon.setImageResource(R.drawable.progress_spinner);
//To stop the glitch caused by mutiple start() calls.
if (!mSpinnerVisible) {
setPageActionVisibility(true);
mFavicon.setAnimation(mProgressSpinner);
mProgressSpinner.start();
mSpinnerVisible = true;
}
Log.i(LOGTAG, "zerdatime " + SystemClock.uptimeMillis() + " - Throbber start");
} else {
mProgressSpinner.stop();
setPageActionVisibility(false);
Tab selectedTab = Tabs.getInstance().getSelectedTab();
if (selectedTab != null)
setFavicon(selectedTab.getFavicon());
if (mSpinnerVisible) {
setPageActionVisibility(false);
mFavicon.setAnimation(null);
mProgressSpinner.cancel();
mSpinnerVisible = false;
}
Log.i(LOGTAG, "zerdatime " + SystemClock.uptimeMillis() + " - Throbber stop");
}
}

View File

@ -721,6 +721,21 @@ abstract public class GeckoApp
// something went wrong.
Log.e(LOGTAG, "Received Contact:Add message with no email nor phone number");
}
} else if (event.equals("Intent:GetHandlers")) {
Intent intent = GeckoAppShell.getOpenURIIntent(sAppContext, message.optString("url"),
message.optString("mime"), message.optString("action"), message.optString("title"));
String[] handlers = GeckoAppShell.getHandlersForIntent(intent);
ArrayList<String> appList = new ArrayList<String>(handlers.length);
for (int i = 0; i < handlers.length; i++) {
appList.add(handlers[i]);
}
JSONObject handlersJSON = new JSONObject();
handlersJSON.put("apps", new JSONArray(appList));
mCurrentResponse = handlersJSON.toString();
} else if (event.equals("Intent:Open")) {
GeckoAppShell.openUriExternal(message.optString("url"),
message.optString("mime"), message.optString("packageName"),
message.optString("className"), message.optString("action"), message.optString("title"));
}
} catch (Exception e) {
Log.e(LOGTAG, "Exception handling message \"" + event + "\":", e);
@ -1507,6 +1522,8 @@ abstract public class GeckoApp
registerEventListener("Update:Install");
registerEventListener("PrivateBrowsing:Data");
registerEventListener("Contact:Add");
registerEventListener("Intent:Open");
registerEventListener("Intent:GetHandlers");
if (SmsManager.getInstance() != null) {
SmsManager.getInstance().start();
@ -2061,6 +2078,8 @@ abstract public class GeckoApp
unregisterEventListener("Update:Install");
unregisterEventListener("PrivateBrowsing:Data");
unregisterEventListener("Contact:Add");
unregisterEventListener("Intent:Open");
unregisterEventListener("Intent:GetHandlers");
deleteTempFiles();

View File

@ -597,6 +597,7 @@ RES_ANIM = \
res/anim/awesomebar_hold_still.xml \
res/anim/grow_fade_in.xml \
res/anim/grow_fade_in_center.xml \
res/anim/progress_spinner.xml \
res/anim/shrink_fade_out.xml \
$(NULL)
@ -647,18 +648,7 @@ RES_DRAWABLE_MDPI = \
res/drawable-mdpi/ic_menu_reload.png \
res/drawable-mdpi/ic_status_logo.png \
res/drawable-mdpi/icon_pageaction.png \
res/drawable-mdpi/progress_spinner_1.png \
res/drawable-mdpi/progress_spinner_2.png \
res/drawable-mdpi/progress_spinner_3.png \
res/drawable-mdpi/progress_spinner_4.png \
res/drawable-mdpi/progress_spinner_5.png \
res/drawable-mdpi/progress_spinner_6.png \
res/drawable-mdpi/progress_spinner_7.png \
res/drawable-mdpi/progress_spinner_8.png \
res/drawable-mdpi/progress_spinner_9.png \
res/drawable-mdpi/progress_spinner_10.png \
res/drawable-mdpi/progress_spinner_11.png \
res/drawable-mdpi/progress_spinner_12.png \
res/drawable-mdpi/progress_spinner.png \
res/drawable-mdpi/tab_indicator_divider.9.png \
res/drawable-mdpi/tab_indicator_selected.9.png \
res/drawable-mdpi/tab_indicator_selected_focused.9.png \
@ -1118,7 +1108,6 @@ RES_DRAWABLE += \
res/drawable/ic_menu_quit.xml \
res/drawable/menu_item_state.xml \
res/drawable/menu_level.xml \
res/drawable/progress_spinner.xml \
res/drawable/remote_tabs_child_divider.xml \
res/drawable/shaped_button.xml \
res/drawable/site_security_level.xml \

View File

@ -138,8 +138,7 @@ public class UpdateService extends IntentService {
int interval;
if (isRetry) {
interval = INTERVAL_RETRY;
} else if (AppConstants.MOZ_UPDATE_CHANNEL.equals("nightly") ||
AppConstants.MOZ_UPDATE_CHANNEL.equals("aurora")) {
} else if (!AppConstants.RELEASE_BUILD) {
interval = INTERVAL_SHORT;
} else {
interval = INTERVAL_LONG;

View File

@ -20,6 +20,7 @@ import android.content.Context;
import android.content.ContextWrapper;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteConstraintException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Build;
@ -186,7 +187,7 @@ public class HealthReportDatabaseStorage implements HealthReportStorage {
protected final HealthReportSQLiteOpenHelper helper;
public static class HealthReportSQLiteOpenHelper extends SQLiteOpenHelper {
public static final int CURRENT_VERSION = 4;
public static final int CURRENT_VERSION = 5;
public static final String LOG_TAG = "HealthReportSQL";
/**
@ -227,11 +228,16 @@ public class HealthReportDatabaseStorage implements HealthReportStorage {
public static boolean CAN_USE_ABSOLUTE_DB_PATH = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO);
public HealthReportSQLiteOpenHelper(Context context, File profileDirectory, String name) {
this(context, profileDirectory, name, CURRENT_VERSION);
}
// For testing DBs of different versions.
public HealthReportSQLiteOpenHelper(Context context, File profileDirectory, String name, int version) {
super(
(CAN_USE_ABSOLUTE_DB_PATH ? context : new AbsolutePathContext(context, profileDirectory)),
(CAN_USE_ABSOLUTE_DB_PATH ? getAbsolutePath(profileDirectory, name) : name),
null,
CURRENT_VERSION);
version);
if (CAN_USE_ABSOLUTE_DB_PATH) {
Logger.pii(LOG_TAG, "Opening: " + getAbsolutePath(profileDirectory, name));
@ -347,6 +353,13 @@ public class HealthReportDatabaseStorage implements HealthReportStorage {
}
}
@Override
public void onOpen(SQLiteDatabase db) {
if (!db.isReadOnly()) {
db.execSQL("PRAGMA foreign_keys=ON;");
}
}
private void createAddonsEnvironmentsView(SQLiteDatabase db) {
db.execSQL("CREATE VIEW environments_with_addons AS " +
"SELECT e.id AS id, " +
@ -394,6 +407,22 @@ public class HealthReportDatabaseStorage implements HealthReportStorage {
" WHERE measurement IN (SELECT id FROM measurements WHERE name = 'org.mozilla.searches.counts')");
}
private void upgradeDatabaseFrom4to5(SQLiteDatabase db) {
// Delete NULL in addons.body, which appeared as a result of Bug 886156. Note that the
// foreign key constraint, "ON DELETE RESTRICT", may be violated, but since onOpen() is
// called after this method, foreign keys are not yet enabled and constraints can be broken.
db.delete("addons", "body IS NULL", null);
// Purge any data inconsistent with foreign key references (which may have appeared before
// foreign keys were enabled in Bug 900289).
db.delete("fields", "measurement NOT IN (SELECT id FROM measurements)", null);
db.delete("environments", "addonsID NOT IN (SELECT id from addons)", null);
db.delete(EVENTS_INTEGER, "env NOT IN (SELECT id FROM environments)", null);
db.delete(EVENTS_TEXTUAL, "env NOT IN (SELECT id FROM environments)", null);
db.delete(EVENTS_INTEGER, "field NOT IN (SELECT id FROM fields)", null);
db.delete(EVENTS_TEXTUAL, "field NOT IN (SELECT id FROM fields)", null);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (oldVersion >= newVersion) {
@ -408,6 +437,8 @@ public class HealthReportDatabaseStorage implements HealthReportStorage {
upgradeDatabaseFrom2To3(db);
case 3:
upgradeDatabaseFrom3To4(db);
case 4:
upgradeDatabaseFrom4to5(db);
}
db.setTransactionSuccessful();
} catch (Exception e) {
@ -1031,7 +1062,11 @@ public class HealthReportDatabaseStorage implements HealthReportStorage {
v.put("env", env);
v.put("field", field);
v.put("date", day);
db.insert(table, null, v);
try {
db.insertOrThrow(table, null, v);
} catch (SQLiteConstraintException e) {
throw new IllegalStateException("Event did not reference existing an environment or field.", e);
}
}
}
@ -1063,7 +1098,11 @@ public class HealthReportDatabaseStorage implements HealthReportStorage {
final SQLiteDatabase db = this.helper.getWritableDatabase();
putValue(v, value);
db.insert(table, null, v);
try {
db.insertOrThrow(table, null, v);
} catch (SQLiteConstraintException e) {
throw new IllegalStateException("Event did not reference existing an environment or field.", e);
}
}
@Override
@ -1133,7 +1172,11 @@ public class HealthReportDatabaseStorage implements HealthReportStorage {
v.put("value", by);
v.put("field", field);
v.put("date", day);
db.insert(EVENTS_INTEGER, null, v);
try {
db.insertOrThrow(EVENTS_INTEGER, null, v);
} catch (SQLiteConstraintException e) {
throw new IllegalStateException("Event did not reference existing an environment or field.", e);
}
}
}

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/linear_interpolator">
<rotate android:duration="1200"
android:fromDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:repeatCount="infinite"
android:toDegrees="360"/>
</set>

View File

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -1,22 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<item android:duration="100" android:drawable="@drawable/progress_spinner_1"/>
<item android:duration="100" android:drawable="@drawable/progress_spinner_2"/>
<item android:duration="100" android:drawable="@drawable/progress_spinner_3"/>
<item android:duration="100" android:drawable="@drawable/progress_spinner_4"/>
<item android:duration="100" android:drawable="@drawable/progress_spinner_5"/>
<item android:duration="100" android:drawable="@drawable/progress_spinner_6"/>
<item android:duration="100" android:drawable="@drawable/progress_spinner_7"/>
<item android:duration="100" android:drawable="@drawable/progress_spinner_8"/>
<item android:duration="100" android:drawable="@drawable/progress_spinner_9"/>
<item android:duration="100" android:drawable="@drawable/progress_spinner_10"/>
<item android:duration="100" android:drawable="@drawable/progress_spinner_11"/>
<item android:duration="100" android:drawable="@drawable/progress_spinner_12"/>
</animation-list>

View File

@ -75,8 +75,9 @@
android:layout_width="@dimen/browser_toolbar_favicon_size"
android:layout_height="fill_parent"
android:scaleType="fitCenter"
android:paddingLeft="8dip"
android:layout_marginRight="4dip"
android:layout_marginLeft="4dip"
android:paddingLeft="4dip"
android:paddingRight="4dip"
android:layout_gravity="center_vertical"
android:src="@drawable/favicon"/>

View File

@ -101,8 +101,9 @@
android:layout_width="@dimen/browser_toolbar_favicon_size"
android:layout_height="fill_parent"
android:scaleType="fitCenter"
android:paddingLeft="12dip"
android:layout_marginRight="4dip"
android:layout_marginLeft="8dip"
android:paddingLeft="4dip"
android:paddingRight="4dip"
android:layout_gravity="center_vertical"
android:src="@drawable/favicon"/>

View File

@ -30,7 +30,7 @@
<dimen name="browser_toolbar_button_padding">12dp</dimen>
<dimen name="browser_toolbar_icon_width">48dp</dimen>
<dimen name="browser_toolbar_lock_width">20dp</dimen>
<dimen name="browser_toolbar_favicon_size">29.33dip</dimen>
<dimen name="browser_toolbar_favicon_size">25.33dip</dimen>
<dimen name="favicon_bg">32dp</dimen>
<dimen name="favicon_bg_radius">1dp</dimen>

View File

@ -3,6 +3,19 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
XPCOMUtils.defineLazyGetter(this, "ContentAreaUtils", function() {
let ContentAreaUtils = {};
Services.scriptloader.loadSubScript("chrome://global/content/contentAreaUtils.js", ContentAreaUtils);
return ContentAreaUtils;
});
function getBridge() {
return Cc["@mozilla.org/android/bridge;1"].getService(Ci.nsIAndroidBridge);
}
function sendMessageToJava(aMessage) {
return getBridge().handleGeckoMessage(JSON.stringify(aMessage));
}
var HelperApps = {
get defaultHttpHandlers() {
@ -37,25 +50,51 @@ var HelperApps = {
getAppsForUri: function getAppsFor(uri) {
let found = [];
let handlerInfoProto = this.urlHandlerService.getURLHandlerInfoFromOS(uri, {});
let urlHandlers = handlerInfoProto.possibleApplicationHandlers;
for (var i = 0; i < urlHandlers.length; i++) {
let urlApp = urlHandlers.queryElementAt(i, Ci.nsIHandlerApp);
if (!this.defaultHttpHandlers[urlApp.name]) {
found.push(urlApp);
}
let mimeType = ContentAreaUtils.getMIMETypeForURI(uri) || "";
// empty action string defaults to android.intent.action.VIEW
let msg = {
type: "Intent:GetHandlers",
mime: mimeType,
action: "",
url: uri.spec,
packageName: "",
className: ""
};
let apps = this._parseApps(JSON.parse(sendMessageToJava(msg)));
for (let i = 0; i < apps.length; i++) {
let appName = apps[i].name;
if (appName.length > 0 && !this.defaultHttpHandlers[appName])
found.push(apps[i]);
}
return found;
},
openUriInApp: function openUriInApp(uri) {
var possibleHandlers = this.getAppsForUri(uri);
if (possibleHandlers.length == 1) {
possibleHandlers[0].launchWithURI(uri);
} else if (possibleHandlers.length > 0) {
let handlerInfoProto = this.urlHandlerService.getURLHandlerInfoFromOS(uri, {});
handlerInfoProto.preferredApplicationHandler.launchWithURI(uri);
let mimeType = ContentAreaUtils.getMIMETypeForURI(uri) || "";
let msg = {
type: "Intent:Open",
mime: mimeType,
action: "",
url: uri.spec,
packageName: "",
className: ""
};
sendMessageToJava(msg);
},
_parseApps: function _parseApps(aJSON) {
// aJSON -> {apps: [app1Label, app1Default, app1PackageName, app1ActivityName, app2Label, app2Defaut, ...]}
// see GeckoAppShell.java getHandlersForIntent function for details
let appInfo = aJSON.apps;
const numAttr = 4; // 4 elements per ResolveInfo: label, default, package name, activity name.
let apps = [];
for (let i = 0; i < appInfo.length; i += numAttr) {
apps.push({"name" : appInfo[i],
"isDefault" : appInfo[i+1],
"packageName" : appInfo[i+2],
"activityName" : appInfo[i+3]});
}
return apps;
},
showDoorhanger: function showDoorhanger(aUri, aCallback) {

View File

@ -41,7 +41,6 @@ var ContextMenus = {
document.getElementById("contextmenu-enable").setAttribute("hidden", "true");
document.getElementById("contextmenu-disable").setAttribute("hidden", "true");
document.getElementById("contextmenu-uninstall").setAttribute("hidden", "true");
document.getElementById("contextmenu-default").setAttribute("hidden", "true");
return;
}
@ -60,8 +59,6 @@ var ContextMenus = {
document.getElementById("contextmenu-enable").removeAttribute("hidden");
document.getElementById("contextmenu-disable").setAttribute("hidden", "true");
}
document.getElementById("contextmenu-default").setAttribute("hidden", "true");
},
enable: function(event) {
@ -253,37 +250,6 @@ var Addons = {
list.appendChild(item);
}
// Load the search engines
let defaults = Services.search.getDefaultEngines({ }).map(function (e) e.name);
function isDefault(aEngine)
defaults.indexOf(aEngine.name) != -1
let defaultDescription = gStringBundle.GetStringFromName("addonsSearchEngine.description");
let engines = Services.search.getEngines({ });
for (let e = 0; e < engines.length; e++) {
let engine = engines[e];
let addon = {};
addon.id = engine.name;
addon.type = "search";
addon.name = engine.name;
addon.version = "";
addon.description = engine.description || defaultDescription;
addon.iconURL = engine.iconURI ? engine.iconURI.spec : "";
addon.optionsURL = "";
addon.appDisabled = false;
addon.scope = isDefault(engine) ? AddonManager.SCOPE_APPLICATION : AddonManager.SCOPE_PROFILE;
addon.engine = engine;
let item = self._createItem(addon);
item.setAttribute("isDisabled", engine.hidden);
item.setAttribute("updateable", "false");
item.setAttribute("opType", "");
item.setAttribute("optionsURL", "");
item.addon = addon;
list.appendChild(item);
}
// Add a "Browse all Firefox Add-ons" item to the bottom of the list.
let browseItem = self._createBrowseItem();
list.appendChild(browseItem);
@ -348,9 +314,6 @@ var Addons = {
else
uninstallBtn.removeAttribute("disabled");
let defaultButton = document.getElementById("default-btn");
defaultButton.setAttribute("hidden", "true");
let box = document.querySelector("#addons-details > .addon-item .options-box");
box.innerHTML = "";

View File

@ -7631,12 +7631,26 @@ let Reader = {
var ExternalApps = {
_contextMenuId: -1,
// extend _getLink to pickup html5 media links.
_getMediaLink: function(aElement) {
let uri = NativeWindow.contextmenus._getLink(aElement);
if (uri == null) {
if (aElement.nodeType == Ci.nsIDOMNode.ELEMENT_NODE && (aElement instanceof Ci.nsIDOMHTMLMediaElement && mediaSrc)) {
try {
let mediaSrc = aElement.currentSrc || aElement.src;
uri = ContentAreaUtils.makeURI(mediaSrc, null, null);
} catch (e) {}
}
}
return uri;
},
init: function helper_init() {
this._contextMenuId = NativeWindow.contextmenus.add(function(aElement) {
let uri = null;
var node = aElement;
while (node && !uri) {
uri = NativeWindow.contextmenus._getLink(node);
uri = ExternalApps._getMediaLink(node);
node = node.parentNode;
}
let apps = [];
@ -7654,7 +7668,7 @@ var ExternalApps = {
filter: {
matches: function(aElement) {
let uri = NativeWindow.contextmenus._getLink(aElement);
let uri = ExternalApps._getMediaLink(aElement);
let apps = [];
if (uri) {
apps = HelperApps.getAppsForUri(uri);
@ -7664,7 +7678,7 @@ var ExternalApps = {
},
openExternal: function(aElement) {
let uri = NativeWindow.contextmenus._getLink(aElement);
let uri = ExternalApps._getMediaLink(aElement);
HelperApps.openUriInApp(uri);
}
};

View File

@ -59,7 +59,8 @@ class MachCommands(MachCommandBase):
return self.run_process([self.python_executable] + args,
pass_thru=True, # Allow user to run Python interactively.
ensure_exit_code=False, # Don't throw on non-zero exit code.
append_env={'PYTHONDONTWRITEBYTECODE': '1'})
# Note: subprocess requires native strings in os.environ on Windows
append_env={b'PYTHONDONTWRITEBYTECODE': str('1')})
@Command('python-test', category='testing',
description='Run Python unit tests.')
@ -109,7 +110,8 @@ class MachCommands(MachCommandBase):
[self.python_executable, file],
ensure_exit_code=False, # Don't throw on non-zero exit code.
log_name='python-test',
append_env={'PYTHONDONTWRITEBYTECODE': '1'},
# subprocess requires native strings in os.environ on Windows
append_env={b'PYTHONDONTWRITEBYTECODE': str('1')},
line_handler=_line_handler)
return_code += inner_return_code

View File

@ -149,7 +149,6 @@ class MochitestRunner(MozbuildObject):
return 1
options.testPath = test_path
env = {'TEST_PATH': test_path}
if rerun_failures:
options.testManifest = failure_file_path

View File

@ -147,4 +147,4 @@ user_pref("geo.provider.testing", true);
// Background thumbnails in particular cause grief, and disabling thumbnails
// in general can't hurt - we re-enable them when tests need them.
user_pref("browser.pagethumbnails.capturing_disabled", false);
user_pref("browser.pagethumbnails.capturing_disabled", true);

View File

@ -465,7 +465,7 @@ this.PageThumbs = {
_prefEnabled: function PageThumbs_prefEnabled() {
try {
return Services.prefs.getBoolPref("browser.pagethumbnails.capturing_disabled");
return !Services.prefs.getBoolPref("browser.pagethumbnails.capturing_disabled");
}
catch (e) {
return true;

View File

@ -11,7 +11,7 @@ let {PageThumbs, PageThumbsStorage, SessionStore, FileUtils, OS} = tmp;
Cu.import("resource://gre/modules/PlacesUtils.jsm");
let oldEnabledPref = Services.prefs.getBoolPref("browser.pagethumbnails.capturing_disabled");
Services.prefs.setBoolPref("browser.pagethumbnails.capturing_disabled", true);
Services.prefs.setBoolPref("browser.pagethumbnails.capturing_disabled", false);
registerCleanupFunction(function () {
while (gBrowser.tabs.length > 1)

View File

@ -111,11 +111,12 @@ function getCtorName(aObj) {
*
* @param {any} aThing
* The object to be stringified
* @param {boolean} aAllowNewLines
* @return {string}
* A single line representation of aThing, which will generally be at
* most 80 chars long
*/
function stringify(aThing) {
function stringify(aThing, aAllowNewLines) {
if (aThing === undefined) {
return "undefined";
}
@ -145,7 +146,10 @@ function stringify(aThing) {
return aThing.toString().replace(/\s+/g, " ");
}
let str = aThing.toString().replace(/\n/g, "|");
let str = aThing.toString();
if (!aAllowNewLines) {
str = str.replace(/\n/g, "|");
}
return str;
}
@ -465,9 +469,9 @@ function createDumper(aLevel) {
let frame = getStack(Components.stack.caller, 1)[0];
sendConsoleAPIMessage(aLevel, frame, args);
let data = args.map(function(arg) {
return stringify(arg);
return stringify(arg, true);
});
dumpMessage(this, aLevel, data.join(", "));
dumpMessage(this, aLevel, data.join(" "));
};
}