Merge fx-team to m-c. a=merge

This commit is contained in:
Ryan VanderMeulen 2014-09-03 15:35:54 -04:00
commit 269c98033b
144 changed files with 1384 additions and 781 deletions

View File

@ -7,22 +7,27 @@ module.metadata = {
};
const { Cc, Ci, Cu } = require('chrome');
const { isNative } = require('@loader/options');
const { rootURI, metadata, isNative } = require('@loader/options');
const { id, loadReason } = require('../self');
const { descriptor, Sandbox, evaluate, main, resolveURI } = require('toolkit/loader');
const { once } = require('../system/events');
const { exit, env, staticArgs } = require('../system');
const { when: unload } = require('../system/unload');
const { loadReason } = require('../self');
const { rootURI, metadata } = require("@loader/options");
const globals = require('../system/globals');
const xulApp = require('../system/xul-app');
const { id } = require('sdk/self');
const { get } = require('../preferences/service');
const appShellService = Cc['@mozilla.org/appshell/appShellService;1'].
getService(Ci.nsIAppShellService);
const { preferences } = metadata;
const Startup = Cu.import("resource://gre/modules/sdk/system/Startup.js", {}).exports;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyGetter(this, "BrowserToolboxProcess", function () {
return Cu.import("resource:///modules/devtools/ToolboxProcess.jsm", {}).
BrowserToolboxProcess;
});
// Initializes default preferences
function setDefaultPrefs(prefsURI) {
const prefs = Cc['@mozilla.org/preferences-service;1'].
@ -102,7 +107,9 @@ function run(options) {
// native-options does stuff directly with preferences key from package.json
if (preferences && preferences.length > 0) {
try {
require('../preferences/native-options').enable({ preferences: preferences, id: id });
require('../preferences/native-options').
enable({ preferences: preferences, id: id }).
catch(console.exception);
}
catch (error) {
console.exception(error);
@ -141,7 +148,6 @@ function run(options) {
unload(program.onUnload);
if (typeof(program.main) === 'function') {
program.main({
loadReason: loadReason,
staticArgs: staticArgs
@ -150,6 +156,10 @@ function run(options) {
quit: exit
});
}
if (get("extensions." + id + ".sdk.debug.show", false)) {
BrowserToolboxProcess.init({ addonID: id });
}
} catch (error) {
console.exception(error);
throw error;

View File

@ -55,6 +55,10 @@ DEFAULT_NO_CONNECTIONS_PREFS = {
# Disable app update
'app.update.enabled' : False,
# Disable about:newtab content fetch and ping
'browser.newtabpage.directory.source': 'data:application/json,{"jetpack":1}',
'browser.newtabpage.directory.ping': '',
# Point update checks to a nonexistent local URL for fast failures.
'extensions.update.url' : 'http://localhost/extensions-dummy/updateURL',
'extensions.blocklist.url' : 'http://localhost/extensions-dummy/blocklistURL',

View File

@ -0,0 +1,17 @@
/* 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/. */
'use strict';
const { Cu } = require('chrome');
const self = require('sdk/self');
const { AddonManager } = Cu.import('resource://gre/modules/AddonManager.jsm', {});
exports.testContributors = function(assert, done) {
AddonManager.getAddonByID(self.id, (addon) => {
assert.equal(addon.creator.name, 'test <test@mozilla.com>', '< and > characters work');
done();
});
}
require('sdk/test/runner').runTestsFromModule(module);

View File

@ -0,0 +1,4 @@
{
"id": "test-addon-author-email@jetpack",
"author": "test <test@mozilla.com>"
}

View File

@ -76,7 +76,7 @@ exports['test `load` events'] = function(assert, done) {
});
};
exports['test removeing listeners'] = function(assert, done) {
exports['test removing listeners'] = function(assert, done) {
Loader({
onLoad: function(window) {
assert.equal(window, this._window, 'windows should match');

View File

@ -10,18 +10,6 @@
* Tab previews utility, produces thumbnails
*/
var tabPreviews = {
aspectRatio: 0.5625, // 16:9
get width() {
delete this.width;
return this.width = Math.ceil(screen.availWidth / 5.75);
},
get height() {
delete this.height;
return this.height = Math.round(this.width * this.aspectRatio);
},
init: function tabPreviews_init() {
if (this._selectedTab)
return;
@ -29,6 +17,12 @@ var tabPreviews = {
gBrowser.tabContainer.addEventListener("TabSelect", this, false);
gBrowser.tabContainer.addEventListener("SSTabRestored", this, false);
let screenManager = Cc["@mozilla.org/gfx/screenmanager;1"]
.getService(Ci.nsIScreenManager);
let left = {}, top = {}, width = {}, height = {};
screenManager.primaryScreen.GetRectDisplayPix(left, top, width, height);
this.aspectRatio = height.value / width.value;
},
get: function tabPreviews_get(aTab) {
@ -52,31 +46,35 @@ var tabPreviews = {
return this.capture(aTab, !aTab.hasAttribute("busy"));
},
capture: function tabPreviews_capture(aTab, aStore) {
var thumbnail = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
thumbnail.mozOpaque = true;
thumbnail.height = this.height;
thumbnail.width = this.width;
capture: function tabPreviews_capture(aTab, aShouldCache) {
let browser = aTab.linkedBrowser;
let uri = browser.currentURI.spec;
// drawWindow doesn't yet work with e10s (bug 698371)
if (gMultiProcessBrowser)
return thumbnail;
// FIXME: The gBrowserThumbnails._shouldCapture determines whether
// thumbnails should be written to disk. This should somehow be part
// of the PageThumbs API. (bug 1062414)
if (aShouldCache &&
gBrowserThumbnails._shouldCapture(browser)) {
let img = new Image;
var ctx = thumbnail.getContext("2d");
var win = aTab.linkedBrowser.contentWindow;
var snippetWidth = win.innerWidth * .6;
var scale = this.width / snippetWidth;
ctx.scale(scale, scale);
ctx.drawWindow(win, win.scrollX, win.scrollY,
snippetWidth, snippetWidth * this.aspectRatio, "rgb(255,255,255)");
PageThumbs.captureAndStore(browser, function () {
img.src = PageThumbs.getThumbnailURL(uri);
});
if (aStore &&
aTab.linkedBrowser /* bug 795608: the tab may got removed while drawing the thumbnail */) {
aTab.__thumbnail = thumbnail;
aTab.__thumbnail_lastURI = aTab.linkedBrowser.currentURI.spec;
aTab.__thumbnail = img;
aTab.__thumbnail_lastURI = uri;
return img;
}
return thumbnail;
let canvas = PageThumbs.createCanvas(window);
if (aShouldCache) {
aTab.__thumbnail = canvas;
aTab.__thumbnail_lastURI = uri;
}
PageThumbs.captureToCanvas(aTab.linkedBrowser.contentWindow, canvas);
return canvas;
},
handleEvent: function tabPreviews_handleEvent(event) {
@ -182,8 +180,7 @@ var ctrlTab = {
get isOpen () this.panel.state == "open" || this.panel.state == "showing" || this._timer,
get tabCount () this.tabList.length,
get tabPreviewCount () Math.min(this.previews.length - 1, this.tabCount),
get canvasWidth () Math.min(tabPreviews.width,
Math.ceil(screen.availWidth * .85 / this.tabPreviewCount)),
get canvasWidth () Math.ceil(screen.availWidth * .85 / this.tabPreviewCount),
get canvasHeight () Math.round(this.canvasWidth * tabPreviews.aspectRatio),
get tabList () {
@ -505,6 +502,15 @@ var ctrlTab = {
}
},
filterForThumbnailExpiration: function (aCallback) {
let urls = [];
let previewCount = this.tabPreviewCount;
for (let i = 0; i < previewCount; i++)
urls.push(this.tabList[i].linkedBrowser.currentURI.spec);
aCallback(urls);
},
_initRecentlyUsedTabs: function () {
this._recentlyUsedTabs =
Array.filter(gBrowser.tabs, tab => !tab.closing)
@ -525,6 +531,11 @@ var ctrlTab = {
document[toggleEventListener]("keypress", this, false);
gBrowser.mTabBox.handleCtrlTab = !enable;
if (enable)
PageThumbs.addExpirationFilter(this);
else
PageThumbs.removeExpirationFilter(this);
// If we're not running, hide the "Show All Tabs" menu item,
// as Shift+Ctrl+Tab will be handled by the tab bar.
document.getElementById("menu_showAllTabs").hidden = !enable;

View File

@ -103,7 +103,9 @@ let gBrowserThumbnails = {
},
_capture: function Thumbnails_capture(aBrowser) {
if (this._shouldCapture(aBrowser))
// Only capture about:newtab top sites.
if (this._topSiteURLs.indexOf(aBrowser.currentURI.spec) >= 0 &&
this._shouldCapture(aBrowser))
PageThumbs.captureAndStoreIfStale(aBrowser);
},
@ -121,15 +123,12 @@ let gBrowserThumbnails = {
this._timeouts.set(aBrowser, timeout);
},
// FIXME: This should be part of the PageThumbs API. (bug 1062414)
_shouldCapture: function Thumbnails_shouldCapture(aBrowser) {
// Capture only if it's the currently selected tab.
if (aBrowser != gBrowser.selectedBrowser)
return false;
// Only capture about:newtab top sites.
if (this._topSiteURLs.indexOf(aBrowser.currentURI.spec) < 0)
return false;
// Don't capture in per-window private browsing mode.
if (PrivateBrowsingUtils.isWindowPrivate(window))
return false;

View File

@ -672,33 +672,17 @@ var gPopupBlockerObserver = {
}
};
function gKeywordURIFixup(fixupInfo, topic, data) {
fixupInfo.QueryInterface(Ci.nsIURIFixupInfo);
function gKeywordURIFixup({ target: browser, data: fixupInfo }) {
let deserializeURI = (spec) => spec ? makeURI(spec) : null;
// We get called irrespective of whether we did a keyword search, or
// whether the original input would be vaguely interpretable as a URL,
// so figure that out first.
let alternativeURI = fixupInfo.fixedURI;
let alternativeURI = deserializeURI(fixupInfo.fixedURI);
if (!fixupInfo.fixupUsedKeyword || !alternativeURI) {
return;
}
// We should have a document loader...
let docshellRef = fixupInfo.consumer;
try {
docshellRef.QueryInterface(Ci.nsIDocumentLoader);
} catch (ex) {
return;
}
if (!docshellRef.document)
return;
// ... from which we can deduce the browser
let browser = gBrowser.getBrowserForDocument(docshellRef.document);
if (!browser)
return;
// At this point we're still only just about to load this URI.
// When the async DNS lookup comes back, we may be in any of these states:
// 1) still on the previous URI, waiting for the preferredURI (keyword
@ -708,6 +692,7 @@ function gKeywordURIFixup(fixupInfo, topic, data) {
// We keep track of the currentURI to detect case (1) in the DNS lookup
// callback.
let previousURI = browser.currentURI;
let preferredURI = deserializeURI(fixupInfo.preferredURI);
// now swap for a weak ref so we don't hang on to browser needlessly
// even if the DNS query takes forever
@ -738,7 +723,7 @@ function gKeywordURIFixup(fixupInfo, topic, data) {
let currentURI = browser.currentURI;
// If we're in case (3) (see above), don't show an info bar.
if (!currentURI.equals(previousURI) &&
!currentURI.equals(fixupInfo.preferredURI)) {
!currentURI.equals(preferredURI)) {
return;
}
@ -1025,15 +1010,12 @@ var gBrowserInit = {
// This pageshow listener needs to be registered before we may call
// swapBrowsersAndCloseOther() to receive pageshow events fired by that.
if (!gMultiProcessBrowser) {
// pageshow handlers are being migrated to
// content.js. Eventually this code should be removed.
gBrowser.addEventListener("pageshow", function(event) {
// Filter out events that are not about the document load we are interested in
if (content && event.target == content.document)
setTimeout(pageShowEventHandlers, 0, event.persisted);
}, true);
}
let mm = window.messageManager;
mm.addMessageListener("PageVisibility:Show", function(message) {
if (message.target == gBrowser.selectedBrowser) {
setTimeout(pageShowEventHandlers, 0, message.data.persisted);
}
});
if (uriToLoad && uriToLoad != "about:blank") {
if (uriToLoad instanceof Ci.nsISupportsArray) {
@ -1087,7 +1069,7 @@ var gBrowserInit = {
Services.obs.addObserver(gXPInstallObserver, "addon-install-blocked", false);
Services.obs.addObserver(gXPInstallObserver, "addon-install-failed", false);
Services.obs.addObserver(gXPInstallObserver, "addon-install-complete", false);
Services.obs.addObserver(gKeywordURIFixup, "keyword-uri-fixup", false);
window.messageManager.addMessageListener("Browser:URIFixup", gKeywordURIFixup);
BrowserOffline.init();
OfflineApps.init();
@ -1393,7 +1375,7 @@ var gBrowserInit = {
Services.obs.removeObserver(gXPInstallObserver, "addon-install-blocked");
Services.obs.removeObserver(gXPInstallObserver, "addon-install-failed");
Services.obs.removeObserver(gXPInstallObserver, "addon-install-complete");
Services.obs.removeObserver(gKeywordURIFixup, "keyword-uri-fixup");
window.messageManager.removeMessageListener("Browser:URIFixup", gKeywordURIFixup);
try {
gPrefService.removeObserver(gHomeButton.prefDomain, gHomeButton);
@ -3561,42 +3543,11 @@ var XULBrowserWindow = {
// Called before links are navigated to to allow us to retarget them if needed.
onBeforeLinkTraversal: function(originalTarget, linkURI, linkNode, isAppTab) {
let target = this._onBeforeLinkTraversal(originalTarget, linkURI, linkNode, isAppTab);
let target = BrowserUtils.onBeforeLinkTraversal(originalTarget, linkURI, linkNode, isAppTab);
SocialUI.closeSocialPanelForLinkTraversal(target, linkNode);
return target;
},
_onBeforeLinkTraversal: function(originalTarget, linkURI, linkNode, isAppTab) {
// Don't modify non-default targets or targets that aren't in top-level app
// tab docshells (isAppTab will be false for app tab subframes).
if (originalTarget != "" || !isAppTab)
return originalTarget;
// External links from within app tabs should always open in new tabs
// instead of replacing the app tab's page (Bug 575561)
let linkHost;
let docHost;
try {
linkHost = linkURI.host;
docHost = linkNode.ownerDocument.documentURIObject.host;
} catch(e) {
// nsIURI.host can throw for non-nsStandardURL nsIURIs.
// If we fail to get either host, just return originalTarget.
return originalTarget;
}
if (docHost == linkHost)
return originalTarget;
// Special case: ignore "www" prefix if it is part of host string
let [longHost, shortHost] =
linkHost.length > docHost.length ? [linkHost, docHost] : [docHost, linkHost];
if (longHost == "www." + shortHost)
return originalTarget;
return "_blank";
},
onProgressChange: function (aWebProgress, aRequest,
aCurSelfProgress, aMaxSelfProgress,
aCurTotalProgress, aMaxTotalProgress) {
@ -7367,9 +7318,17 @@ let ToolbarIconColor = {
toolbarSelector += ":not([type=menubar])";
#endif
// The getComputedStyle calls and setting the brighttext are separated in
// two loops to avoid flushing layout and making it dirty repeatedly.
let luminances = new Map;
for (let toolbar of document.querySelectorAll(toolbarSelector)) {
let [r, g, b] = parseRGB(getComputedStyle(toolbar).color);
let luminance = 0.2125 * r + 0.7154 * g + 0.0721 * b;
luminances.set(toolbar, luminance);
}
for (let [toolbar, luminance] of luminances) {
if (luminance <= 110)
toolbar.removeAttribute("brighttext");
else

View File

@ -633,3 +633,54 @@ let DOMFullscreenHandler = {
}
};
DOMFullscreenHandler.init();
function gKeywordURIFixup(fixupInfo) {
fixupInfo.QueryInterface(Ci.nsIURIFixupInfo);
// Ignore info from other docshells
let parent = fixupInfo.consumer.QueryInterface(Ci.nsIDocShellTreeItem).sameTypeRootTreeItem;
if (parent != docShell)
return;
let data = {};
for (let f of Object.keys(fixupInfo)) {
if (f == "consumer" || typeof fixupInfo[f] == "function")
continue;
if (fixupInfo[f] && fixupInfo[f] instanceof Ci.nsIURI) {
data[f] = fixupInfo[f].spec;
} else {
data[f] = fixupInfo[f];
}
}
sendAsyncMessage("Browser:URIFixup", data);
}
Services.obs.addObserver(gKeywordURIFixup, "keyword-uri-fixup", false);
addEventListener("unload", () => {
Services.obs.removeObserver(gKeywordURIFixup, "keyword-uri-fixup");
}, false);
addMessageListener("Browser:AppTab", function(message) {
docShell.isAppTab = message.data.isAppTab;
});
let WebBrowserChrome = {
onBeforeLinkTraversal: function(originalTarget, linkURI, linkNode, isAppTab) {
return BrowserUtils.onBeforeLinkTraversal(originalTarget, linkURI, linkNode, isAppTab);
},
};
if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT) {
let tabchild = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsITabChild);
tabchild.webBrowserChrome = WebBrowserChrome;
}
addEventListener("pageshow", function(event) {
if (event.target == content.document) {
sendAsyncMessage("PageVisibility:Show", {
persisted: event.persisted,
});
}
});

View File

@ -289,9 +289,7 @@
this.tabContainer._positionPinnedTabs();
this.tabContainer.adjustTabstrip();
// Bug 961867 - [e10s] Implement the logic for app tabs
if (!gMultiProcessBrowser)
this.getBrowserForTab(aTab).docShell.isAppTab = true;
this.getBrowserForTab(aTab).messageManager.sendAsyncMessage("Browser:AppTab", { isAppTab: true })
if (aTab.selected)
this._setCloseKeyState(false);
@ -315,9 +313,7 @@
this.tabContainer._positionPinnedTabs();
this.tabContainer.adjustTabstrip();
// Bug 961867 - [e10s] Implement the logic for app tabs
if (!gMultiProcessBrowser)
this.getBrowserForTab(aTab).docShell.isAppTab = false;
this.getBrowserForTab(aTab).messageManager.sendAsyncMessage("Browser:AppTab", { isAppTab: false })
if (aTab.selected)
this._setCloseKeyState(true);
@ -5330,7 +5326,8 @@
let switchPromise = gBrowser._prepareForTabSwitch(toTab, fromTab);
var panel = this._selectedPanel;
this._selectedPanel = this.childNodes[val];
var newPanel = this.childNodes[val];
this._selectedPanel = newPanel;
if (this._selectedPanel != panel) {
var event = document.createEvent("Events");
event.initEvent("select", true, true);
@ -5340,8 +5337,16 @@
this._selectedIndex = val;
switchPromise.then(() => {
this.setAttribute("selectedIndex", val);
gBrowser._finalizeTabSwitch(toTab, fromTab);
// If we cannot find the tabpanel that we were trying to switch to, then
// it must have been removed before our Promise could be resolved. In
// that case, we just cancel the tab switch.
var updatedTabIndex = Array.indexOf(this.childNodes, newPanel);
if (updatedTabIndex == -1) {
gBrowser._cancelTabSwitch(toTab);
} else {
this.setAttribute("selectedIndex", updatedTabIndex);
gBrowser._finalizeTabSwitch(toTab, fromTab);
}
}, () => {
// If the promise rejected, that means we don't want to actually
// flip the deck, so we cancel the tab switch.

View File

@ -198,17 +198,13 @@ skip-if = e10s # Bug 940195 - XULBrowserWindow.isBusy is false as a remote tab s
run-if = toolkit == "cocoa"
[browser_bug567306.js]
[browser_bug575561.js]
skip-if = e10s # Bug 921905 - pinTab/unpinTab fail in e10s
[browser_bug575830.js]
skip-if = e10s # Bug 691614 - no e10s zoom support yet
[browser_bug577121.js]
skip-if = e10s # Bug 921905 - pinTab/unpinTab fail in e10s
[browser_bug578534.js]
skip-if = e10s # Bug ?????? - test directly manipulates content
[browser_bug579872.js]
skip-if = e10s # Bug 921905 - pinTab/unpinTab fail in e10s
[browser_bug580638.js]
skip-if = e10s # Bug 921905 - pinTab/unpinTab fail in e10s
[browser_bug580956.js]
skip-if = e10s # Bug 516755 - SessionStore disabled for e10s
[browser_bug581242.js]
@ -217,19 +213,16 @@ skip-if = e10s # Bug 930863 - pageshow issues ("TypeError: charset is undefined"
skip-if = e10s # Bug 930863 - pageshow issues ("TypeError: charset is undefined" in pageshow listener, as document is null)
[browser_bug581947.js]
[browser_bug585558.js]
skip-if = e10s # Bug 921905 - pinTab/unpinTab fail in e10s
[browser_bug585785.js]
[browser_bug585830.js]
[browser_bug590206.js]
[browser_bug592338.js]
skip-if = e10s # Bug 653065 - Make the lightweight theme web installer ready for e10s
[browser_bug594131.js]
skip-if = e10s # Bug 921905 - pinTab/unpinTab fail in e10s
[browser_bug595507.js]
skip-if = e10s # Bug 691601 - no form submit observers
[browser_bug596687.js]
[browser_bug597218.js]
skip-if = e10s # Bug 921905 - pinTab/unpinTab fail in e10s
[browser_bug609700.js]
skip-if = e10s # Bug 516755 - SessionStore disabled for e10s (calls duplicateTabIn, which uses SessionStore)
[browser_bug623155.js]
@ -336,7 +329,6 @@ skip-if = buildapp == 'mulet' || e10s # Bug ?????? - uncaught exception - Error:
[browser_offlineQuotaNotification.js]
skip-if = buildapp == 'mulet' || e10s # Bug ?????? - test directly manipulates content (gBrowser.selectedBrowser.contentWindow.applicationCache.oncached = function() {...})
[browser_overflowScroll.js]
skip-if = e10s # Bug 921905 - pinTab/unpinTab fail in e10s
[browser_pageInfo.js]
skip-if = buildapp == 'mulet' || e10s # Bug 866413 - PageInfo doesn't work in e10s
[browser_page_style_menu.js]
@ -347,7 +339,6 @@ skip-if = e10s # Bug ?????? - test directly manipulates content
skip-if = debug || asan # Times out on debug/asan, and we are less picky about our JS there
[browser_pinnedTabs.js]
skip-if = e10s # Bug 921905 - pinTab/unpinTab fail in e10s
[browser_plainTextLinks.js]
skip-if = e10s # Bug ?????? - test directly manipulates content (creates and fetches elements directly from content document)
[browser_popupUI.js]
@ -360,7 +351,6 @@ skip-if = buildapp == 'mulet'
skip-if = buildapp == 'mulet'
[browser_relatedTabs.js]
[browser_removeTabsToTheEnd.js]
skip-if = e10s # Bug 921905 - pinTab/unpinTab fail in e10s
[browser_removeUnsafeProtocolsFromURLBarPaste.js]
[browser_sanitize-download-history.js]
skip-if = true # bug 432425
@ -438,13 +428,10 @@ skip-if = e10s # Bug ?????? - FHR tests failing (either with "no data for today"
skip-if = e10s # Bug ?????? - test directly manipulates content
[browser_visibleLabel.js]
[browser_visibleTabs.js]
skip-if = e10s # Bug 921905 - pinTab/unpinTab fail in e10s
[browser_visibleTabs_bookmarkAllPages.js]
skip-if = true # Bug 1005420 - fails intermittently. also with e10s enabled: bizarre problem with hidden tab having _mouseenter called, via _setPositionalAttributes, and tab not being found resulting in 'candidate is undefined'
[browser_visibleTabs_bookmarkAllTabs.js]
skip-if = e10s # Bug 921905 - pinTab/unpinTab fail in e10s
[browser_visibleTabs_contextMenu.js]
skip-if = e10s # Bug 921905 - pinTab/unpinTab fail in e10s
[browser_visibleTabs_tabPreview.js]
skip-if = (os == "win" && !debug) || e10s # Bug 1007418 / Bug 698371 - thumbnail captures need e10s love (tabPreviews_capture fails with Argument 1 of CanvasRenderingContext2D.drawWindow does not implement interface Window.)
[browser_web_channel.js]

View File

@ -43,16 +43,8 @@ function testLink(aLinkIndex, pinTab, expectNewTab, nextTest, testSubFrame) {
if (pinTab)
gBrowser.pinTab(appTab);
gBrowser.selectedTab = appTab;
appTab.linkedBrowser.addEventListener("load", onLoad, true);
let loadCount = 0;
function onLoad() {
loadCount++;
if (loadCount < 2)
return;
appTab.linkedBrowser.removeEventListener("load", onLoad, true);
waitForDocLoadComplete(appTab.linkedBrowser).then(function() {
let browser = gBrowser.getBrowserForTab(appTab);
if (testSubFrame)
browser = browser.contentDocument.getElementsByTagName("iframe")[0];
@ -62,7 +54,7 @@ function testLink(aLinkIndex, pinTab, expectNewTab, nextTest, testSubFrame) {
if (expectNewTab)
gBrowser.tabContainer.addEventListener("TabOpen", onTabOpen, true);
else
browser.addEventListener("load", onPageLoad, true);
waitForDocLoadComplete(appTab.linkedBrowser).then(onPageLoad);
info("Clicking " + links[aLinkIndex].textContent);
EventUtils.sendMouseEvent({type:"click"}, links[aLinkIndex], browser.contentWindow);
@ -80,11 +72,13 @@ function testLink(aLinkIndex, pinTab, expectNewTab, nextTest, testSubFrame) {
function onTabOpen(event) {
gBrowser.tabContainer.removeEventListener("TabOpen", onTabOpen, true);
ok(true, "Link should open a new tab");
executeSoon(function(){
gBrowser.removeTab(appTab);
gBrowser.removeCurrentTab();
nextTest();
waitForDocLoadComplete(event.target.linkedBrowser).then(function() {
executeSoon(function(){
gBrowser.removeTab(appTab);
gBrowser.removeCurrentTab();
nextTest();
});
});
}
}
});
}

View File

@ -49,14 +49,6 @@ const EXPECTED_REFLOWS = [
"ssi_updateWindowFeatures/<@resource:///modules/sessionstore/SessionStore.jsm|" +
"ssi_updateWindowFeatures@resource:///modules/sessionstore/SessionStore.jsm|" +
"ssi_collectWindowData@resource:///modules/sessionstore/SessionStore.jsm|",
// tabPreviews.capture()
"tabPreviews_capture@chrome://browser/content/browser.js|" +
"tabPreviews_handleEvent/<@chrome://browser/content/browser.js|",
// tabPreviews.capture()
"tabPreviews_capture@chrome://browser/content/browser.js|" +
"@chrome://browser/content/browser.js|"
];
const PREF_PRELOAD = "browser.newtab.preload";

View File

@ -15,8 +15,10 @@ function promiseNotificationForTab(aBrowser, value, expected, tab=aBrowser.selec
let deferred = Promise.defer();
let notificationBox = aBrowser.getNotificationBox(tab.linkedBrowser);
if (expected) {
info("Waiting for " + value + " notification");
let checkForNotification = function() {
if (notificationBox.getNotificationWithValue(value)) {
info("Saw the notification");
notificationObserver.disconnect();
notificationObserver = null;
deferred.resolve();
@ -48,12 +50,13 @@ function* runURLBarSearchTest(valueToOpen, expectSearch, expectNotification, aWi
expectedURI = Services.search.defaultEngine.getSubmission(valueToOpen, null, "keyword").uri.spec;
}
aWindow.gURLBar.focus();
let docLoadPromise = waitForDocLoadAndStopIt(expectedURI, aWindow.gBrowser);
let docLoadPromise = waitForDocLoadAndStopIt(expectedURI, aWindow.gBrowser.selectedBrowser);
EventUtils.synthesizeKey("VK_RETURN", {}, aWindow);
yield docLoadPromise;
yield promiseNotificationForTab(aWindow.gBrowser, "keyword-uri-fixup", expectNotification);
yield Promise.all([
docLoadPromise,
promiseNotificationForTab(aWindow.gBrowser, "keyword-uri-fixup", expectNotification)
]);
}
add_task(function* test_navigate_full_domain() {
@ -88,7 +91,7 @@ function get_test_function_for_localhost_with_hostname(hostName, isPrivate) {
let notificationBox = browser.getNotificationBox(tab.linkedBrowser);
let notification = notificationBox.getNotificationWithValue("keyword-uri-fixup");
let docLoadPromise = waitForDocLoadAndStopIt("http://" + hostName + "/", browser);
let docLoadPromise = waitForDocLoadAndStopIt("http://" + hostName + "/", tab.linkedBrowser);
notification.querySelector(".notification-button-default").click();
// check pref value

View File

@ -394,26 +394,66 @@ function promiseClearHistory() {
* The URL of the document that is expected to load.
* @return promise
*/
function waitForDocLoadAndStopIt(aExpectedURL, aBrowser=gBrowser) {
function waitForDocLoadAndStopIt(aExpectedURL, aBrowser=gBrowser.selectedBrowser) {
function content_script() {
let { interfaces: Ci, utils: Cu } = Components;
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
let wp = docShell.QueryInterface(Ci.nsIWebProgress);
let progressListener = {
onStateChange: function (webProgress, req, flags, status) {
dump("waitForDocLoadAndStopIt: onStateChange " + flags.toString(16) + ": " + req.name + "\n");
let docStart = Ci.nsIWebProgressListener.STATE_IS_DOCUMENT |
Ci.nsIWebProgressListener.STATE_START;
if (((flags & docStart) == docStart) && webProgress.isTopLevel) {
dump("waitForDocLoadAndStopIt: Document start: " +
req.QueryInterface(Ci.nsIChannel).URI.spec + "\n");
req.cancel(Components.results.NS_ERROR_FAILURE);
wp.removeProgressListener(progressListener);
sendAsyncMessage("Test:WaitForDocLoadAndStopIt", { uri: req.originalURI.spec });
}
},
QueryInterface: XPCOMUtils.generateQI(["nsISupportsWeakReference"])
};
wp.addProgressListener(progressListener, wp.NOTIFY_ALL);
}
return new Promise((resolve, reject) => {
function complete({ data }) {
is(data.uri, aExpectedURL, "waitForDocLoadAndStopIt: The expected URL was loaded");
mm.removeMessageListener("Test:WaitForDocLoadAndStopIt", complete);
resolve();
}
let mm = aBrowser.messageManager;
mm.loadFrameScript("data:,(" + content_script.toString() + ")();", true);
mm.addMessageListener("Test:WaitForDocLoadAndStopIt", complete);
info("waitForDocLoadAndStopIt: Waiting for URL: " + aExpectedURL);
});
}
/**
* Waits for the next load to complete in the current browser.
*
* @return promise
*/
function waitForDocLoadComplete(aBrowser=gBrowser) {
let deferred = Promise.defer();
let progressListener = {
onStateChange: function (webProgress, req, flags, status) {
info("waitForDocLoadAndStopIt: onStateChange: " + req.name);
let docStart = Ci.nsIWebProgressListener.STATE_IS_DOCUMENT |
Ci.nsIWebProgressListener.STATE_START;
if ((flags & docStart) && webProgress.isTopLevel) {
info("waitForDocLoadAndStopIt: Document start: " +
req.QueryInterface(Ci.nsIChannel).URI.spec);
is(req.originalURI.spec, aExpectedURL,
"waitForDocLoadAndStopIt: The expected URL was loaded");
req.cancel(Components.results.NS_ERROR_FAILURE);
let docStart = Ci.nsIWebProgressListener.STATE_IS_NETWORK |
Ci.nsIWebProgressListener.STATE_STOP;
if ((flags & docStart) == docStart) {
aBrowser.removeProgressListener(progressListener);
info("Browser loaded");
deferred.resolve();
}
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
Ci.nsISupportsWeakReference])
};
aBrowser.addProgressListener(progressListener);
info("waitForDocLoadAndStopIt: Waiting for URL: " + aExpectedURL);
info("Waiting for browser load");
return deferred.promise;
}

View File

@ -21,7 +21,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "console",
*/
let MozLoopPushHandler = {
// This is the uri of the push server.
pushServerUri: Services.prefs.getCharPref("services.push.serverURL"),
pushServerUri: undefined,
// This is the channel id we're using for notifications
channelID: "8b1081ce-9b35-42b5-b8f5-3ff8cb813a50",
// This is the UserAgent UUID assigned by the PushServer
@ -211,8 +211,51 @@ let MozLoopPushHandler = {
}
this._websocket.protocol = "push-notification";
let uri = Services.io.newURI(this.pushServerUri, null, null);
this._websocket.asyncOpen(uri, this.pushServerUri, this, null);
let performOpen = () => {
let uri = Services.io.newURI(this.pushServerUri, null, null);
this._websocket.asyncOpen(uri, this.pushServerUri, this, null);
}
let pushServerURLFetchError = () => {
console.warn("MozLoopPushHandler - Could not retrieve push server URL from Loop server; using default");
this.pushServerUri = Services.prefs.getCharPref("services.push.serverURL");
performOpen();
}
if (!this.pushServerUri) {
// Get push server to use from the Loop server
let pushUrlEndpoint = Services.prefs.getCharPref("loop.server") + "/push-server-config";
let req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].
createInstance(Ci.nsIXMLHttpRequest);
req.open("GET", pushUrlEndpoint);
req.onload = () => {
if (req.status >= 200 && req.status < 300) {
let pushServerConfig;
try {
pushServerConfig = JSON.parse(req.responseText);
} catch (e) {
console.warn("MozLoopPushHandler - Error parsing JSON response for push server URL");
pushServerURLFetchError();
}
if (pushServerConfig.pushServerURI) {
this.pushServerUri = pushServerConfig.pushServerURI;
performOpen();
} else {
console.warn("MozLoopPushHandler - push server URL config lacks pushServerURI parameter");
pushServerURLFetchError();
}
} else {
console.warn("MozLoopPushHandler - push server URL retrieve error: " + req.status);
pushServerURLFetchError();
}
};
req.onerror = pushServerURLFetchError;
req.send();
} else {
// this.pushServerUri already set -- just open the channel
performOpen();
}
},
/**

View File

@ -57,9 +57,17 @@ function loadLoopPanel() {
Services.prefs.setCharPref("services.push.serverURL", "ws://localhost/");
Services.prefs.setCharPref("loop.server", "http://localhost/");
// Turn off the network for loop tests, so that we don't
// try to access the remote servers. If we want to turn this
// back on in future, be careful to check for intermittent
// failures.
let wasOffline = Services.io.offline;
Services.io.offline = true;
registerCleanupFunction(function() {
Services.prefs.clearUserPref("services.push.serverURL");
Services.prefs.clearUserPref("loop.server");
Services.io.offline = wasOffline;
});
// Turn off animations to make tests quicker.

View File

@ -54,6 +54,8 @@
});
function run_test() {
setupFakeLoopServer();
Services.prefs.setCharPref("services.push.serverURL", kServerPushUrl);
Services.prefs.setIntPref("loop.retry_delay.start", 10); // 10 ms
Services.prefs.setIntPref("loop.retry_delay.limit", 20); // 20 ms

View File

@ -7,6 +7,8 @@ function expiryTimePref() {
function run_test()
{
setupFakeLoopServer();
Services.prefs.setIntPref("loop.urlsExpiryTimeSeconds", 0);
MozLoopService.noteCallUrlExpiry(1000);

View File

@ -50,6 +50,8 @@ add_task(function test_initialize_starts_timer() {
function run_test()
{
setupFakeLoopServer();
// Override MozLoopService's initializeTimer, so that we can verify the timeout is called
// correctly.
MozLoopService.initializeTimerFunc = function() {

View File

@ -22,6 +22,8 @@ function test_getStrings() {
function run_test()
{
setupFakeLoopServer();
test_locale();
test_getStrings();
}

View File

@ -89,6 +89,8 @@ function test_getLoopBoolPref_not_found()
function run_test()
{
setupFakeLoopServer();
test_getLoopCharPref();
test_getLoopCharPref_not_found();
test_getLoopCharPref_non_coercible_type();

View File

@ -76,6 +76,9 @@ const TEST_DATA = [
" var handler9 = function divKeyDown() {\n" +
" alert(9);\n" +
" };\n" +
" var handler10 = function divDragOut() {\n" +
" alert(10);\n" +
" };\n" +
"\n" +
" if ($(\"#livediv\").live) {\n" +
" $(\"#livediv\").live(\"dblclick\", handler1);\n" +
@ -90,6 +93,7 @@ const TEST_DATA = [
" if ($(\"#livediv\").on) {\n" +
" $(document).on(\"drop\", \"#livediv\", handler5);\n" +
" $(document).on(\"dragover\", \"#livediv\", handler6);\n" +
" $(document).on(\"dragout\", \"#livediv:xxxxx\", handler10);\n" +
" }\n" +
"\n" +
" var div = $(\"div\")[0];\n" +

View File

@ -80,6 +80,9 @@ const TEST_DATA = [
" var handler9 = function divKeyDown() {\n" +
" alert(9);\n" +
" };\n" +
" var handler10 = function divDragOut() {\n" +
" alert(10);\n" +
" };\n" +
"\n" +
" if ($(\"#livediv\").live) {\n" +
" $(\"#livediv\").live(\"dblclick\", handler1);\n" +
@ -94,6 +97,7 @@ const TEST_DATA = [
" if ($(\"#livediv\").on) {\n" +
" $(document).on(\"drop\", \"#livediv\", handler5);\n" +
" $(document).on(\"dragover\", \"#livediv\", handler6);\n" +
" $(document).on(\"dragout\", \"#livediv:xxxxx\", handler10);\n" +
" }\n" +
"\n" +
" var div = $(\"div\")[0];\n" +

View File

@ -51,6 +51,9 @@ const TEST_DATA = [
" var handler9 = function divKeyDown() {\n" +
" alert(9);\n" +
" };\n" +
" var handler10 = function divDragOut() {\n" +
" alert(10);\n" +
" };\n" +
"\n" +
" if ($(\"#livediv\").live) {\n" +
" $(\"#livediv\").live(\"dblclick\", handler1);\n" +
@ -65,6 +68,7 @@ const TEST_DATA = [
" if ($(\"#livediv\").on) {\n" +
" $(document).on(\"drop\", \"#livediv\", handler5);\n" +
" $(document).on(\"dragover\", \"#livediv\", handler6);\n" +
" $(document).on(\"dragout\", \"#livediv:xxxxx\", handler10);\n" +
" }\n" +
"\n" +
" var div = $(\"div\")[0];\n" +

View File

@ -51,6 +51,9 @@ const TEST_DATA = [
" var handler9 = function divKeyDown() {\n" +
" alert(9);\n" +
" };\n" +
" var handler10 = function divDragOut() {\n" +
" alert(10);\n" +
" };\n" +
"\n" +
" if ($(\"#livediv\").live) {\n" +
" $(\"#livediv\").live(\"dblclick\", handler1);\n" +
@ -65,6 +68,7 @@ const TEST_DATA = [
" if ($(\"#livediv\").on) {\n" +
" $(document).on(\"drop\", \"#livediv\", handler5);\n" +
" $(document).on(\"dragover\", \"#livediv\", handler6);\n" +
" $(document).on(\"dragout\", \"#livediv:xxxxx\", handler10);\n" +
" }\n" +
"\n" +
" var div = $(\"div\")[0];\n" +

View File

@ -81,6 +81,9 @@ const TEST_DATA = [
" var handler9 = function divKeyDown() {\n" +
" alert(9);\n" +
" };\n" +
" var handler10 = function divDragOut() {\n" +
" alert(10);\n" +
" };\n" +
"\n" +
" if ($(\"#livediv\").live) {\n" +
" $(\"#livediv\").live(\"dblclick\", handler1);\n" +
@ -95,6 +98,7 @@ const TEST_DATA = [
" if ($(\"#livediv\").on) {\n" +
" $(document).on(\"drop\", \"#livediv\", handler5);\n" +
" $(document).on(\"dragover\", \"#livediv\", handler6);\n" +
" $(document).on(\"dragout\", \"#livediv:xxxxx\", handler10);\n" +
" }\n" +
"\n" +
" var div = $(\"div\")[0];\n" +

View File

@ -51,6 +51,9 @@ const TEST_DATA = [
" var handler9 = function divKeyDown() {\n" +
" alert(9);\n" +
" };\n" +
" var handler10 = function divDragOut() {\n" +
" alert(10);\n" +
" };\n" +
"\n" +
" if ($(\"#livediv\").live) {\n" +
" $(\"#livediv\").live(\"dblclick\", handler1);\n" +
@ -65,6 +68,7 @@ const TEST_DATA = [
" if ($(\"#livediv\").on) {\n" +
" $(document).on(\"drop\", \"#livediv\", handler5);\n" +
" $(document).on(\"dragover\", \"#livediv\", handler6);\n" +
" $(document).on(\"dragout\", \"#livediv:xxxxx\", handler10);\n" +
" }\n" +
"\n" +
" var div = $(\"div\")[0];\n" +

View File

@ -51,6 +51,9 @@ const TEST_DATA = [
" var handler9 = function divKeyDown() {\n" +
" alert(9);\n" +
" };\n" +
" var handler10 = function divDragOut() {\n" +
" alert(10);\n" +
" };\n" +
"\n" +
" if ($(\"#livediv\").live) {\n" +
" $(\"#livediv\").live(\"dblclick\", handler1);\n" +
@ -65,6 +68,7 @@ const TEST_DATA = [
" if ($(\"#livediv\").on) {\n" +
" $(document).on(\"drop\", \"#livediv\", handler5);\n" +
" $(document).on(\"dragover\", \"#livediv\", handler6);\n" +
" $(document).on(\"dragout\", \"#livediv:xxxxx\", handler10);\n" +
" }\n" +
"\n" +
" var div = $(\"div\")[0];\n" +

View File

@ -51,6 +51,9 @@ const TEST_DATA = [
" var handler9 = function divKeyDown() {\n" +
" alert(9);\n" +
" };\n" +
" var handler10 = function divDragOut() {\n" +
" alert(10);\n" +
" };\n" +
"\n" +
" if ($(\"#livediv\").live) {\n" +
" $(\"#livediv\").live(\"dblclick\", handler1);\n" +
@ -65,6 +68,7 @@ const TEST_DATA = [
" if ($(\"#livediv\").on) {\n" +
" $(document).on(\"drop\", \"#livediv\", handler5);\n" +
" $(document).on(\"dragover\", \"#livediv\", handler6);\n" +
" $(document).on(\"dragout\", \"#livediv:xxxxx\", handler10);\n" +
" }\n" +
"\n" +
" var div = $(\"div\")[0];\n" +

View File

@ -51,6 +51,9 @@ const TEST_DATA = [
" var handler9 = function divKeyDown() {\n" +
" alert(9);\n" +
" };\n" +
" var handler10 = function divDragOut() {\n" +
" alert(10);\n" +
" };\n" +
"\n" +
" if ($(\"#livediv\").live) {\n" +
" $(\"#livediv\").live(\"dblclick\", handler1);\n" +
@ -65,6 +68,7 @@ const TEST_DATA = [
" if ($(\"#livediv\").on) {\n" +
" $(document).on(\"drop\", \"#livediv\", handler5);\n" +
" $(document).on(\"dragover\", \"#livediv\", handler6);\n" +
" $(document).on(\"dragout\", \"#livediv:xxxxx\", handler10);\n" +
" }\n" +
"\n" +
" var div = $(\"div\")[0];\n" +

View File

@ -34,6 +34,7 @@
var handler7 = function divClick1() { alert(7); };
var handler8 = function divClick2() { alert(8); };
var handler9 = function divKeyDown() { alert(9); };
var handler10 = function divDragOut() { alert(10); };
if ($("#livediv").live) {
$("#livediv").live( "dblclick", handler1);
@ -48,6 +49,7 @@
if ($("#livediv").on) {
$(document).on( "drop", "#livediv", handler5);
$(document).on( "dragover", "#livediv", handler6);
$(document).on( "dragout", "#livediv:xxxxx", handler10);
}
var div = $("div")[0];

View File

@ -324,38 +324,83 @@ CssHtmlTree.prototype = {
* returns null of the node isn't anything we care about
*/
getNodeInfo: function(node) {
let type, value;
if (!node) {
return null;
}
let classes = node.classList;
if (classes.contains("property-name") ||
classes.contains("property-value") ||
(classes.contains("theme-link") && !classes.contains("link"))) {
// Go up to the common parent to find the property and value
let parent = node.parentNode;
while (!parent.classList.contains("property-view")) {
parent = parent.parentNode;
// Check if the node isn't a selector first since this doesn't require
// walking the DOM
if (classes.contains("matched") ||
classes.contains("bestmatch") ||
classes.contains("parentmatch")) {
let selectorText = "";
for (let child of node.childNodes) {
if (child.nodeType === node.TEXT_NODE) {
selectorText += child.textContent;
}
}
return {
type: overlays.VIEW_NODE_SELECTOR_TYPE,
value: selectorText.trim()
}
}
// Walk up the nodes to find out where node is
let propertyView;
let propertyContent;
let parent = node;
while (parent.parentNode) {
if (parent.classList.contains("property-view")) {
propertyView = parent;
break;
}
if (parent.classList.contains("property-content")) {
propertyContent = parent;
break;
}
parent = parent.parentNode;
}
if (!propertyView && !propertyContent) {
return null;
}
let value, type;
// Get the property and value for a node that's a property name or value
let isHref = classes.contains("theme-link") && !classes.contains("link");
if (propertyView && (classes.contains("property-name") ||
classes.contains("property-value") ||
isHref)) {
value = {
property: parent.querySelector(".property-name").textContent,
value: parent.querySelector(".property-value").textContent
};
}
if (propertyContent && (classes.contains("other-property-value") ||
isHref)) {
let view = propertyContent.previousSibling;
value = {
property: view.querySelector(".property-name").textContent,
value: node.textContent
};
}
// Get the type
if (classes.contains("property-name")) {
type = overlays.VIEW_NODE_PROPERTY_TYPE;
} else if (classes.contains("property-value")) {
} else if (classes.contains("property-value") ||
classes.contains("other-property-value")) {
type = overlays.VIEW_NODE_VALUE_TYPE;
} else if (classes.contains("theme-link")) {
} else if (isHref) {
type = overlays.VIEW_NODE_IMAGE_URL_TYPE;
value.url = node.href;
} else {
return null;
}
return {
type: type,
value: value
};
return {type, value};
},
_createPropertyViews: function()

View File

@ -1248,6 +1248,10 @@ CssRuleView.prototype = {
* returns null of the node isn't anything we care about
*/
getNodeInfo: function(node) {
if (!node) {
return null;
}
let type, value;
let classes = node.classList;
let prop = getParentTextProperty(node);

View File

@ -25,6 +25,7 @@ support-files =
head.js
[browser_computedview_browser-styles.js]
[browser_computedview_getNodeInfo.js]
[browser_computedview_keybindings_01.js]
[browser_computedview_keybindings_02.js]
[browser_computedview_matched-selectors-toggle.js]

View File

@ -0,0 +1,177 @@
/* 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/ */
"use strict";
// Test various output of the computed-view's getNodeInfo method.
// This method is used by the style-inspector-overlay on mouseover to decide
// which tooltip or highlighter to show when hovering over a value/name/selector
// if any.
// For instance, browser_ruleview_selector-highlighter_01.js and
// browser_ruleview_selector-highlighter_02.js test that the selector
// highlighter appear when hovering over a selector in the rule-view.
// Since the code to make this work for the computed-view is 90% the same, there
// is no need for testing it again here.
// This test however serves as a unit test for getNodeInfo.
const {
VIEW_NODE_SELECTOR_TYPE,
VIEW_NODE_PROPERTY_TYPE,
VIEW_NODE_VALUE_TYPE,
VIEW_NODE_IMAGE_URL_TYPE
} = devtools.require("devtools/styleinspector/style-inspector-overlays");
const PAGE_CONTENT = [
'<style type="text/css">',
' body {',
' background: red;',
' color: white;',
' }',
' div {',
' background: green;',
' }',
' div div {',
' background-color: yellow;',
' background-image: url(chrome://global/skin/icons/warning-64.png);',
' color: red;',
' }',
'</style>',
'<div><div id="testElement">Test element</div></div>'
].join("\n");
// Each item in this array must have the following properties:
// - desc {String} will be logged for information
// - getHoveredNode {Generator Function} received the computed-view instance as
// argument and must return the node to be tested
// - assertNodeInfo {Function} should check the validity of the nodeInfo
// argument it receives
const TEST_DATA = [
{
desc: "Testing a null node",
getHoveredNode: function*() {
return null;
},
assertNodeInfo: function(nodeInfo) {
is(nodeInfo, null);
}
},
{
desc: "Testing a useless node",
getHoveredNode: function*(view) {
return view.element;
},
assertNodeInfo: function(nodeInfo) {
is(nodeInfo, null);
}
},
{
desc: "Testing a property name",
getHoveredNode: function*(view) {
return getComputedViewProperty(view, "color").nameSpan;
},
assertNodeInfo: function(nodeInfo) {
is(nodeInfo.type, VIEW_NODE_PROPERTY_TYPE);
ok("property" in nodeInfo.value);
ok("value" in nodeInfo.value);
is(nodeInfo.value.property, "color");
is(nodeInfo.value.value, "#F00");
}
},
{
desc: "Testing a property value",
getHoveredNode: function*(view) {
return getComputedViewProperty(view, "color").valueSpan;
},
assertNodeInfo: function(nodeInfo) {
is(nodeInfo.type, VIEW_NODE_VALUE_TYPE);
ok("property" in nodeInfo.value);
ok("value" in nodeInfo.value);
is(nodeInfo.value.property, "color");
is(nodeInfo.value.value, "#F00");
}
},
{
desc: "Testing an image url",
getHoveredNode: function*(view) {
let {valueSpan} = getComputedViewProperty(view, "background-image");
return valueSpan.querySelector(".theme-link");
},
assertNodeInfo: function(nodeInfo) {
is(nodeInfo.type, VIEW_NODE_IMAGE_URL_TYPE);
ok("property" in nodeInfo.value);
ok("value" in nodeInfo.value);
is(nodeInfo.value.property, "background-image");
is(nodeInfo.value.value, "url(\"chrome://global/skin/icons/warning-64.png\")");
is(nodeInfo.value.url, "chrome://global/skin/icons/warning-64.png");
}
},
{
desc: "Testing a matched rule selector (bestmatch)",
getHoveredNode: function*(view) {
let content = yield getComputedViewMatchedRules(view, "background-color");
return content.querySelector(".bestmatch");
},
assertNodeInfo: function(nodeInfo) {
is(nodeInfo.type, VIEW_NODE_SELECTOR_TYPE);
is(nodeInfo.value, "div div");
}
},
{
desc: "Testing a matched rule selector (matched)",
getHoveredNode: function*(view) {
let content = yield getComputedViewMatchedRules(view, "background-color");
return content.querySelector(".matched");
},
assertNodeInfo: function(nodeInfo) {
is(nodeInfo.type, VIEW_NODE_SELECTOR_TYPE);
is(nodeInfo.value, "div");
}
},
{
desc: "Testing a matched rule selector (parentmatch)",
getHoveredNode: function*(view) {
let content = yield getComputedViewMatchedRules(view, "color");
return content.querySelector(".parentmatch");
},
assertNodeInfo: function(nodeInfo) {
is(nodeInfo.type, VIEW_NODE_SELECTOR_TYPE);
is(nodeInfo.value, "body");
}
},
{
desc: "Testing a matched rule value",
getHoveredNode: function*(view) {
let content = yield getComputedViewMatchedRules(view, "color");
return content.querySelector(".other-property-value");
},
assertNodeInfo: function(nodeInfo) {
is(nodeInfo.type, VIEW_NODE_VALUE_TYPE);
is(nodeInfo.value.property, "color");
is(nodeInfo.value.value, "#F00");
}
},
{
desc: "Testing a matched rule stylesheet link",
getHoveredNode: function*(view) {
let content = yield getComputedViewMatchedRules(view, "color");
return content.querySelector(".rule-link .theme-link");
},
assertNodeInfo: function(nodeInfo) {
is(nodeInfo, null);
}
}
];
let test = asyncTest(function*() {
yield addTab("data:text/html;charset=utf-8," + PAGE_CONTENT);
let {inspector, view} = yield openComputedView();
yield selectNode("#testElement", inspector);
for (let {desc, getHoveredNode, assertNodeInfo} of TEST_DATA) {
info(desc);
let nodeInfo = view.getNodeInfo(yield getHoveredNode(view));
assertNodeInfo(nodeInfo);
}
});

View File

@ -23,7 +23,7 @@ let test = asyncTest(function*() {
yield selectNode("div", inspector);
info("Expanding the first property");
yield expandComputedViewPropertyByIndex(view, inspector, 0);
yield expandComputedViewPropertyByIndex(view, 0);
info("Verifying the link text");
yield verifyLinkText(view, SCSS_LOC);

View File

@ -61,7 +61,7 @@ let test = asyncTest(function*() {
function* testInlineStyle(view, inspector) {
info("Testing inline style");
yield expandComputedViewPropertyByIndex(view, inspector, 0);
yield expandComputedViewPropertyByIndex(view, 0);
let onWindow = waitForWindow();
info("Clicking on the first rule-link in the computed-view");

View File

@ -35,6 +35,8 @@ let test = asyncTest(function*() {
let {toolbox, inspector, view} = yield openComputedView();
yield testComputedView(view, inspector.selection.nodeFront);
yield testExpandedComputedViewProperty(view, inspector.selection.nodeFront);
});
function* testRuleView(ruleView, nodeFront) {
@ -77,3 +79,39 @@ function* testComputedView(computedView, nodeFront) {
let dataURL = yield getFontFamilyDataURL(valueSpan.textContent, nodeFront);
is(images[0].getAttribute("src"), dataURL, "Tooltip contains the correct data-uri image");
}
function* testExpandedComputedViewProperty(computedView, nodeFront) {
info("Testing font-family tooltips in expanded properties of the computed view");
info("Expanding the font-family property to reveal matched selectors");
let propertyView = getPropertyView(computedView, "font-family");
propertyView.matchedExpanded = true;
yield propertyView.refreshMatchedSelectors();
let valueSpan = propertyView.matchedSelectorsContainer
.querySelector(".bestmatch .other-property-value");
let tooltip = computedView.tooltips.previewTooltip;
let panel = tooltip.panel;
yield assertHoverTooltipOn(tooltip, valueSpan);
let images = panel.getElementsByTagName("image");
is(images.length, 1, "Tooltip contains an image");
ok(images[0].getAttribute("src").startsWith("data:"), "Tooltip contains a data-uri image as expected");
let dataURL = yield getFontFamilyDataURL(valueSpan.textContent, nodeFront);
is(images[0].getAttribute("src"), dataURL, "Tooltip contains the correct data-uri image");
}
function getPropertyView(computedView, name) {
let propertyView = null;
computedView.propertyViews.some(function(view) {
if (view.name == name) {
propertyView = view;
return true;
}
return false;
});
return propertyView;
}

View File

@ -28,11 +28,6 @@ let test = asyncTest(function*() {
yield selectNode("#testElement", inspector);
yield testRuleView(view, inspector.selection.nodeFront);
info("Opening the computed view");
let {toolbox, inspector, view} = yield openComputedView();
yield testComputedView(view, inspector.selection.nodeFront);
});
function* testRuleView(ruleView, nodeFront) {
@ -63,21 +58,3 @@ function* testRuleView(ruleView, nodeFront) {
let dataURL = yield getFontFamilyDataURL(valueSpan.textContent, nodeFront);
is(images[0].getAttribute("src"), dataURL, "Tooltip contains the correct data-uri image");
}
function* testComputedView(computedView, nodeFront) {
info("Testing font-family tooltips in the computed view");
let tooltip = computedView.tooltips.previewTooltip;
let panel = tooltip.panel;
let {valueSpan} = getComputedViewProperty(computedView, "font-family");
yield assertHoverTooltipOn(tooltip, valueSpan);
let images = panel.getElementsByTagName("image");
is(images.length, 1, "Tooltip contains an image");
ok(images[0].getAttribute("src").startsWith("data:"), "Tooltip contains a data-uri image as expected");
let dataURL = yield getFontFamilyDataURL(valueSpan.textContent, nodeFront);
is(images[0].getAttribute("src"), dataURL, "Tooltip contains the correct data-uri image");
}

View File

@ -752,32 +752,6 @@ let createNewRuleViewProperty = Task.async(function*(ruleEditor, inputValue) {
yield onFocus;
});
// TO BE UNCOMMENTED WHEN THE EYEDROPPER FINALLY LANDS
// /**
// * Given a color swatch in the ruleview, click on it to open the color picker
// * and then click on the eyedropper button to start the eyedropper tool
// * @param {CssRuleView} view The instance of the rule-view panel
// * @param {DOMNode} swatch The color swatch to be clicked on
// * @return A promise that resolves when the dropper is opened
// */
// let openRuleViewEyeDropper = Task.async(function*(view, swatch) {
// info("Opening the colorpicker tooltip on a colorswatch");
// let tooltip = view.colorPicker.tooltip;
// let onTooltipShown = tooltip.once("shown");
// swatch.click();
// yield onTooltipShown;
// info("Finding the eyedropper icon in the colorpicker document");
// let tooltipDoc = tooltip.content.contentDocument;
// let dropperButton = tooltipDoc.querySelector("#eyedropper-button");
// ok(dropperButton, "Found the eyedropper icon");
// info("Opening the eyedropper");
// let onOpen = tooltip.once("eyedropper-opened");
// dropperButton.click();
// return yield onOpen;
// });
/* *********************************************
* COMPUTED-VIEW
* *********************************************
@ -806,6 +780,40 @@ function getComputedViewProperty(view, name) {
return prop;
}
/**
* Get a reference to the property-content element for a given property name in
* the computed-view.
* A property-content element always follows (nextSibling) the property itself
* and is only shown when the twisty icon is expanded on the property.
* A property-content element contains matched rules, with selectors, properties,
* values and stylesheet links
* @param {CssHtmlTree} view The instance of the computed view panel
* @param {String} name The name of the property to retrieve
* @return {Promise} A promise that resolves to the property matched rules
* container
*/
let getComputedViewMatchedRules = Task.async(function*(view, name) {
let expander;
let propertyContent;
for (let property of view.styleDocument.querySelectorAll(".property-view")) {
let nameSpan = property.querySelector(".property-name");
if (nameSpan.textContent === name) {
expander = property.querySelector(".expandable");
propertyContent = property.nextSibling;
break;
}
}
if (!expander.hasAttribute("open")) {
// Need to expand the property
let onExpand = view.inspector.once("computed-view-property-expanded");
expander.click();
yield onExpand;
}
return propertyContent;
});
/**
* Get the text value of the property corresponding to a given name in the
* computed-view
@ -813,8 +821,8 @@ function getComputedViewProperty(view, name) {
* @param {String} name The name of the property to retrieve
* @return {String} The property value
*/
function getComputedViewPropertyValue(view, selectorText, propertyName) {
return getComputedViewProperty(view, selectorText, propertyName)
function getComputedViewPropertyValue(view, name, propertyName) {
return getComputedViewProperty(view, name, propertyName)
.valueSpan.textContent;
}
@ -822,19 +830,18 @@ function getComputedViewPropertyValue(view, selectorText, propertyName) {
* Expand a given property, given its index in the current property list of
* the computed view
* @param {CssHtmlTree} view The instance of the computed view panel
* @param {InspectorPanel} inspector The instance of the inspector panel
* @param {Number} index The index of the property to be expanded
* @return a promise that resolves when the property has been expanded, or
* rejects if the property was not found
*/
function expandComputedViewPropertyByIndex(view, inspector, index) {
function expandComputedViewPropertyByIndex(view, index) {
info("Expanding property " + index + " in the computed view");
let expandos = view.styleDocument.querySelectorAll(".expandable");
if (!expandos.length || !expandos[index]) {
return promise.reject();
}
let onExpand = inspector.once("computed-view-property-expanded");
let onExpand = view.inspector.once("computed-view-property-expanded");
expandos[index].click();
return onExpand;
}

View File

@ -147,13 +147,18 @@ const HISTORY_FORWARD = 1;
const GROUP_INDENT = 12;
// The number of messages to display in a single display update. If we display
// too many messages at once we slow the Firefox UI too much.
// too many messages at once we slow down the Firefox UI too much.
const MESSAGES_IN_INTERVAL = DEFAULT_LOG_LIMIT;
// The delay between display updates - tells how often we should *try* to push
// new messages to screen. This value is optimistic, updates won't always
// happen. Keep this low so the Web Console output feels live.
const OUTPUT_INTERVAL = 50; // milliseconds
const OUTPUT_INTERVAL = 20; // milliseconds
// The maximum amount of time that can be spent doing cleanup inside of the
// flush output callback. If things don't get cleaned up in this time,
// then it will start again the next time it is called.
const MAX_CLEANUP_TIME = 10; // milliseconds
// When the output queue has more than MESSAGES_IN_INTERVAL items we throttle
// output updates to this number of milliseconds. So during a lot of output we
@ -190,6 +195,7 @@ function WebConsoleFrame(aWebConsoleOwner)
this._repeatNodes = {};
this._outputQueue = [];
this._itemDestroyQueue = [];
this._pruneCategoriesQueue = {};
this._networkRequests = {};
this.filterPrefs = {};
@ -2048,9 +2054,7 @@ WebConsoleFrame.prototype = {
this._outputQueue.push([aCategory, aMethodOrNode, aArguments]);
if (!this._outputTimerInitialized) {
this._initOutputTimer();
}
this._initOutputTimer();
},
/**
@ -2062,21 +2066,31 @@ WebConsoleFrame.prototype = {
*/
_flushMessageQueue: function WCF__flushMessageQueue()
{
this._outputTimerInitialized = false;
if (!this._outputTimer) {
return;
}
let timeSinceFlush = Date.now() - this._lastOutputFlush;
if (this._outputQueue.length > MESSAGES_IN_INTERVAL &&
timeSinceFlush < THROTTLE_UPDATES) {
this._initOutputTimer();
return;
}
let startTime = Date.now();
let timeSinceFlush = startTime - this._lastOutputFlush;
let shouldThrottle = this._outputQueue.length > MESSAGES_IN_INTERVAL &&
timeSinceFlush < THROTTLE_UPDATES;
// Determine how many messages we can display now.
let toDisplay = Math.min(this._outputQueue.length, MESSAGES_IN_INTERVAL);
if (toDisplay < 1) {
this._outputTimerInitialized = false;
// If there aren't any messages to display (because of throttling or an
// empty queue), then take care of some cleanup. Destroy items that were
// pruned from the outputQueue before being displayed.
if (shouldThrottle || toDisplay < 1) {
while (this._itemDestroyQueue.length) {
if ((Date.now() - startTime) > MAX_CLEANUP_TIME) {
break;
}
this._destroyItem(this._itemDestroyQueue.pop());
}
this._initOutputTimer();
return;
}
@ -2088,21 +2102,22 @@ WebConsoleFrame.prototype = {
}
let batch = this._outputQueue.splice(0, toDisplay);
if (!batch.length) {
this._outputTimerInitialized = false;
return;
}
let outputNode = this.outputNode;
let lastVisibleNode = null;
let scrollNode = outputNode.parentNode;
let scrolledToBottom = Utils.isOutputScrolledToBottom(outputNode);
let hudIdSupportsString = WebConsoleUtils.supportsString(this.hudId);
// We won't bother to try to restore scroll position if this is showing
// a lot of messages at once (and there are still items in the queue).
// It is going to purge whatever you were looking at anyway.
let scrolledToBottom = shouldPrune ||
Utils.isOutputScrolledToBottom(outputNode);
// Output the current batch of messages.
let newMessages = new Set();
let updatedMessages = new Set();
for (let item of batch) {
for (let i = 0; i < batch.length; i++) {
let item = batch[i];
let result = this._outputMessageFromQueue(hudIdSupportsString, item);
if (result) {
if (result.isRepeated) {
@ -2118,12 +2133,15 @@ WebConsoleFrame.prototype = {
}
let oldScrollHeight = 0;
// Prune messages if needed. We do not do this for every flush call to
// improve performance.
let removedNodes = 0;
// Prune messages from the DOM, but only if needed.
if (shouldPrune || !this._outputQueue.length) {
oldScrollHeight = scrollNode.scrollHeight;
// Only bother measuring the scrollHeight if not scrolled to bottom,
// since the oldScrollHeight will not be used if it is.
if (!scrolledToBottom) {
oldScrollHeight = scrollNode.scrollHeight;
}
let categories = Object.keys(this._pruneCategoriesQueue);
categories.forEach(function _pruneOutput(aCategory) {
@ -2156,17 +2174,15 @@ WebConsoleFrame.prototype = {
this.emit("messages-updated", updatedMessages);
}
// If the queue is not empty, schedule another flush.
if (this._outputQueue.length > 0) {
this._initOutputTimer();
}
else {
this._outputTimerInitialized = false;
if (this._flushCallback && this._flushCallback() === false) {
// If the output queue is empty, then run _flushCallback.
if (this._outputQueue.length === 0 && this._flushCallback) {
if (this._flushCallback() === false) {
this._flushCallback = null;
}
}
this._initOutputTimer();
this._lastOutputFlush = Date.now();
},
@ -2176,7 +2192,13 @@ WebConsoleFrame.prototype = {
*/
_initOutputTimer: function WCF__initOutputTimer()
{
if (!this._outputTimer) {
let panelIsDestroyed = !this._outputTimer;
let alreadyScheduled = this._outputTimerInitialized;
let nothingToDo = !this._itemDestroyQueue.length &&
!this._outputQueue.length;
// Don't schedule a callback in the following cases:
if (panelIsDestroyed || alreadyScheduled || nothingToDo) {
return;
}
@ -2274,7 +2296,7 @@ WebConsoleFrame.prototype = {
let n = Math.max(0, indexes.length - limit);
pruned += n;
for (let i = n - 1; i >= 0; i--) {
this._pruneItemFromQueue(this._outputQueue[indexes[i]]);
this._itemDestroyQueue.push(this._outputQueue[indexes[i]]);
this._outputQueue.splice(indexes[i], 1);
}
}
@ -2284,17 +2306,18 @@ WebConsoleFrame.prototype = {
},
/**
* Prune an item from the output queue.
* Destroy an item that was once in the outputQueue but isn't needed
* after all.
*
* @private
* @param array aItem
* The item you want to remove from the output queue.
* The item you want to destroy. Does not remove it from the output
* queue.
*/
_pruneItemFromQueue: function WCF__pruneItemFromQueue(aItem)
_destroyItem: function WCF__destroyItem(aItem)
{
// TODO: handle object releasing in a more elegant way once all console
// messages use the new API - bug 778766.
let [category, methodOrNode, args] = aItem;
if (typeof methodOrNode != "function" && methodOrNode._objectActors) {
for (let actor of methodOrNode._objectActors) {
@ -2370,9 +2393,7 @@ WebConsoleFrame.prototype = {
let messageNodes = this.outputNode.querySelectorAll(".message[category=" +
CATEGORY_CLASS_FRAGMENTS[aCategory] + "]");
let n = Math.max(0, messageNodes.length - logLimit);
let toRemove = Array.prototype.slice.call(messageNodes, 0, n);
toRemove.forEach(this.removeOutputMessage, this);
[...messageNodes].slice(0, n).forEach(this.removeOutputMessage, this);
return n;
},
@ -2415,9 +2436,7 @@ WebConsoleFrame.prototype = {
aNode._variablesView = null;
}
if (aNode.parentNode) {
aNode.parentNode.removeChild(aNode);
}
aNode.remove();
},
/**
@ -2897,7 +2916,10 @@ WebConsoleFrame.prototype = {
gDevTools.off("pref-changed", this._onToolboxPrefChanged);
this._repeatNodes = {};
this._outputQueue.forEach(this._destroyItem, this);
this._outputQueue = [];
this._itemDestroyQueue.forEach(this._destroyItem, this);
this._itemDestroyQueue = [];
this._pruneCategoriesQueue = {};
this._networkRequests = {};
@ -2906,7 +2928,6 @@ WebConsoleFrame.prototype = {
this._outputTimer.cancel();
}
this._outputTimer = null;
if (this.jsterm) {
this.jsterm.destroy();
this.jsterm = null;
@ -3787,7 +3808,7 @@ JSTerm.prototype = {
}
hud.groupDepth = 0;
hud._outputQueue.forEach(hud._pruneItemFromQueue, hud);
hud._outputQueue.forEach(hud._destroyItem, hud);
hud._outputQueue = [];
hud._networkRequests = {};
hud._repeatNodes = {};

View File

@ -89,6 +89,7 @@ SimulatorRuntime.prototype = {
return promise.reject("Can't find simulator: " + this.getName());
}
return simulator.launch({port: port}).then(() => {
connection.host = "localhost";
connection.port = port;
connection.keepConnecting = true;
connection.once(Connection.Events.DISCONNECTED, simulator.close);
@ -109,8 +110,8 @@ let gLocalRuntime = {
DebuggerServer.init();
DebuggerServer.addBrowserActors();
}
connection.port = null;
connection.host = null; // Force Pipe transport
connection.port = null;
connection.connect();
return promise.resolve();
},

Binary file not shown.

Before

Width:  |  Height:  |  Size: 883 B

After

Width:  |  Height:  |  Size: 874 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 811 B

After

Width:  |  Height:  |  Size: 742 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@ -1051,6 +1051,9 @@ nsFrameLoader::SwapWithOtherLoader(nsFrameLoader* aOther,
nsCOMPtr<EventTarget> otherChromeEventHandler =
do_QueryInterface(otherWindow->GetChromeEventHandler());
nsCOMPtr<EventTarget> ourEventTarget = ourWindow->GetParentTarget();
nsCOMPtr<EventTarget> otherEventTarget = otherWindow->GetParentTarget();
NS_ASSERTION(SameCOMIdentity(ourFrameElement, ourContent) &&
SameCOMIdentity(otherFrameElement, otherContent) &&
SameCOMIdentity(ourChromeEventHandler, ourContent) &&
@ -1100,25 +1103,25 @@ nsFrameLoader::SwapWithOtherLoader(nsFrameLoader* aOther,
// Fire pageshow events on still-loading pages, and then fire pagehide
// events. Note that we do NOT fire these in the normal way, but just fire
// them on the chrome event handlers.
FirePageShowEvent(ourDocshell, ourChromeEventHandler, false);
FirePageShowEvent(otherDocshell, otherChromeEventHandler, false);
FirePageHideEvent(ourDocshell, ourChromeEventHandler);
FirePageHideEvent(otherDocshell, otherChromeEventHandler);
FirePageShowEvent(ourDocshell, ourEventTarget, false);
FirePageShowEvent(otherDocshell, otherEventTarget, false);
FirePageHideEvent(ourDocshell, ourEventTarget);
FirePageHideEvent(otherDocshell, otherEventTarget);
nsIFrame* ourFrame = ourContent->GetPrimaryFrame();
nsIFrame* otherFrame = otherContent->GetPrimaryFrame();
if (!ourFrame || !otherFrame) {
mInSwap = aOther->mInSwap = false;
FirePageShowEvent(ourDocshell, ourChromeEventHandler, true);
FirePageShowEvent(otherDocshell, otherChromeEventHandler, true);
FirePageShowEvent(ourDocshell, ourEventTarget, true);
FirePageShowEvent(otherDocshell, otherEventTarget, true);
return NS_ERROR_NOT_IMPLEMENTED;
}
nsSubDocumentFrame* ourFrameFrame = do_QueryFrame(ourFrame);
if (!ourFrameFrame) {
mInSwap = aOther->mInSwap = false;
FirePageShowEvent(ourDocshell, ourChromeEventHandler, true);
FirePageShowEvent(otherDocshell, otherChromeEventHandler, true);
FirePageShowEvent(ourDocshell, ourEventTarget, true);
FirePageShowEvent(otherDocshell, otherEventTarget, true);
return NS_ERROR_NOT_IMPLEMENTED;
}
@ -1126,8 +1129,8 @@ nsFrameLoader::SwapWithOtherLoader(nsFrameLoader* aOther,
rv = ourFrameFrame->BeginSwapDocShells(otherFrame);
if (NS_FAILED(rv)) {
mInSwap = aOther->mInSwap = false;
FirePageShowEvent(ourDocshell, ourChromeEventHandler, true);
FirePageShowEvent(otherDocshell, otherChromeEventHandler, true);
FirePageShowEvent(ourDocshell, ourEventTarget, true);
FirePageShowEvent(otherDocshell, otherEventTarget, true);
return rv;
}
@ -1230,8 +1233,8 @@ nsFrameLoader::SwapWithOtherLoader(nsFrameLoader* aOther,
ourParentDocument->FlushPendingNotifications(Flush_Layout);
otherParentDocument->FlushPendingNotifications(Flush_Layout);
FirePageShowEvent(ourDocshell, otherChromeEventHandler, true);
FirePageShowEvent(otherDocshell, ourChromeEventHandler, true);
FirePageShowEvent(ourDocshell, ourEventTarget, true);
FirePageShowEvent(otherDocshell, otherEventTarget, true);
mInSwap = aOther->mInSwap = false;
return NS_OK;

View File

@ -7,3 +7,5 @@ skip-if = e10s # Bug ?????? - test e10s utils don't support load events from ifr
[browser_state_notifications.js]
# skip-if = e10s # Bug ?????? - content-document-* notifications come while document's URI is still about:blank, but test expects real URL.
skip-if = true # Intermittent failures - bug 987493. Restore the skip-if above once fixed
[browser_bug1058164.js]
skip-if = e10s # We need bug 918634 to land before this can be tested with e10s.

View File

@ -0,0 +1,106 @@
/* 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/. */
"use strict";
const kTimeout = 5000; // ms
/**
* Frame script injected in the test browser that sends
* messages when it sees the pagehide and pageshow events
* with the persisted property set to true.
*/
function frame_script() {
addEventListener("pageshow", (event) => {
if (event.persisted) {
sendAsyncMessage("test:pageshow");
}
});
addEventListener("pagehide", (event) => {
if (event.persisted) {
sendAsyncMessage("test:pagehide");
}
});
}
/**
* Return a Promise that resolves when the browser's frame
* script sees an event of type eventType. eventType can be
* either "pagehide" or "pageshow". Times out after kTimeout
* milliseconds if the event is never seen.
*/
function prepareForPageEvent(browser, eventType) {
return new Promise((resolve, reject) => {
let mm = browser.messageManager;
let timeoutId = setTimeout(() => {
ok(false, "Timed out waiting for " + eventType)
reject();
}, kTimeout);
mm.addMessageListener("test:" + eventType, function onSawEvent(message) {
mm.removeMessageListener("test:" + eventType, onSawEvent);
ok(true, "Saw " + eventType + " event in frame script.");
clearTimeout(timeoutId);
resolve();
});
});
}
/**
* Returns a Promise that resolves when both the pagehide
* and pageshow events have been seen from the frame script.
*/
function prepareForPageHideAndShow(browser) {
return Promise.all([prepareForPageEvent(browser, "pagehide"),
prepareForPageEvent(browser, "pageshow")]);
}
/**
* Returns a Promise that resolves when the load event for
* aWindow fires during the capture phase.
*/
function waitForLoad(aWindow) {
return new Promise((resolve, reject) => {
aWindow.addEventListener("load", function onLoad(aEvent) {
aWindow.removeEventListener("load", onLoad, true);
resolve();
}, true);
});
}
/**
* Tests that frame scripts get pageshow / pagehide events when
* swapping browser frameloaders (which occurs when moving a tab
* into a different window).
*/
add_task(function* test_swap_frameloader_pagevisibility_events() {
// Inject our frame script into a new browser.
let tab = gBrowser.addTab();
gBrowser.selectedTab = tab;
let mm = window.getGroupMessageManager("browsers");
mm.loadFrameScript("data:,(" + frame_script.toString() + ")();", true);
let browser = gBrowser.selectedBrowser;
// Swap the browser out to a new window
let newWindow = gBrowser.replaceTabWithWindow(tab);
// We have to wait for the window to load so we can get the selected browser
// to listen to.
yield waitForLoad(newWindow);
let pageHideAndShowPromise = prepareForPageHideAndShow(newWindow.gBrowser.selectedBrowser);
// Yield waiting for the pagehide and pageshow events.
yield pageHideAndShowPromise;
// Send the browser back to its original window
let newTab = gBrowser.addTab();
gBrowser.selectedTab = newTab;
browser = newWindow.gBrowser.selectedBrowser;
pageHideAndShowPromise = prepareForPageHideAndShow(gBrowser.selectedBrowser);
gBrowser.swapBrowsersAndCloseOther(newTab, newWindow.gBrowser.selectedTab);
// Yield waiting for the pagehide and pageshow events.
yield pageHideAndShowPromise;
gBrowser.removeTab(gBrowser.selectedTab);
});

View File

@ -5,12 +5,15 @@
#include "domstubs.idl"
interface nsIContentFrameMessageManager;
interface nsIWebBrowserChrome3;
[scriptable, uuid(2eb3bc54-78bf-40f2-b301-a5b5b70f7da0)]
interface nsITabChild : nsISupports
{
readonly attribute nsIContentFrameMessageManager messageManager;
attribute nsIWebBrowserChrome3 webBrowserChrome;
[notxpcom] void sendRequestFocus(in boolean canFocus);
};

View File

@ -80,6 +80,7 @@
#include "UnitTransforms.h"
#include "ClientLayerManager.h"
#include "LayersLogging.h"
#include "nsIWebBrowserChrome3.h"
#include "nsColorPickerProxy.h"
@ -205,12 +206,14 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(TabChildBase)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mTabChildGlobal)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlobal)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mAnonymousGlobalScopes)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mWebBrowserChrome)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(TabChildBase)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTabChildGlobal)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobal)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWebBrowserChrome)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(TabChildBase)
@ -1314,6 +1317,11 @@ TabChild::FocusPrevElement()
NS_IMETHODIMP
TabChild::GetInterface(const nsIID & aIID, void **aSink)
{
if (aIID.Equals(NS_GET_IID(nsIWebBrowserChrome3))) {
NS_IF_ADDREF(((nsISupports *) (*aSink = mWebBrowserChrome)));
return NS_OK;
}
// XXXbz should we restrict the set of interfaces we hand out here?
// See bug 537429
return QueryInterface(aIID, aSink);
@ -2840,6 +2848,20 @@ TabChild::GetMessageManager(nsIContentFrameMessageManager** aResult)
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
TabChild::GetWebBrowserChrome(nsIWebBrowserChrome3** aWebBrowserChrome)
{
NS_IF_ADDREF(*aWebBrowserChrome = mWebBrowserChrome);
return NS_OK;
}
NS_IMETHODIMP
TabChild::SetWebBrowserChrome(nsIWebBrowserChrome3* aWebBrowserChrome)
{
mWebBrowserChrome = aWebBrowserChrome;
return NS_OK;
}
void
TabChild::SendRequestFocus(bool aCanFocus)
{

View File

@ -33,6 +33,7 @@
#include "mozilla/EventDispatcher.h"
#include "mozilla/EventForwards.h"
#include "mozilla/layers/CompositorTypes.h"
#include "nsIWebBrowserChrome3.h"
class nsICachedFileDescriptorListener;
class nsIDOMWindowUtils;
@ -224,6 +225,7 @@ protected:
ScreenIntSize mInnerSize;
mozilla::layers::FrameMetrics mLastRootMetrics;
mozilla::layout::ScrollingBehavior mScrolling;
nsCOMPtr<nsIWebBrowserChrome3> mWebBrowserChrome;
};
class TabChild MOZ_FINAL : public TabChildBase,

View File

@ -9,7 +9,7 @@ random != boxshadow-blur-2.html boxshadow-blur-2-notref.html # fixedpoint divisi
== tableboxshadow-trshadow.html tableboxshadow-trshadow-ref.html
== tableboxshadow-tdshadow.html tableboxshadow-tdshadow-ref.html
== boxshadow-rounding.html boxshadow-rounding-ref.html
fails-if(Android||B2G) == boxshadow-button.html boxshadow-button-ref.html
fails-if(B2G) == boxshadow-button.html boxshadow-button-ref.html
fails-if(Android||B2G) == boxshadow-fileupload.html boxshadow-fileupload-ref.html
== boxshadow-inner-basic.html boxshadow-inner-basic-ref.svg
random-if(layersGPUAccelerated) == boxshadow-mixed.html boxshadow-mixed-ref.html
@ -25,7 +25,7 @@ random-if(d2d) == boxshadow-threecorners.html boxshadow-threecorners-ref.html
== overflow-not-scrollable-1.html overflow-not-scrollable-1-ref.html
== overflow-not-scrollable-1.html overflow-not-scrollable-1-ref2.html
== overflow-not-scrollable-2.html overflow-not-scrollable-2-ref.html
fails-if(Android||B2G) == 611574-1.html 611574-1-ref.html
fails-if(Android||B2G) == 611574-2.html 611574-2-ref.html
fails-if(B2G) == 611574-1.html 611574-1-ref.html
fails-if(B2G) == 611574-2.html 611574-2-ref.html
fuzzy-if(winWidget,5,30) == fieldset.html fieldset-ref.html # minor anti-aliasing problem on Windows
fuzzy-if(winWidget,5,30) == fieldset-inset.html fieldset-inset-ref.html # minor anti-aliasing problem on Windows

View File

@ -1305,9 +1305,9 @@ skip-if(B2G) == 478811-1.html 478811-1-ref.html
== 480880-2a.html about:blank
== 480880-2b.html about:blank
== 480880-2c.html about:blank
skip-if(B2G) fails-if(Android) == 481024-1a.html 481024-1-ref.html
skip-if(B2G) fails-if(Android) == 481024-1b.html 481024-1-ref.html
skip-if(B2G) fails-if(Android) == 481024-1c.html 481024-1-ref.html
skip-if(B2G) == 481024-1a.html 481024-1-ref.html
skip-if(B2G) == 481024-1b.html 481024-1-ref.html
skip-if(B2G) == 481024-1c.html 481024-1-ref.html
== 481024-1d.html 481024-1-ref.html
== 481024-1e.html 481024-1-ref.html
!= 481948-1.html 481948-1-ref.html
@ -1501,7 +1501,7 @@ skip-if(B2G) fails-if(Android) == 557087-2.html 557087-ref.html
== 557736-1.html 557736-1-ref.html
skip-if(B2G&&browserIsRemote) != 558011-1.xul 558011-1-ref.xul # bug 974780
== 559284-1.html 559284-1-ref.html
skip-if(B2G) fails-if(Android) == 560455-1.xul 560455-1-ref.xul
skip-if(B2G) == 560455-1.xul 560455-1-ref.xul
== 561981-1.html 561981-1-ref.html
== 561981-2.html 561981-2-ref.html
== 561981-3.html 561981-3-ref.html

View File

@ -1,7 +1,7 @@
== input-valid.html input-ref.html
fuzzy(11,4) == input-customerror.html input-ref.html
skip-if(B2G) fails-if(Android) == input-disabled.html input-ref.html
skip-if(B2G) fails-if(Android) == input-dyn-disabled.html input-ref.html
skip-if(B2G) == input-disabled.html input-ref.html
skip-if(B2G) == input-dyn-disabled.html input-ref.html
== input-dyn-not-disabled.html input-ref.html
== input-readonly.html input-ref.html
== input-dyn-readonly.html input-ref.html

View File

@ -1,7 +1,7 @@
== textarea-valid.html textarea-ref.html
== textarea-customerror.html textarea-ref.html
fails-if(Android||B2G) == textarea-disabled.html textarea-ref.html
fails-if(Android||B2G) == textarea-dyn-disabled.html textarea-ref.html
fails-if(B2G) == textarea-disabled.html textarea-ref.html
fails-if(B2G) == textarea-dyn-disabled.html textarea-ref.html
== textarea-dyn-not-disabled.html textarea-ref.html
== textarea-readonly.html textarea-ref.html
== textarea-dyn-readonly.html textarea-ref.html

View File

@ -1,7 +1,7 @@
== input-valid.html input-ref.html
fuzzy(64,4) == input-customerror.html input-ref.html
skip-if(B2G) fails-if(Android) == input-disabled.html input-ref.html
skip-if(B2G) fails-if(Android) == input-dyn-disabled.html input-ref.html
skip-if(B2G) == input-disabled.html input-ref.html
skip-if(B2G) == input-dyn-disabled.html input-ref.html
== input-dyn-not-disabled.html input-ref.html
== input-readonly.html input-ref.html
== input-dyn-readonly.html input-ref.html

View File

@ -1,7 +1,7 @@
== textarea-valid.html textarea-ref.html
== textarea-customerror.html textarea-ref.html
skip-if(B2G) fails-if(Android) == textarea-disabled.html textarea-ref.html
fails-if(Android||B2G) == textarea-dyn-disabled.html textarea-ref.html
skip-if(B2G) == textarea-disabled.html textarea-ref.html
fails-if(B2G) == textarea-dyn-disabled.html textarea-ref.html
== textarea-dyn-not-disabled.html textarea-ref.html
== textarea-readonly.html textarea-ref.html
== textarea-dyn-readonly.html textarea-ref.html

View File

@ -1,7 +1,7 @@
== input-valid.html input-ref.html
fuzzy(11,4) == input-customerror.html input-ref.html
fails-if(Android||B2G) == input-disabled.html input-ref.html
fails-if(Android||B2G) == input-dyn-disabled.html input-ref.html
fails-if(B2G) == input-disabled.html input-ref.html
fails-if(B2G) == input-dyn-disabled.html input-ref.html
== input-dyn-not-disabled.html input-ref.html
== input-dyn-not-disabled-changed.html input-ref.html
== input-readonly.html input-ref.html

View File

@ -1,7 +1,7 @@
== textarea-valid.html textarea-ref.html
== textarea-customerror.html textarea-ref.html
fails-if(Android||B2G) == textarea-disabled.html textarea-ref.html
random-if(Android||B2G) == textarea-dyn-disabled.html textarea-ref.html
fails-if(B2G) == textarea-disabled.html textarea-ref.html
random-if(B2G) == textarea-dyn-disabled.html textarea-ref.html
== textarea-dyn-not-disabled.html textarea-ref.html
== textarea-dyn-not-disabled-changed.html textarea-ref.html
== textarea-readonly.html textarea-ref.html

View File

@ -1,7 +1,7 @@
== input-valid.html input-ref.html
fuzzy(64,4) == input-customerror.html input-ref.html
fails-if(Android||B2G) == input-disabled.html input-ref.html
fails-if(Android||B2G) == input-dyn-disabled.html input-ref.html
fails-if(B2G) == input-disabled.html input-ref.html
fails-if(B2G) == input-dyn-disabled.html input-ref.html
== input-dyn-not-disabled.html input-ref.html
== input-readonly.html input-ref.html
== input-dyn-readonly.html input-ref.html

View File

@ -1,7 +1,7 @@
== textarea-valid.html textarea-ref.html
== textarea-customerror.html textarea-ref.html
fails-if(Android||B2G) == textarea-disabled.html textarea-ref.html
fails-if(Android||B2G) == textarea-dyn-disabled.html textarea-ref.html
fails-if(B2G) == textarea-disabled.html textarea-ref.html
fails-if(B2G) == textarea-dyn-disabled.html textarea-ref.html
== textarea-dyn-not-disabled.html textarea-ref.html
== textarea-readonly.html textarea-ref.html
== textarea-dyn-readonly.html textarea-ref.html

View File

@ -3,6 +3,6 @@ fails-if(B2G||Android) fuzzy-if(OSX==10.6,8,128) skip-if(B2G&&browserIsRemote) =
fails-if(B2G||Android) fuzzy-if(OSX==10.6,8,64) skip-if(B2G&&browserIsRemote) == rtl.html rtl-ref.xul # bug 974780
fails-if(B2G||Android) fuzzy-if(OSX==10.6,8,128) skip-if(B2G&&browserIsRemote) == size.html simple-ref.xul # bug 974780
fails-if(B2G||Android) fuzzy-if(OSX==10.6,8,64) skip-if(B2G&&browserIsRemote) == background.html background-ref.xul # bug 974780
fails-if(B2G||Android) skip-if(B2G&&browserIsRemote) == style.html style-ref.xul # bug 974780
fails-if(B2G) skip-if(B2G&&browserIsRemote) == style.html style-ref.xul # bug 974780
!= width-clip.html width-clip-ref.html
fails-if(B2G||Android) == color-inherit.html color-inherit-ref.html

View File

@ -1,6 +1,6 @@
== bounds-1.html bounds-1-ref.html
== size-1.html size-1-ref.html
skip-if(B2G) fails-if(Android) == size-2.html size-2-ref.html
skip-if(B2G) == size-2.html size-2-ref.html
HTTP(..) == baseline-1.html baseline-1-ref.html
skip-if(B2G&&browserIsRemote) HTTP(..) == centering-1.xul centering-1-ref.xul # bug 974780
skip-if(B2G&&browserIsRemote) == dynamic-height-1.xul dynamic-height-1-ref.xul # bug 974780

View File

@ -1,4 +1,4 @@
skip-if(B2G) fails-if(Android) HTTP(..) == text-control-baseline-1.html text-control-baseline-1-ref.html
skip-if(B2G) HTTP(..) == text-control-baseline-1.html text-control-baseline-1-ref.html
# button element
include button/reftest.list

View File

@ -25,7 +25,7 @@ fails-if(!nativeThemePref) != radio-native.html radio-nonnative.html
== radio-still-native-when-styled.html radio-still-native-when-styled-ref.html
fails-if(!nativeThemePref) != checkbox-native.html checkbox-nonnative.html
== checkbox-still-native-when-styled.html checkbox-still-native-when-styled-ref.html
fails-if(Android) == native-theme-disabled-cascade-levels.html native-theme-disabled-cascade-levels-ref.html
== native-theme-disabled-cascade-levels.html native-theme-disabled-cascade-levels-ref.html
!= 427122-1.html 427122-1-ref.html

View File

@ -444,6 +444,9 @@ pref("dom.max_script_run_time", 20);
// JS error console
pref("devtools.errorconsole.enabled", false);
// Absolute path to the devtools unix domain socket file used
// to communicate with a usb cable via adb forward.
pref("devtools.debugger.unix-domain-socket", "/data/data/@ANDROID_PACKAGE_NAME@/firefox-debugger-socket");
pref("font.size.inflation.minTwips", 120);

View File

@ -7,7 +7,7 @@
for var in ('APP_NAME', 'APP_VERSION'):
DEFINES[var] = CONFIG['MOZ_%s' % var]
for var in ('MOZ_UPDATER', 'MOZ_APP_UA_NAME'):
for var in ('MOZ_UPDATER', 'MOZ_APP_UA_NAME', 'ANDROID_PACKAGE_NAME'):
DEFINES[var] = CONFIG[var]
if CONFIG['MOZ_PKG_SPECIAL']:

View File

@ -100,6 +100,7 @@ import android.nfc.NfcAdapter;
import android.nfc.NfcEvent;
import android.os.Build;
import android.os.Bundle;
import android.os.StrictMode;
import android.support.v4.app.FragmentManager;
import android.support.v4.content.LocalBroadcastManager;
import android.text.TextUtils;
@ -279,10 +280,37 @@ public class BrowserApp extends GeckoApp
loadFavicon(tab);
}
break;
case BOOKMARK_ADDED:
showBookmarkAddedToast();
break;
case BOOKMARK_REMOVED:
showBookmarkRemovedToast();
break;
}
super.onTabChanged(tab, msg, data);
}
private void showBookmarkAddedToast() {
getButtonToast().show(false,
getResources().getString(R.string.bookmark_added),
ButtonToast.LENGTH_SHORT,
getResources().getString(R.string.bookmark_options),
null,
new ButtonToast.ToastListener() {
@Override
public void onButtonClicked() {
showBookmarkDialog();
}
@Override
public void onToastHidden(ButtonToast.ReasonHidden reason) { }
});
}
private void showBookmarkRemovedToast() {
Toast.makeText(this, R.string.bookmark_removed, Toast.LENGTH_SHORT).show();
}
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (AndroidGamepadManager.handleKeyEvent(event)) {
@ -607,7 +635,7 @@ public class BrowserApp extends GeckoApp
Method init = mediaManagerClass.getMethod("init", Context.class);
init.invoke(null, this);
} catch(Exception ex) {
Log.i(LOGTAG, "Error initializing media manager", ex);
Log.e(LOGTAG, "Error initializing media manager", ex);
}
}
}
@ -637,7 +665,7 @@ public class BrowserApp extends GeckoApp
return Class.forName("org.mozilla.gecko.MediaPlayerManager");
} catch(Exception ex) {
// Ignore failures
Log.i(LOGTAG, "No native casting support", ex);
Log.e(LOGTAG, "No native casting support", ex);
}
}
@ -859,7 +887,7 @@ public class BrowserApp extends GeckoApp
try {
args.put("tabId", tab.getId());
} catch (JSONException e) {
Log.e(LOGTAG, "error building json arguments");
Log.e(LOGTAG, "error building json arguments", e);
}
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Feeds:Subscribe", args.toString()));
if (Versions.preHC) {
@ -877,7 +905,7 @@ public class BrowserApp extends GeckoApp
try {
args.put("tabId", tab.getId());
} catch (JSONException e) {
Log.e(LOGTAG, "error building json arguments");
Log.e(LOGTAG, "error building json arguments", e);
return true;
}
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("SearchEngines:Add", args.toString()));
@ -1003,7 +1031,7 @@ public class BrowserApp extends GeckoApp
Method destroy = mediaManagerClass.getMethod("onDestroy", (Class[]) null);
destroy.invoke(null);
} catch(Exception ex) {
Log.i(LOGTAG, "Error destroying media manager", ex);
Log.e(LOGTAG, "Error destroying media manager", ex);
}
}
@ -1864,9 +1892,6 @@ public class BrowserApp extends GeckoApp
* {@link BrowserHealthRecorder#SEARCH_LOCATIONS}.
*/
private static void recordSearch(SearchEngine engine, String where) {
Log.i(LOGTAG, "Recording search: " +
((engine == null) ? "null" : engine.name) +
", " + where);
try {
String identifier = (engine == null) ? "other" : engine.getEngineIdentifier();
JSONObject message = new JSONObject();
@ -1875,7 +1900,7 @@ public class BrowserApp extends GeckoApp
message.put("identifier", identifier);
EventDispatcher.getInstance().dispatchEvent(message, null);
} catch (Exception e) {
Log.w(LOGTAG, "Error recording search.", e);
Log.e(LOGTAG, "Error recording search.", e);
}
}
@ -2269,7 +2294,6 @@ public class BrowserApp extends GeckoApp
item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
Log.i(LOGTAG, "Menu item clicked");
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Menu:Clicked", Integer.toString(info.id - ADDON_MENU_OFFSET)));
return true;
}
@ -2620,25 +2644,10 @@ public class BrowserApp extends GeckoApp
if (item.isChecked()) {
Telemetry.sendUIEvent(TelemetryContract.Event.UNSAVE, TelemetryContract.Method.MENU, "bookmark");
tab.removeBookmark();
Toast.makeText(this, R.string.bookmark_removed, Toast.LENGTH_SHORT).show();
item.setIcon(R.drawable.ic_menu_bookmark_add);
} else {
Telemetry.sendUIEvent(TelemetryContract.Event.SAVE, TelemetryContract.Method.MENU, "bookmark");
tab.addBookmark();
getButtonToast().show(false,
getResources().getString(R.string.bookmark_added),
ButtonToast.LENGTH_SHORT,
getResources().getString(R.string.bookmark_options),
null,
new ButtonToast.ToastListener() {
@Override
public void onButtonClicked() {
showBookmarkDialog();
}
@Override
public void onToastHidden(ButtonToast.ReasonHidden reason) { }
});
item.setIcon(R.drawable.ic_menu_bookmark_remove);
}
}
@ -2729,7 +2738,7 @@ public class BrowserApp extends GeckoApp
args.put("desktopMode", !item.isChecked());
args.put("tabId", selectedTab.getId());
} catch (JSONException e) {
Log.e(LOGTAG, "error building json arguments");
Log.e(LOGTAG, "error building json arguments", e);
}
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("DesktopMode:Change", args.toString()));
return true;
@ -2859,30 +2868,27 @@ public class BrowserApp extends GeckoApp
return;
}
(new UIAsyncTask.WithoutParams<Boolean>(ThreadUtils.getBackgroundHandler()) {
@Override
public synchronized Boolean doInBackground() {
// Check to see how many times the app has been launched.
SharedPreferences settings = getPreferences(Activity.MODE_PRIVATE);
String keyName = getPackageName() + ".feedback_launch_count";
int launchCount = settings.getInt(keyName, 0);
if (launchCount >= FEEDBACK_LAUNCH_COUNT)
return false;
// Check to see how many times the app has been launched.
final String keyName = getPackageName() + ".feedback_launch_count";
final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
// Faster on main thread with an async apply().
try {
SharedPreferences settings = getPreferences(Activity.MODE_PRIVATE);
int launchCount = settings.getInt(keyName, 0);
if (launchCount < FEEDBACK_LAUNCH_COUNT) {
// Increment the launch count and store the new value.
launchCount++;
settings.edit().putInt(keyName, launchCount).commit();
settings.edit().putInt(keyName, launchCount).apply();
// If we've reached our magic number, show the feedback page.
return launchCount == FEEDBACK_LAUNCH_COUNT;
}
@Override
public void onPostExecute(Boolean shouldShowFeedbackPage) {
if (shouldShowFeedbackPage)
if (launchCount == FEEDBACK_LAUNCH_COUNT) {
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Feedback:Show", null));
}
}
}).execute();
} finally {
StrictMode.setThreadPolicy(savedPolicy);
}
}
@Override
@ -2893,13 +2899,8 @@ public class BrowserApp extends GeckoApp
}
private void resetFeedbackLaunchCount() {
ThreadUtils.postToBackgroundThread(new Runnable() {
@Override
public synchronized void run() {
SharedPreferences settings = getPreferences(Activity.MODE_PRIVATE);
settings.edit().putInt(getPackageName() + ".feedback_launch_count", 0).commit();
}
});
SharedPreferences settings = getPreferences(Activity.MODE_PRIVATE);
settings.edit().putInt(getPackageName() + ".feedback_launch_count", 0).apply();
}
private void getLastUrl() {

View File

@ -282,7 +282,7 @@ public class BrowserLocaleManager implements LocaleManager {
public void resetToSystemLocale(Context context) {
// Wipe the pref.
final SharedPreferences settings = getSharedPreferences(context);
settings.edit().remove(PREF_LOCALE).commit();
settings.edit().remove(PREF_LOCALE).apply();
// Apply the system locale.
updateLocale(context, systemLocale);
@ -324,7 +324,7 @@ public class BrowserLocaleManager implements LocaleManager {
private void persistLocale(Context context, String localeCode) {
final SharedPreferences settings = getSharedPreferences(context);
settings.edit().putString(PREF_LOCALE, localeCode).commit();
settings.edit().putString(PREF_LOCALE, localeCode).apply();
}
@Override

View File

@ -137,7 +137,7 @@ public class CrashReporter extends Activity
SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean(GeckoApp.PREFS_WAS_STOPPED, true);
editor.putBoolean(GeckoApp.PREFS_CRASHED, true);
editor.commit();
editor.apply();
final CheckBox allowContactCheckBox = (CheckBox) findViewById(R.id.allow_contact);
final CheckBox includeUrlCheckBox = (CheckBox) findViewById(R.id.include_url);

View File

@ -44,7 +44,7 @@ public class DataReportingNotification {
if (AppConstants.MOZ_SERVICES_HEALTHREPORT) {
SharedPreferences.Editor editor = dataPrefs.edit();
editor.putBoolean(GeckoPreferences.PREFS_HEALTHREPORT_UPLOAD_ENABLED, true);
editor.commit();
editor.apply();
}
return;
}
@ -57,7 +57,7 @@ public class DataReportingNotification {
// Silently update the version.
SharedPreferences.Editor editor = dataPrefs.edit();
editor.putInt(PREFS_POLICY_VERSION, DATA_REPORTING_VERSION);
editor.commit();
editor.apply();
}
return;
}
@ -123,7 +123,7 @@ public class DataReportingNotification {
long now = System.currentTimeMillis();
editor.putLong(PREFS_POLICY_NOTIFIED_TIME, now);
editor.putInt(PREFS_POLICY_VERSION, DATA_REPORTING_VERSION);
editor.commit();
editor.apply();
result = true;
} finally {
// We want to track any errors, so record notification outcome.

View File

@ -27,7 +27,6 @@ import java.util.concurrent.CopyOnWriteArrayList;
public final class EventDispatcher {
private static final String LOGTAG = "GeckoEventDispatcher";
private static final String GUID = "__guid__";
private static final String STATUS_CANCEL = "cancel";
private static final String STATUS_ERROR = "error";
private static final String STATUS_SUCCESS = "success";
@ -200,10 +199,9 @@ public final class EventDispatcher {
if (listeners == null || listeners.size() == 0) {
Log.w(LOGTAG, "No listeners for " + type);
// If there are no listeners, cancel the callback to prevent Gecko-side observers
// from being leaked.
// If there are no listeners, dispatch an error.
if (callback != null) {
callback.sendCancel();
callback.sendError("No listeners for request");
}
return;
}
@ -258,10 +256,6 @@ public final class EventDispatcher {
sendResponse(STATUS_ERROR, response);
}
public void sendCancel() {
sendResponse(STATUS_CANCEL, null);
}
private void sendResponse(final String status, final Object response) {
if (sent) {
throw new IllegalStateException("Callback has already been executed for type=" +

View File

@ -1222,8 +1222,7 @@ public abstract class GeckoApp
// injecting states.
final SharedPreferences prefs = getSharedPreferences();
if (prefs.getBoolean(PREFS_ALLOW_STATE_BUNDLE, false)) {
Log.i(LOGTAG, "Restoring state from intent bundle");
prefs.edit().remove(PREFS_ALLOW_STATE_BUNDLE).commit();
prefs.edit().remove(PREFS_ALLOW_STATE_BUNDLE).apply();
savedInstanceState = stateBundle;
}
} else if (savedInstanceState != null) {
@ -1279,14 +1278,13 @@ public abstract class GeckoApp
// on exit, or if we were suddenly killed (crash or native OOM).
editor.putBoolean(GeckoApp.PREFS_WAS_STOPPED, false);
editor.commit();
editor.apply();
// The lifecycle of mHealthRecorder is "shortly after onCreate"
// through "onDestroy" -- essentially the same as the lifecycle
// of the activity itself.
final String profilePath = getProfile().getDir().getAbsolutePath();
final EventDispatcher dispatcher = EventDispatcher.getInstance();
Log.i(LOGTAG, "Creating HealthRecorder.");
final String osLocale = Locale.getDefault().toString();
String appLocale = localeManager.getAndApplyPersistedLocale(GeckoApp.this);
@ -1691,15 +1689,7 @@ public abstract class GeckoApp
if (prefs.getInt(PREFS_VERSION_CODE, 0) != versionCode) {
// If the version has changed, the user has done an upgrade, so restore
// previous tabs.
ThreadUtils.postToBackgroundThread(new Runnable() {
@Override
public void run() {
prefs.edit()
.putInt(PREFS_VERSION_CODE, versionCode)
.commit();
}
});
prefs.edit().putInt(PREFS_VERSION_CODE, versionCode).apply();
shouldRestore = true;
} else if (savedInstanceState != null ||
getSessionRestorePreference().equals("always") ||
@ -1708,12 +1698,7 @@ public abstract class GeckoApp
// has chosen to always restore, or we restarted.
shouldRestore = true;
} else if (prefs.getBoolean(GeckoApp.PREFS_CRASHED, false)) {
ThreadUtils.postToBackgroundThread(new Runnable() {
@Override
public void run() {
prefs.edit().putBoolean(PREFS_CRASHED, false).commit();
}
});
prefs.edit().putBoolean(PREFS_CRASHED, false).apply();
shouldRestore = true;
}
@ -1959,7 +1944,7 @@ public abstract class GeckoApp
SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean(GeckoApp.PREFS_WAS_STOPPED, false);
currentSession.recordBegin(editor);
editor.commit();
editor.apply();
final HealthRecorder rec = mHealthRecorder;
if (rec != null) {
@ -2008,7 +1993,7 @@ public abstract class GeckoApp
editor.putBoolean(GeckoApp.PREFS_CLEANUP_TEMP_FILES, false);
}
editor.commit();
editor.apply();
// In theory, the first browser session will not run long enough that we need to
// prune during it and we'd rather run it when the browser is inactive so we wait
@ -2027,24 +2012,22 @@ public abstract class GeckoApp
}
@Override
public void onRestart()
{
ThreadUtils.postToBackgroundThread(new Runnable() {
@Override
public void run() {
SharedPreferences prefs = GeckoApp.this.getSharedPreferences();
SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean(GeckoApp.PREFS_WAS_STOPPED, false);
editor.commit();
}
});
public void onRestart() {
// Faster on main thread with an async apply().
final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
try {
SharedPreferences.Editor editor = GeckoApp.this.getSharedPreferences().edit();
editor.putBoolean(GeckoApp.PREFS_WAS_STOPPED, false);
editor.apply();
} finally {
StrictMode.setThreadPolicy(savedPolicy);
}
super.onRestart();
}
@Override
public void onDestroy()
{
public void onDestroy() {
EventDispatcher.getInstance().unregisterGeckoThreadListener((GeckoEventListener)this,
"Gecko:Ready",
"Gecko:DelayedStartup",
@ -2094,6 +2077,7 @@ public abstract class GeckoApp
mTextSelection.destroy();
NotificationHelper.destroy();
IntentHelper.destroy();
GeckoNetworkManager.destroy();
if (SmsManager.getInstance() != null) {
SmsManager.getInstance().stop();
@ -2250,14 +2234,11 @@ public abstract class GeckoApp
if (dir.exists() && dir.isDirectory()) {
for (File file : dir.listFiles()) {
if (file.isFile() && file.getName().endsWith(".ttf")) {
Log.i(LOGTAG, "deleting " + file.toString());
file.delete();
}
}
if (!dir.delete()) {
Log.w(LOGTAG, "unable to delete res/fonts directory (not empty?)");
} else {
Log.i(LOGTAG, "res/fonts directory deleted");
}
}
}
@ -2267,7 +2248,7 @@ public abstract class GeckoApp
if (cleanupVersion != CURRENT_CLEANUP_VERSION) {
SharedPreferences.Editor editor = GeckoApp.this.getSharedPreferences().edit();
editor.putInt(CLEANUP_VERSION, CURRENT_CLEANUP_VERSION);
editor.commit();
editor.apply();
}
}
}
@ -2592,7 +2573,6 @@ public abstract class GeckoApp
* and poke HealthRecorder to tell it of our changed state.
*/
protected void setLocale(final String locale) {
Log.d(LOGTAG, "setLocale: " + locale);
if (locale == null) {
return;
}

View File

@ -485,6 +485,9 @@ public class GeckoAppShell
SharedPreferences prefs = getSharedPreferences();
SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean(GeckoApp.PREFS_OOM_EXCEPTION, true);
// Synchronously write to disk so we know it's done before we
// shutdown
editor.commit();
}
} finally {

View File

@ -39,6 +39,12 @@ public class GeckoNetworkManager extends BroadcastReceiver implements NativeEven
static private final GeckoNetworkManager sInstance = new GeckoNetworkManager();
public static void destroy() {
if (sInstance != null) {
sInstance.onDestroy();
}
}
// Connection Type defined in Network Information API v3.
private enum ConnectionType {
CELLULAR(0),
@ -60,6 +66,14 @@ public class GeckoNetworkManager extends BroadcastReceiver implements NativeEven
MNC
}
private GeckoNetworkManager() {
EventDispatcher.getInstance().registerGeckoThreadListener(this, "Wifi:Enable");
}
private void onDestroy() {
EventDispatcher.getInstance().unregisterGeckoThreadListener(this, "Wifi:Enable");
}
private ConnectionType mConnectionType = ConnectionType.NONE;
private final IntentFilter mNetworkFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
@ -96,8 +110,6 @@ public class GeckoNetworkManager extends BroadcastReceiver implements NativeEven
if (mShouldNotify) {
startListening();
}
EventDispatcher.getInstance().registerGeckoThreadListener((NativeEventListener)this, "Wifi:Enable");
}
private void startListening() {
@ -117,8 +129,6 @@ public class GeckoNetworkManager extends BroadcastReceiver implements NativeEven
if (mShouldNotify) {
stopListening();
}
EventDispatcher.getInstance().unregisterGeckoThreadListener((NativeEventListener)this, "Wifi:Enable");
}
@Override

View File

@ -186,7 +186,7 @@ public final class GeckoProfile {
if (success) {
// Clear all shared prefs for the given profile.
GeckoSharedPrefs.forProfileName(context, profileName)
.edit().clear().commit();
.edit().clear().apply();
}
return success;
@ -270,7 +270,7 @@ public final class GeckoProfile {
if (success) {
// Clear all shared prefs for the guest profile.
GeckoSharedPrefs.forProfileName(context, GUEST_PROFILE)
.edit().clear().commit();
.edit().clear().apply();
}
}

View File

@ -204,10 +204,10 @@ public final class GeckoSharedPrefs {
// Update prefs version accordingly.
appEditor.putInt(PREFS_VERSION_KEY, PREFS_VERSION);
appEditor.commit();
profileEditor.commit();
appEditor.apply();
profileEditor.apply();
if (pmEditor != null) {
pmEditor.commit();
pmEditor.apply();
}
Log.d(LOGTAG, "All keys have been migrated");

View File

@ -151,7 +151,7 @@ public final class SharedPreferencesHelper
} else {
Log.w(LOGTAG, "Unknown pref value type [" + type + "] for pref [" + name + "]");
}
editor.commit();
editor.apply();
}
}

View File

@ -459,6 +459,7 @@ public class Tab {
return;
BrowserDB.addBookmark(getContentResolver(), mTitle, url);
Tabs.getInstance().notifyListeners(Tab.this, Tabs.TabEvents.BOOKMARK_ADDED);
}
});
}
@ -472,6 +473,7 @@ public class Tab {
return;
BrowserDB.removeBookmarksWithURL(getContentResolver(), url);
Tabs.getInstance().notifyListeners(Tab.this, Tabs.TabEvents.BOOKMARK_REMOVED);
}
});
}

View File

@ -597,7 +597,9 @@ public class Tabs implements GeckoEventListener {
READER_ENABLED,
DESKTOP_MODE_CHANGE,
VIEWPORT_CHANGE,
RECORDING_CHANGE
RECORDING_CHANGE,
BOOKMARK_ADDED,
BOOKMARK_REMOVED
}
public void notifyListeners(Tab tab, TabEvents msg) {

View File

@ -385,7 +385,7 @@ public class SuggestedSites {
private static void updateSuggestedSitesLocale(Context context) {
final Editor editor = GeckoSharedPrefs.forProfile(context).edit();
editor.putString(PREF_SUGGESTED_SITES_LOCALE, Locale.getDefault().toString());
editor.commit();
editor.apply();
}
private boolean isEnabled() {
@ -582,6 +582,6 @@ public class SuggestedSites {
final SharedPreferences prefs = GeckoSharedPrefs.forProfile(context);
final String prefString = prefs.getString(PREF_SUGGESTED_SITES_HIDDEN, "");
final String siteString = prefString.concat(" " + Uri.encode(url));
prefs.edit().putString(PREF_SUGGESTED_SITES_HIDDEN, siteString).commit();
prefs.edit().putString(PREF_SUGGESTED_SITES_HIDDEN, siteString).apply();
}
}

View File

@ -371,7 +371,7 @@ public class Distribution {
checkSystemDistribution();
this.state = distributionSet ? STATE_SET : STATE_NONE;
settings.edit().putInt(keyName, this.state).commit();
settings.edit().putInt(keyName, this.state).apply();
runReadyQueue();
return distributionSet;

View File

@ -8,6 +8,10 @@ package org.mozilla.gecko.home;
import java.util.Date;
import java.util.EnumSet;
import org.json.JSONException;
import org.json.JSONObject;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.GeckoEvent;
import org.mozilla.gecko.R;
import org.mozilla.gecko.Telemetry;
import org.mozilla.gecko.TelemetryContract;
@ -25,6 +29,7 @@ import android.database.Cursor;
import android.os.Bundle;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.Loader;
import android.util.Log;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
@ -123,13 +128,16 @@ public class HistoryPanel extends HomeFragment {
@Override
public void onClick(final DialogInterface dialog, final int which) {
dialog.dismiss();
ThreadUtils.postToBackgroundThread(new Runnable() {
@Override
public void run() {
final ContentResolver cr = context.getContentResolver();
BrowserDB.clearHistory(cr);
}
});
// Send message to Java to clear history.
final JSONObject json = new JSONObject();
try {
json.put("history", true);
} catch (JSONException e) {
Log.e(LOGTAG, "JSON error", e);
}
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Sanitize:ClearData", json.toString()));
Telemetry.sendUIEvent(TelemetryContract.Event.SANITIZE, TelemetryContract.Method.BUTTON, "history");
}

View File

@ -197,7 +197,7 @@ class HomeConfigPrefsBackend implements HomeConfigBackend {
newJson.put(JSON_KEY_VERSION, VERSION);
prefsEditor.putString(PREFS_CONFIG_KEY, newJson.toString());
prefsEditor.commit();
prefsEditor.apply();
return newJsonPanels;
}
@ -278,7 +278,7 @@ class HomeConfigPrefsBackend implements HomeConfigBackend {
}
editor.putString(PREFS_LOCALE_KEY, Locale.getDefault().toString());
editor.commit();
editor.apply();
// Trigger reload listeners on all live backend instances
sendReloadBroadcast();
@ -295,7 +295,7 @@ class HomeConfigPrefsBackend implements HomeConfigBackend {
final SharedPreferences.Editor editor = prefs.edit();
editor.putString(PREFS_LOCALE_KEY, currentLocale);
editor.commit();
editor.apply();
// If the user has saved HomeConfig before, return null this
// one time to trigger a refresh and ensure we use the

View File

@ -355,7 +355,7 @@ public class HomePanelsManager implements GeckoEventListener {
public void run() {
final HomeConfig.Editor editor = mHomeConfig.load().edit();
executePendingChanges(editor);
editor.commit();
editor.apply();
}
};
}

View File

@ -28,17 +28,6 @@ public class MenuPanel extends LinearLayout {
setLayoutParams(new ViewGroup.LayoutParams(width, ViewGroup.LayoutParams.WRAP_CONTENT));
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// Restrict the height to 75% of the screen-height. heightPixels changes during rotation.
DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
int restrictedHeightSpec = MeasureSpec.makeMeasureSpec((int) (0.75 * metrics.heightPixels), MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, restrictedHeightSpec);
}
@Override
public boolean dispatchPopulateAccessibilityEvent (AccessibilityEvent event) {
if (Versions.feature14Plus) {

View File

@ -267,7 +267,6 @@ gbjar.sources += [
'home/BookmarksPanel.java',
'home/BrowserSearch.java',
'home/DynamicPanel.java',
'home/FadedTextView.java',
'home/FramePanelLayout.java',
'home/HistoryPanel.java',
'home/HomeAdapter.java',
@ -443,6 +442,7 @@ gbjar.sources += [
'widget/Divider.java',
'widget/DoorHanger.java',
'widget/EllipsisTextView.java',
'widget/FadedTextView.java',
'widget/FaviconView.java',
'widget/FloatingHintEditText.java',
'widget/FlowLayout.java',

View File

@ -36,8 +36,8 @@ public class SendTabDeviceListArrayAdapter extends ArrayAdapter<ParcelableClient
// This will show the user a prompt to select a device from a longer list of devices.
private AlertDialog dialog;
public SendTabDeviceListArrayAdapter(Context context, SendTabTargetSelectedListener aListener, int textViewResourceId) {
super(context, textViewResourceId);
public SendTabDeviceListArrayAdapter(Context context, SendTabTargetSelectedListener aListener) {
super(context, R.layout.overlay_share_send_tab_item);
listener = aListener;

View File

@ -103,6 +103,7 @@ public class ShareDialog extends LocaleAware.LocaleAwareActivity implements Send
// trying to send a share intent).
Toast toast = Toast.makeText(this, getResources().getText(R.string.overlay_share_no_url), Toast.LENGTH_SHORT);
toast.show();
finish();
return;
}
@ -162,7 +163,7 @@ public class ShareDialog extends LocaleAware.LocaleAwareActivity implements Send
SendTabList sendTabList = (SendTabList) findViewById(R.id.overlay_send_tab_btn);
// Register ourselves as both the listener and the context for the Adapter.
SendTabDeviceListArrayAdapter adapter = new SendTabDeviceListArrayAdapter(this, this, R.layout.sync_list_item);
SendTabDeviceListArrayAdapter adapter = new SendTabDeviceListArrayAdapter(this, this);
sendTabList.setAdapter(adapter);
sendTabList.setSendTabTargetSelectedListener(this);
}

View File

@ -0,0 +1,13 @@
<?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/.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:drawable="@color/overlay_share_selected" />
<item android:drawable="@color/overlay_share_background"/>
</selector>

View File

@ -30,7 +30,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="0dp"
android:background="@color/background_light"
android:background="@color/overlay_share_header_background"
android:orientation="vertical"
android:paddingTop="10dp"
android:paddingBottom="15dp"
@ -63,7 +63,7 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/overlay_share_background_colour"
android:background="@color/overlay_share_background"
android:orientation="vertical">
<!-- TODO: Once API 11 is available, stick "showDividers=middle" into the parent and get rid
@ -73,7 +73,6 @@
<org.mozilla.gecko.overlays.ui.SendTabList
style="@style/ShareOverlayButton"
android:id="@+id/overlay_send_tab_btn"
android:background="@color/overlay_share_background_colour"
android:padding="0dp"/>
<!-- Evil separator -->

View File

@ -20,6 +20,7 @@
<TextView
android:id="@+id/client_name"
style="@style/ShareOverlayButton.Text"
android:layout_gravity="center"
android:layout_width="0dp"
android:layout_weight="0.5"

View File

@ -12,7 +12,7 @@
android:layout_height="wrap_content"
android:layout_alignParentTop="true"/>
<org.mozilla.gecko.home.FadedTextView
<org.mozilla.gecko.widget.FadedTextView
android:id="@+id/title"
style="@style/Widget.TopSitesGridItemTitle"
android:layout_width="match_parent"

View File

@ -17,7 +17,7 @@
android:layout_marginRight="10dip"
android:orientation="vertical">
<org.mozilla.gecko.home.FadedTextView
<org.mozilla.gecko.widget.FadedTextView
android:id="@+id/title"
style="@style/Widget.TwoLinePageRow.Title"
android:layout_width="match_parent"

View File

@ -51,8 +51,11 @@
<!-- Colour used for share overlay button labels -->
<color name="text_color_overlaybtn">#666666</color>
<!-- Colour used for share overlay button background -->
<color name="overlay_share_background_colour">#FFD0CECB</color>
<color name="overlay_share_header_background">#FFFFFFFF</color>
<!-- Colours used for share overlay button background -->
<color name="overlay_share_background">#FFEBEBF0</color>
<color name="overlay_share_selected">#FFF5F5F5</color>
<!-- Disabled colors -->
<color name="text_color_primary_disable_only">#999999</color>

Some files were not shown because too many files have changed in this diff Show More