mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 05:11:16 +00:00
Merge autoland to m-c. a=merge
This commit is contained in:
commit
c1ebf1a679
@ -55,12 +55,13 @@ DEFAULT_NO_CONNECTIONS_PREFS = {
|
||||
'browser.newtab.url' : 'about:blank',
|
||||
'browser.search.update': False,
|
||||
'browser.search.suggest.enabled' : False,
|
||||
'browser.safebrowsing.downloads.remote.url': 'http://localhost/safebrowsing-dummy/downloads',
|
||||
'browser.safebrowsing.malware.enabled' : False,
|
||||
'browser.safebrowsing.phishing.enabled' : False,
|
||||
'browser.safebrowsing.provider.google.updateURL': 'http://localhost/safebrowsing-dummy/update',
|
||||
'browser.safebrowsing.provider.google.gethashURL': 'http://localhost/safebrowsing-dummy/gethash',
|
||||
'browser.safebrowsing.provider.google4.updateURL': 'http://localhost/safebrowsing4-dummy/update',
|
||||
'browser.safebrowsing.provider.google4.gethashURL': 'http://localhost/safebrowsing4-dummy/gethash',
|
||||
'browser.safebrowsing.malware.reportURL': 'http://localhost/safebrowsing-dummy/malwarereport',
|
||||
'browser.selfsupport.url': 'https://localhost/selfsupport-dummy',
|
||||
'browser.safebrowsing.provider.mozilla.gethashURL': 'http://localhost/safebrowsing-dummy/gethash',
|
||||
'browser.safebrowsing.provider.mozilla.updateURL': 'http://localhost/safebrowsing-dummy/update',
|
||||
@ -118,6 +119,7 @@ DEFAULT_FIREFOX_PREFS = {
|
||||
# Make url-classifier updates so rare that they won't affect tests.
|
||||
'urlclassifier.updateinterval' : 172800,
|
||||
# Point the url-classifier to a nonexistent local URL for fast failures.
|
||||
'browser.safebrowsing.downloads.remote.url': 'http://localhost/safebrowsing-dummy/downloads',
|
||||
'browser.safebrowsing.provider.google.gethashURL' : 'http://localhost/safebrowsing-dummy/gethash',
|
||||
'browser.safebrowsing.provider.google.updateURL' : 'http://localhost/safebrowsing-dummy/update',
|
||||
'browser.safebrowsing.provider.google4.gethashURL' : 'http://localhost/safebrowsing4-dummy/gethash',
|
||||
|
@ -15,6 +15,8 @@
|
||||
"browser.newtab.url": "about:blank",
|
||||
"browser.search.update": false,
|
||||
"browser.search.suggest.enabled": false,
|
||||
"browser.safebrowsing.downloads.remote.url": "http://localhost/safebrowsing-dummy/downloads",
|
||||
"browser.safebrowsing.malware.enabled": false,
|
||||
"browser.safebrowsing.phishing.enabled": false,
|
||||
"browser.safebrowsing.provider.google.updateURL": "http://localhost/safebrowsing-dummy/update",
|
||||
"browser.safebrowsing.provider.google.gethashURL": "http://localhost/safebrowsing-dummy/gethash",
|
||||
|
@ -175,6 +175,14 @@ appUpdater.prototype =
|
||||
if (button) {
|
||||
if (aChildID == "downloadAndInstall") {
|
||||
let updateVersion = gAppUpdater.update.displayVersion;
|
||||
// Include the build ID if this is an "a#" (nightly or aurora) build
|
||||
if (/a\d+$/.test(updateVersion)) {
|
||||
let buildID = gAppUpdater.update.buildID;
|
||||
let year = buildID.slice(0, 4);
|
||||
let month = buildID.slice(4, 6);
|
||||
let day = buildID.slice(6, 8);
|
||||
updateVersion += ` (${year}-${month}-${day})`;
|
||||
}
|
||||
button.label = this.bundle.formatStringFromName("update.downloadAndInstallButton.label", [updateVersion], 1);
|
||||
button.accessKey = this.bundle.GetStringFromName("update.downloadAndInstallButton.accesskey");
|
||||
}
|
||||
|
@ -482,7 +482,7 @@ var PlacesCommandHook = {
|
||||
|
||||
try {
|
||||
info.title = docInfo.isErrorPage ?
|
||||
(await PlacesUtils.promisePlaceInfo(aBrowser.currentURI)).title :
|
||||
(await PlacesUtils.history.fetch(aBrowser.currentURI)).title :
|
||||
aBrowser.contentTitle;
|
||||
info.title = info.title || url.href;
|
||||
description = docInfo.description;
|
||||
|
@ -25,9 +25,6 @@ with Files("newtab/**"):
|
||||
with Files("pageinfo/**"):
|
||||
BUG_COMPONENT = ("Firefox", "Page Info Window")
|
||||
|
||||
with Files("sync/**"):
|
||||
BUG_COMPONENT = ("Firefox", "Sync")
|
||||
|
||||
with Files("test/alerts/**"):
|
||||
BUG_COMPONENT = ("Toolkit", "Notifications and Alerts")
|
||||
|
||||
|
@ -1,48 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<!-- 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/. -->
|
||||
|
||||
<!-- import-globals-from aboutSyncTabs.js -->
|
||||
|
||||
<bindings id="tabBindings"
|
||||
xmlns="http://www.mozilla.org/xbl"
|
||||
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
xmlns:xbl="http://www.mozilla.org/xbl">
|
||||
|
||||
<binding id="tab-listing" extends="chrome://global/content/bindings/richlistbox.xml#richlistitem">
|
||||
<content>
|
||||
<xul:hbox flex="1">
|
||||
<xul:vbox pack="start">
|
||||
<xul:image class="tabIcon"
|
||||
xbl:inherits="src=icon"/>
|
||||
</xul:vbox>
|
||||
<xul:vbox pack="start" flex="1">
|
||||
<xul:label xbl:inherits="value=title,selected"
|
||||
crop="end" flex="1" class="title"/>
|
||||
<xul:label xbl:inherits="value=url,selected"
|
||||
crop="end" flex="1" class="url"/>
|
||||
</xul:vbox>
|
||||
</xul:hbox>
|
||||
</content>
|
||||
<handlers>
|
||||
<handler event="dblclick" button="0">
|
||||
<![CDATA[
|
||||
RemoteTabViewer.openSelected();
|
||||
]]>
|
||||
</handler>
|
||||
</handlers>
|
||||
</binding>
|
||||
|
||||
<binding id="client-listing" extends="chrome://global/content/bindings/richlistbox.xml#richlistitem">
|
||||
<content>
|
||||
<xul:hbox pack="start" align="center" onfocus="event.target.blur()" onselect="return false;">
|
||||
<xul:image/>
|
||||
<xul:label xbl:inherits="value=clientName"
|
||||
class="clientName"
|
||||
crop="center" flex="1"/>
|
||||
</xul:hbox>
|
||||
</content>
|
||||
</binding>
|
||||
</bindings>
|
@ -1,11 +0,0 @@
|
||||
/* 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/. */
|
||||
|
||||
richlistitem[type="tab"] {
|
||||
-moz-binding: url(chrome://browser/content/sync/aboutSyncTabs-bindings.xml#tab-listing);
|
||||
}
|
||||
|
||||
richlistitem[type="client"] {
|
||||
-moz-binding: url(chrome://browser/content/sync/aboutSyncTabs-bindings.xml#client-listing);
|
||||
}
|
@ -1,305 +0,0 @@
|
||||
/* 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/. */
|
||||
|
||||
/* import-globals-from ../utilityOverlay.js */
|
||||
|
||||
var Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://services-common/utils.js");
|
||||
Cu.import("resource://services-sync/main.js");
|
||||
Cu.import("resource:///modules/PlacesUIUtils.jsm");
|
||||
Cu.import("resource://gre/modules/AppConstants.jsm");
|
||||
Cu.import("resource://gre/modules/PlacesUtils.jsm", this);
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
||||
"resource://gre/modules/Promise.jsm");
|
||||
|
||||
var RemoteTabViewer = {
|
||||
_tabsList: null,
|
||||
|
||||
init() {
|
||||
Services.obs.addObserver(this, "weave:service:login:finish");
|
||||
Services.obs.addObserver(this, "weave:engine:sync:finish");
|
||||
|
||||
this._tabsList = document.getElementById("tabsList");
|
||||
|
||||
this.buildList(true);
|
||||
},
|
||||
|
||||
uninit() {
|
||||
Services.obs.removeObserver(this, "weave:service:login:finish");
|
||||
Services.obs.removeObserver(this, "weave:engine:sync:finish");
|
||||
},
|
||||
|
||||
createItem(attrs) {
|
||||
let item = document.createElement("richlistitem");
|
||||
|
||||
// Copy the attributes from the argument into the item.
|
||||
for (let attr in attrs) {
|
||||
item.setAttribute(attr, attrs[attr]);
|
||||
}
|
||||
|
||||
if (attrs["type"] == "tab") {
|
||||
item.label = attrs.title != "" ? attrs.title : attrs.url;
|
||||
}
|
||||
|
||||
return item;
|
||||
},
|
||||
|
||||
filterTabs(event) {
|
||||
let val = event.target.value.toLowerCase();
|
||||
let numTabs = this._tabsList.getRowCount();
|
||||
let clientTabs = 0;
|
||||
let currentClient = null;
|
||||
|
||||
for (let i = 0; i < numTabs; i++) {
|
||||
let item = this._tabsList.getItemAtIndex(i);
|
||||
let hide = false;
|
||||
if (item.getAttribute("type") == "tab") {
|
||||
if (!item.getAttribute("url").toLowerCase().includes(val) &&
|
||||
!item.getAttribute("title").toLowerCase().includes(val)) {
|
||||
hide = true;
|
||||
} else {
|
||||
clientTabs++;
|
||||
}
|
||||
} else if (item.getAttribute("type") == "client") {
|
||||
if (currentClient) {
|
||||
if (clientTabs == 0) {
|
||||
currentClient.hidden = true;
|
||||
}
|
||||
}
|
||||
currentClient = item;
|
||||
clientTabs = 0;
|
||||
}
|
||||
item.hidden = hide;
|
||||
}
|
||||
if (clientTabs == 0) {
|
||||
currentClient.hidden = true;
|
||||
}
|
||||
},
|
||||
|
||||
openSelected() {
|
||||
let items = this._tabsList.selectedItems;
|
||||
let urls = [];
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
if (items[i].getAttribute("type") == "tab") {
|
||||
urls.push(items[i].getAttribute("url"));
|
||||
let index = this._tabsList.getIndexOfItem(items[i]);
|
||||
this._tabsList.removeItemAt(index);
|
||||
}
|
||||
}
|
||||
if (urls.length) {
|
||||
getTopWin().gBrowser.loadTabs(urls);
|
||||
this._tabsList.clearSelection();
|
||||
}
|
||||
},
|
||||
|
||||
bookmarkSingleTab() {
|
||||
let item = this._tabsList.selectedItems[0];
|
||||
let uri = Weave.Utils.makeURI(item.getAttribute("url"));
|
||||
let title = item.getAttribute("title");
|
||||
PlacesUIUtils.showBookmarkDialog({ action: "add"
|
||||
, type: "bookmark"
|
||||
, uri
|
||||
, title
|
||||
, hiddenRows: [ "description"
|
||||
, "location"
|
||||
, "loadInSidebar"
|
||||
, "keyword" ]
|
||||
}, window.top);
|
||||
},
|
||||
|
||||
bookmarkSelectedTabs() {
|
||||
let items = this._tabsList.selectedItems;
|
||||
let URIs = [];
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
if (items[i].getAttribute("type") == "tab") {
|
||||
let uri = Weave.Utils.makeURI(items[i].getAttribute("url"));
|
||||
if (!uri) {
|
||||
continue;
|
||||
}
|
||||
|
||||
URIs.push(uri);
|
||||
}
|
||||
}
|
||||
if (URIs.length) {
|
||||
PlacesUIUtils.showBookmarkDialog({ action: "add"
|
||||
, type: "folder"
|
||||
, URIList: URIs
|
||||
, hiddenRows: [ "description" ]
|
||||
}, window.top);
|
||||
}
|
||||
},
|
||||
|
||||
getIcon(iconUri, defaultIcon) {
|
||||
try {
|
||||
let iconURI = Weave.Utils.makeURI(iconUri);
|
||||
return PlacesUtils.favicons.getFaviconLinkForIcon(iconURI).spec;
|
||||
} catch (ex) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
// Just give the provided default icon or the system's default.
|
||||
return defaultIcon || PlacesUtils.favicons.defaultFavicon.spec;
|
||||
},
|
||||
|
||||
_waitingForBuildList: false,
|
||||
|
||||
_buildListRequested: false,
|
||||
|
||||
buildList(forceSync) {
|
||||
if (this._waitingForBuildList) {
|
||||
this._buildListRequested = true;
|
||||
return;
|
||||
}
|
||||
|
||||
this._waitingForBuildList = true;
|
||||
this._buildListRequested = false;
|
||||
|
||||
this._clearTabList();
|
||||
|
||||
if (Weave.Service.isLoggedIn) {
|
||||
this._refetchTabs(forceSync);
|
||||
this._generateWeaveTabList();
|
||||
} else {
|
||||
// XXXzpao We should say something about not being logged in & not having data
|
||||
// or tell the appropriate condition. (bug 583344)
|
||||
}
|
||||
|
||||
this._waitingForBuildList = false;
|
||||
if (this._buildListRequested) {
|
||||
CommonUtils.nextTick(this.buildList, this);
|
||||
}
|
||||
},
|
||||
|
||||
_clearTabList() {
|
||||
let list = this._tabsList;
|
||||
|
||||
// Clear out existing richlistitems.
|
||||
let count = list.getRowCount();
|
||||
if (count > 0) {
|
||||
for (let i = count - 1; i >= 0; i--) {
|
||||
list.removeItemAt(i);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_generateWeaveTabList() {
|
||||
let engine = Weave.Service.engineManager.get("tabs");
|
||||
let list = this._tabsList;
|
||||
|
||||
let seenURLs = new Set();
|
||||
let localURLs = engine.getOpenURLs();
|
||||
|
||||
for (let [, client] of Object.entries(engine.getAllClients())) {
|
||||
// Create the client node, but don't add it in-case we don't show any tabs
|
||||
let appendClient = true;
|
||||
|
||||
client.tabs.forEach(function({title, urlHistory, icon}) {
|
||||
let url = urlHistory[0];
|
||||
if (!url || localURLs.has(url) || seenURLs.has(url)) {
|
||||
return;
|
||||
}
|
||||
seenURLs.add(url);
|
||||
|
||||
if (appendClient) {
|
||||
let attrs = {
|
||||
type: "client",
|
||||
clientName: client.clientName,
|
||||
class: Weave.Service.clientsEngine.isMobile(client.id) ? "mobile" : "desktop"
|
||||
};
|
||||
let clientEnt = this.createItem(attrs);
|
||||
list.appendChild(clientEnt);
|
||||
appendClient = false;
|
||||
clientEnt.disabled = true;
|
||||
}
|
||||
let attrs = {
|
||||
type: "tab",
|
||||
title: title || url,
|
||||
url,
|
||||
icon: this.getIcon(icon),
|
||||
}
|
||||
let tab = this.createItem(attrs);
|
||||
list.appendChild(tab);
|
||||
}, this);
|
||||
}
|
||||
},
|
||||
|
||||
adjustContextMenu(event) {
|
||||
let mode = "all";
|
||||
switch (this._tabsList.selectedItems.length) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
mode = "single"
|
||||
break;
|
||||
default:
|
||||
mode = "multiple";
|
||||
break;
|
||||
}
|
||||
|
||||
let menu = document.getElementById("tabListContext");
|
||||
let el = menu.firstChild;
|
||||
while (el) {
|
||||
let showFor = el.getAttribute("showFor");
|
||||
if (showFor) {
|
||||
el.hidden = showFor != mode && showFor != "all";
|
||||
}
|
||||
|
||||
el = el.nextSibling;
|
||||
}
|
||||
},
|
||||
|
||||
_refetchTabs(force) {
|
||||
if (!force) {
|
||||
// Don't bother refetching tabs if we already did so recently
|
||||
let lastFetch = Services.prefs.getIntPref("services.sync.lastTabFetch", 0);
|
||||
|
||||
let now = Math.floor(Date.now() / 1000);
|
||||
if (now - lastFetch < 30) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Ask Sync to just do the tabs engine if it can.
|
||||
Weave.Service.sync(["tabs"]);
|
||||
Services.prefs.setIntPref("services.sync.lastTabFetch",
|
||||
Math.floor(Date.now() / 1000));
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
observe(subject, topic, data) {
|
||||
switch (topic) {
|
||||
case "weave:service:login:finish":
|
||||
// A login has finished, which means that a Sync is about to start and
|
||||
// we will eventually get to the "tabs" engine - but try and force the
|
||||
// tab engine to sync first by passing |true| for the forceSync param.
|
||||
this.buildList(true);
|
||||
break;
|
||||
case "weave:engine:sync:finish":
|
||||
if (data == "tabs") {
|
||||
// The tabs engine just finished, so re-build the list without
|
||||
// forcing a new sync of the tabs engine.
|
||||
this.buildList(false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
handleClick(event) {
|
||||
if (event.target.getAttribute("type") != "tab") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.button == 1) {
|
||||
let url = event.target.getAttribute("url");
|
||||
openUILink(url, event);
|
||||
let index = this._tabsList.getIndexOfItem(event.target);
|
||||
this._tabsList.removeItemAt(index);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<?xml-stylesheet href="chrome://browser/skin/" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/aboutSyncTabs.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://browser/content/sync/aboutSyncTabs.css" type="text/css"?>
|
||||
|
||||
<!DOCTYPE window [
|
||||
<!ENTITY % aboutSyncTabsDTD SYSTEM "chrome://browser/locale/aboutSyncTabs.dtd">
|
||||
%aboutSyncTabsDTD;
|
||||
]>
|
||||
|
||||
<window id="tabs-display"
|
||||
onload="RemoteTabViewer.init()"
|
||||
onunload="RemoteTabViewer.uninit()"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
xmlns:html="http://www.w3.org/1999/xhtml"
|
||||
title="&tabs.otherDevices.label;">
|
||||
<script type="application/javascript" src="chrome://browser/content/sync/aboutSyncTabs.js"/>
|
||||
<script type="application/javascript" src="chrome://browser/content/utilityOverlay.js"/>
|
||||
<html:head>
|
||||
<html:link rel="icon" href="chrome://browser/skin/sync-16.png"/>
|
||||
</html:head>
|
||||
|
||||
<popupset id="contextmenus">
|
||||
<menupopup id="tabListContext">
|
||||
<menuitem label="&tabs.context.openTab.label;"
|
||||
accesskey="&tabs.context.openTab.accesskey;"
|
||||
oncommand="RemoteTabViewer.openSelected()"
|
||||
showFor="single"/>
|
||||
<menuitem label="&tabs.context.bookmarkSingleTab.label;"
|
||||
accesskey="&tabs.context.bookmarkSingleTab.accesskey;"
|
||||
oncommand="RemoteTabViewer.bookmarkSingleTab(event)"
|
||||
showFor="single"/>
|
||||
<menuitem label="&tabs.context.openMultipleTabs.label;"
|
||||
accesskey="&tabs.context.openMultipleTabs.accesskey;"
|
||||
oncommand="RemoteTabViewer.openSelected()"
|
||||
showFor="multiple"/>
|
||||
<menuitem label="&tabs.context.bookmarkMultipleTabs.label;"
|
||||
accesskey="&tabs.context.bookmarkMultipleTabs.accesskey;"
|
||||
oncommand="RemoteTabViewer.bookmarkSelectedTabs()"
|
||||
showFor="multiple"/>
|
||||
<menuseparator/>
|
||||
<menuitem label="&tabs.context.refreshList.label;"
|
||||
accesskey="&tabs.context.refreshList.accesskey;"
|
||||
oncommand="RemoteTabViewer.buildList()"
|
||||
showFor="all"/>
|
||||
</menupopup>
|
||||
</popupset>
|
||||
<richlistbox context="tabListContext" id="tabsList" seltype="multiple"
|
||||
align="center" flex="1"
|
||||
onclick="RemoteTabViewer.handleClick(event)"
|
||||
oncontextmenu="RemoteTabViewer.adjustContextMenu(event)">
|
||||
<hbox id="headers" align="center">
|
||||
<label id="tabsListHeading"
|
||||
value="&tabs.otherDevices.label;"/>
|
||||
<spacer flex="1"/>
|
||||
<textbox type="search"
|
||||
emptytext="&tabs.searchText.label;"
|
||||
oncommand="RemoteTabViewer.filterTabs(event)"/>
|
||||
</hbox>
|
||||
|
||||
</richlistbox>
|
||||
</window>
|
||||
|
@ -506,8 +506,6 @@ skip-if = os == "linux" || os == "mac" # No tabs in titlebar on linux
|
||||
[browser_tabkeynavigation.js]
|
||||
skip-if = (os == "mac" && !e10s) # Bug 1237713 - OSX eats keypresses for some reason
|
||||
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
|
||||
[browser_tabopen_reflows.js]
|
||||
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
|
||||
[browser_tabs_close_beforeunload.js]
|
||||
support-files =
|
||||
close_beforeunload_opens_second_tab.html
|
||||
@ -584,9 +582,6 @@ skip-if = (os == "win" && !debug)
|
||||
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
|
||||
[browser_web_channel.js]
|
||||
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
|
||||
[browser_windowopen_reflows.js]
|
||||
skip-if = os == "mac" # bug 1339317
|
||||
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
|
||||
[browser_zbug569342.js]
|
||||
skip-if = e10s || debug # Bug 1094240 - has findbar-related failures
|
||||
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
|
||||
|
@ -1,145 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "docShell", () => {
|
||||
return window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsIDocShell);
|
||||
});
|
||||
|
||||
const EXPECTED_REFLOWS = [
|
||||
// tabbrowser.adjustTabstrip() call after tabopen animation has finished
|
||||
"adjustTabstrip@chrome://browser/content/tabbrowser.xml|" +
|
||||
"_handleNewTab@chrome://browser/content/tabbrowser.xml|" +
|
||||
"onxbltransitionend@chrome://browser/content/tabbrowser.xml|",
|
||||
|
||||
// switching focus in updateCurrentBrowser() causes reflows
|
||||
"_adjustFocusAfterTabSwitch@chrome://browser/content/tabbrowser.xml|" +
|
||||
"updateCurrentBrowser@chrome://browser/content/tabbrowser.xml|" +
|
||||
"onselect@chrome://browser/content/browser.xul|",
|
||||
|
||||
// switching focus in openLinkIn() causes reflows
|
||||
"openLinkIn@chrome://browser/content/utilityOverlay.js|" +
|
||||
"openUILinkIn@chrome://browser/content/utilityOverlay.js|" +
|
||||
"BrowserOpenTab@chrome://browser/content/browser.js|",
|
||||
|
||||
// selection change notification may cause querying the focused editor content
|
||||
// by IME and that will cause reflow.
|
||||
"select@chrome://global/content/bindings/textbox.xml|" +
|
||||
"focusAndSelectUrlBar@chrome://browser/content/browser.js|" +
|
||||
"openLinkIn@chrome://browser/content/utilityOverlay.js|" +
|
||||
"openUILinkIn@chrome://browser/content/utilityOverlay.js|" +
|
||||
"BrowserOpenTab@chrome://browser/content/browser.js|",
|
||||
|
||||
];
|
||||
|
||||
const PREF_PRELOAD = "browser.newtab.preload";
|
||||
const PREF_NEWTAB_DIRECTORYSOURCE = "browser.newtabpage.directory.source";
|
||||
|
||||
/*
|
||||
* This test ensures that there are no unexpected
|
||||
* uninterruptible reflows when opening new tabs.
|
||||
*/
|
||||
add_task(async function() {
|
||||
let DirectoryLinksProvider = Cu.import("resource:///modules/DirectoryLinksProvider.jsm", {}).DirectoryLinksProvider;
|
||||
let NewTabUtils = Cu.import("resource://gre/modules/NewTabUtils.jsm", {}).NewTabUtils;
|
||||
let Promise = Cu.import("resource://gre/modules/Promise.jsm", {}).Promise;
|
||||
|
||||
// resolves promise when directory links are downloaded and written to disk
|
||||
function watchLinksChangeOnce() {
|
||||
return new Promise(resolve => {
|
||||
let observer = {
|
||||
onManyLinksChanged: () => {
|
||||
DirectoryLinksProvider.removeObserver(observer);
|
||||
NewTabUtils.links.populateCache(() => {
|
||||
NewTabUtils.allPages.update();
|
||||
resolve();
|
||||
}, true);
|
||||
}
|
||||
};
|
||||
observer.onDownloadFail = observer.onManyLinksChanged;
|
||||
DirectoryLinksProvider.addObserver(observer);
|
||||
});
|
||||
}
|
||||
|
||||
let gOrigDirectorySource = Services.prefs.getCharPref(PREF_NEWTAB_DIRECTORYSOURCE);
|
||||
registerCleanupFunction(() => {
|
||||
Services.prefs.clearUserPref(PREF_PRELOAD);
|
||||
Services.prefs.setCharPref(PREF_NEWTAB_DIRECTORYSOURCE, gOrigDirectorySource);
|
||||
return watchLinksChangeOnce();
|
||||
});
|
||||
|
||||
Services.prefs.setBoolPref(PREF_PRELOAD, false);
|
||||
// set directory source to dummy/empty links
|
||||
Services.prefs.setCharPref(PREF_NEWTAB_DIRECTORYSOURCE, 'data:application/json,{"test":1}');
|
||||
|
||||
// run tests when directory source change completes
|
||||
await watchLinksChangeOnce();
|
||||
|
||||
// Perform a click in the top left of content to ensure the mouse isn't
|
||||
// hovering over any of the tiles
|
||||
let target = gBrowser.selectedBrowser;
|
||||
let rect = target.getBoundingClientRect();
|
||||
let left = rect.left + 1;
|
||||
let top = rect.top + 1;
|
||||
|
||||
let utils = window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils);
|
||||
utils.sendMouseEvent("mousedown", left, top, 0, 1, 0, false, 0, 0);
|
||||
utils.sendMouseEvent("mouseup", left, top, 0, 1, 0, false, 0, 0);
|
||||
|
||||
// Add a reflow observer and open a new tab.
|
||||
docShell.addWeakReflowObserver(observer);
|
||||
BrowserOpenTab();
|
||||
|
||||
// Wait until the tabopen animation has finished.
|
||||
await waitForTransitionEnd();
|
||||
|
||||
// Remove reflow observer and clean up.
|
||||
docShell.removeWeakReflowObserver(observer);
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
||||
var observer = {
|
||||
reflow(start, end) {
|
||||
// Gather information about the current code path.
|
||||
let path = (new Error().stack).split("\n").slice(1).map(line => {
|
||||
return line.replace(/:\d+:\d+$/, "");
|
||||
}).join("|");
|
||||
let pathWithLineNumbers = (new Error().stack).split("\n").slice(1).join("|");
|
||||
|
||||
// Stack trace is empty. Reflow was triggered by native code.
|
||||
if (path === "") {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if this is an expected reflow.
|
||||
for (let stack of EXPECTED_REFLOWS) {
|
||||
if (path.startsWith(stack)) {
|
||||
ok(true, "expected uninterruptible reflow '" + stack + "'");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ok(false, "unexpected uninterruptible reflow '" + pathWithLineNumbers + "'");
|
||||
},
|
||||
|
||||
reflowInterruptible(start, end) {
|
||||
// We're not interested in interruptible reflows.
|
||||
},
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIReflowObserver,
|
||||
Ci.nsISupportsWeakReference])
|
||||
};
|
||||
|
||||
function waitForTransitionEnd() {
|
||||
return new Promise(resolve => {
|
||||
let tab = gBrowser.selectedTab;
|
||||
tab.addEventListener("transitionend", function onEnd(event) {
|
||||
if (event.propertyName === "max-width") {
|
||||
tab.removeEventListener("transitionend", onEnd);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
@ -1,117 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const EXPECTED_REFLOWS = [
|
||||
// handleEvent flushes layout to get the tabstrip width after a resize.
|
||||
"handleEvent@chrome://browser/content/tabbrowser.xml|",
|
||||
|
||||
// Loading a tab causes a reflow.
|
||||
"loadTabs@chrome://browser/content/tabbrowser.xml|" +
|
||||
"loadOneOrMoreURIs@chrome://browser/content/browser.js|" +
|
||||
"_delayedStartup@chrome://browser/content/browser.js|",
|
||||
|
||||
// Selecting the address bar causes a reflow.
|
||||
"select@chrome://global/content/bindings/textbox.xml|" +
|
||||
"focusAndSelectUrlBar@chrome://browser/content/browser.js|" +
|
||||
"_delayedStartup@chrome://browser/content/browser.js|",
|
||||
|
||||
// Focusing the content area causes a reflow.
|
||||
"_delayedStartup@chrome://browser/content/browser.js|",
|
||||
];
|
||||
|
||||
if (Services.appinfo.OS == "WINNT" || Services.appinfo.OS == "Darwin") {
|
||||
// TabsInTitlebar._update causes a reflow on OS X and Windows trying to do calculations
|
||||
// since layout info is already dirty. This doesn't seem to happen before
|
||||
// MozAfterPaint on Linux.
|
||||
EXPECTED_REFLOWS.push("rect@chrome://browser/content/browser-tabsintitlebar.js|" +
|
||||
"_update@chrome://browser/content/browser-tabsintitlebar.js|" +
|
||||
"updateAppearance@chrome://browser/content/browser-tabsintitlebar.js|" +
|
||||
"handleEvent@chrome://browser/content/tabbrowser.xml|");
|
||||
}
|
||||
|
||||
if (Services.appinfo.OS == "Darwin") {
|
||||
// _onOverflow causes a reflow getting widths.
|
||||
EXPECTED_REFLOWS.push("_onOverflow@resource:///modules/CustomizableUI.jsm|" +
|
||||
"init@resource:///modules/CustomizableUI.jsm|" +
|
||||
"observe@resource:///modules/CustomizableUI.jsm|" +
|
||||
"_delayedStartup@chrome://browser/content/browser.js|");
|
||||
// Same as above since in packaged builds there are no function names and the resource URI includes "app"
|
||||
EXPECTED_REFLOWS.push("@resource://app/modules/CustomizableUI.jsm|" +
|
||||
"@resource://app/modules/CustomizableUI.jsm|" +
|
||||
"@resource://app/modules/CustomizableUI.jsm|" +
|
||||
"_delayedStartup@chrome://browser/content/browser.js|");
|
||||
}
|
||||
|
||||
/*
|
||||
* This test ensures that there are no unexpected
|
||||
* uninterruptible reflows when opening new windows.
|
||||
*/
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
// Add a reflow observer and open a new window
|
||||
let win = OpenBrowserWindow();
|
||||
let docShell = win.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsIDocShell);
|
||||
docShell.addWeakReflowObserver(observer);
|
||||
|
||||
// Wait until the mozafterpaint event occurs.
|
||||
waitForMozAfterPaint(win, function paintListener() {
|
||||
// Remove reflow observer and clean up.
|
||||
docShell.removeWeakReflowObserver(observer);
|
||||
win.close();
|
||||
|
||||
finish();
|
||||
});
|
||||
}
|
||||
|
||||
var observer = {
|
||||
reflow(start, end) {
|
||||
// Gather information about the current code path.
|
||||
let stack = new Error().stack;
|
||||
let path = stack.split("\n").slice(1).map(line => {
|
||||
return line.replace(/:\d+:\d+$/, "");
|
||||
}).join("|");
|
||||
let pathWithLineNumbers = (new Error().stack).split("\n").slice(1).join("|");
|
||||
|
||||
// Stack trace is empty. Reflow was triggered by native code.
|
||||
if (path === "") {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if this is an expected reflow.
|
||||
for (let expectedStack of EXPECTED_REFLOWS) {
|
||||
if (path.startsWith(expectedStack) ||
|
||||
// Accept an empty function name for gBrowserInit._delayedStartup or TabsInTitlebar._update to workaround bug 906578.
|
||||
path.startsWith(expectedStack.replace(/(^|\|)(gBrowserInit\._delayedStartup|TabsInTitlebar\._update)@/, "$1@"))) {
|
||||
ok(true, "expected uninterruptible reflow '" + expectedStack + "'");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ok(false, "unexpected uninterruptible reflow '" + pathWithLineNumbers + "'");
|
||||
},
|
||||
|
||||
reflowInterruptible(start, end) {
|
||||
// We're not interested in interruptible reflows.
|
||||
},
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIReflowObserver,
|
||||
Ci.nsISupportsWeakReference])
|
||||
};
|
||||
|
||||
function waitForMozAfterPaint(win, callback) {
|
||||
let dwu = win.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils);
|
||||
let lastTransactionId = dwu.lastTransactionId;
|
||||
|
||||
win.addEventListener("MozAfterPaint", function onEnd(event) {
|
||||
if (event.target != win || event.transactionId <= lastTransactionId)
|
||||
return;
|
||||
win.removeEventListener("MozAfterPaint", onEnd);
|
||||
executeSoon(callback);
|
||||
});
|
||||
}
|
7
browser/base/content/test/performance/browser.ini
Normal file
7
browser/base/content/test/performance/browser.ini
Normal file
@ -0,0 +1,7 @@
|
||||
[DEFAULT]
|
||||
support-files =
|
||||
head.js
|
||||
[browser_tabclose_reflows.js]
|
||||
[browser_tabopen_reflows.js]
|
||||
[browser_toolbariconcolor_restyles.js]
|
||||
[browser_windowopen_reflows.js]
|
@ -0,0 +1,71 @@
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* WHOA THERE: We should never be adding new things to EXPECTED_REFLOWS. This
|
||||
* is a whitelist that should slowly go away as we improve the performance of
|
||||
* the front-end. Instead of adding more reflows to the whitelist, you should
|
||||
* be modifying your code to avoid the reflow.
|
||||
*
|
||||
* See https://developer.mozilla.org/en-US/Firefox/Performance_best_practices_for_Firefox_fe_engineers
|
||||
* for tips on how to do that.
|
||||
*/
|
||||
const EXPECTED_REFLOWS = [
|
||||
[
|
||||
"_adjustFocusAfterTabSwitch@chrome://browser/content/tabbrowser.xml",
|
||||
],
|
||||
];
|
||||
|
||||
if (gMultiProcessBrowser) {
|
||||
EXPECTED_REFLOWS.push(
|
||||
[
|
||||
"_adjustFocusAfterTabSwitch@chrome://browser/content/tabbrowser.xml",
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* This test ensures that there are no unexpected
|
||||
* uninterruptible reflows when closing new tabs.
|
||||
*/
|
||||
add_task(async function() {
|
||||
// If we've got a preloaded browser, get rid of it so that it
|
||||
// doesn't interfere with the test if it's loading. We have to
|
||||
// do this before we disable preloading or changing the new tab
|
||||
// URL, otherwise _getPreloadedBrowser will return null, despite
|
||||
// the preloaded browser existing.
|
||||
let preloaded = gBrowser._getPreloadedBrowser();
|
||||
if (preloaded) {
|
||||
preloaded.remove();
|
||||
}
|
||||
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["browser.newtab.preload", false]],
|
||||
});
|
||||
|
||||
let aboutNewTabService = Cc["@mozilla.org/browser/aboutnewtab-service;1"]
|
||||
.getService(Ci.nsIAboutNewTabService);
|
||||
aboutNewTabService.newTabURL = "about:blank";
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
aboutNewTabService.resetNewTabURL();
|
||||
});
|
||||
|
||||
// Because the tab strip is a scrollable frame, we can't use the
|
||||
// default dirtying function from withReflowObserver and reliably
|
||||
// get reflows for the strip. Instead, we provide a node that's
|
||||
// already in the scrollable frame to dirty - in this case, the
|
||||
// original tab.
|
||||
let origTab = gBrowser.selectedTab;
|
||||
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
|
||||
await BrowserTestUtils.waitForCondition(() => tab._fullyOpen);
|
||||
|
||||
// Add a reflow observer and open a new tab.
|
||||
await withReflowObserver(async function() {
|
||||
let switchDone = BrowserTestUtils.waitForEvent(window, "TabSwitchDone");
|
||||
gBrowser.removeTab(tab, { animate: true });
|
||||
await BrowserTestUtils.waitForEvent(tab, "transitionend",
|
||||
false, e => e.propertyName === "max-width");
|
||||
await switchDone;
|
||||
}, EXPECTED_REFLOWS, window, origTab);
|
||||
});
|
108
browser/base/content/test/performance/browser_tabopen_reflows.js
Normal file
108
browser/base/content/test/performance/browser_tabopen_reflows.js
Normal file
@ -0,0 +1,108 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* WHOA THERE: We should never be adding new things to EXPECTED_REFLOWS. This
|
||||
* is a whitelist that should slowly go away as we improve the performance of
|
||||
* the front-end. Instead of adding more reflows to the whitelist, you should
|
||||
* be modifying your code to avoid the reflow.
|
||||
*
|
||||
* See https://developer.mozilla.org/en-US/Firefox/Performance_best_practices_for_Firefox_fe_engineers
|
||||
* for tips on how to do that.
|
||||
*/
|
||||
const EXPECTED_REFLOWS = [
|
||||
// selection change notification may cause querying the focused editor content
|
||||
// by IME and that will cause reflow.
|
||||
[
|
||||
"select@chrome://global/content/bindings/textbox.xml",
|
||||
"focusAndSelectUrlBar@chrome://browser/content/browser.js",
|
||||
"openLinkIn@chrome://browser/content/utilityOverlay.js",
|
||||
"openUILinkIn@chrome://browser/content/utilityOverlay.js",
|
||||
"BrowserOpenTab@chrome://browser/content/browser.js",
|
||||
],
|
||||
|
||||
// selection change notification may cause querying the focused editor content
|
||||
// by IME and that will cause reflow.
|
||||
[
|
||||
"select@chrome://global/content/bindings/textbox.xml",
|
||||
"focusAndSelectUrlBar@chrome://browser/content/browser.js",
|
||||
"openLinkIn@chrome://browser/content/utilityOverlay.js",
|
||||
"openUILinkIn@chrome://browser/content/utilityOverlay.js",
|
||||
"BrowserOpenTab@chrome://browser/content/browser.js",
|
||||
],
|
||||
|
||||
[
|
||||
"select@chrome://global/content/bindings/textbox.xml",
|
||||
"focusAndSelectUrlBar@chrome://browser/content/browser.js",
|
||||
"openLinkIn@chrome://browser/content/utilityOverlay.js",
|
||||
"openUILinkIn@chrome://browser/content/utilityOverlay.js",
|
||||
"BrowserOpenTab@chrome://browser/content/browser.js",
|
||||
],
|
||||
|
||||
[
|
||||
"openLinkIn@chrome://browser/content/utilityOverlay.js",
|
||||
"openUILinkIn@chrome://browser/content/utilityOverlay.js",
|
||||
"BrowserOpenTab@chrome://browser/content/browser.js",
|
||||
],
|
||||
];
|
||||
|
||||
if (!gMultiProcessBrowser) {
|
||||
EXPECTED_REFLOWS.push(
|
||||
[
|
||||
"_adjustFocusAfterTabSwitch@chrome://browser/content/tabbrowser.xml",
|
||||
"updateCurrentBrowser@chrome://browser/content/tabbrowser.xml",
|
||||
"onselect@chrome://browser/content/browser.xul",
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* This test ensures that there are no unexpected
|
||||
* uninterruptible reflows when opening new tabs.
|
||||
*/
|
||||
add_task(async function() {
|
||||
// If we've got a preloaded browser, get rid of it so that it
|
||||
// doesn't interfere with the test if it's loading. We have to
|
||||
// do this before we disable preloading or changing the new tab
|
||||
// URL, otherwise _getPreloadedBrowser will return null, despite
|
||||
// the preloaded browser existing.
|
||||
let preloaded = gBrowser._getPreloadedBrowser();
|
||||
if (preloaded) {
|
||||
preloaded.remove();
|
||||
}
|
||||
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["browser.newtab.preload", false]],
|
||||
});
|
||||
|
||||
let aboutNewTabService = Cc["@mozilla.org/browser/aboutnewtab-service;1"]
|
||||
.getService(Ci.nsIAboutNewTabService);
|
||||
aboutNewTabService.newTabURL = "about:blank";
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
aboutNewTabService.resetNewTabURL();
|
||||
});
|
||||
|
||||
// Because the tab strip is a scrollable frame, we can't use the
|
||||
// default dirtying function from withReflowObserver and reliably
|
||||
// get reflows for the strip. Instead, we provide a node that's
|
||||
// already in the scrollable frame to dirty - in this case, the
|
||||
// original tab.
|
||||
let origTab = gBrowser.selectedTab;
|
||||
|
||||
// Add a reflow observer and open a new tab.
|
||||
await withReflowObserver(async function() {
|
||||
let switchDone = BrowserTestUtils.waitForEvent(window, "TabSwitchDone");
|
||||
BrowserOpenTab();
|
||||
await BrowserTestUtils.waitForEvent(gBrowser.selectedTab, "transitionend",
|
||||
false, e => e.propertyName === "max-width");
|
||||
await switchDone;
|
||||
}, EXPECTED_REFLOWS, window, origTab);
|
||||
|
||||
let switchDone = BrowserTestUtils.waitForEvent(window, "TabSwitchDone");
|
||||
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
await switchDone;
|
||||
});
|
||||
|
@ -0,0 +1,73 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* WHOA THERE: We should never be adding new things to EXPECTED_REFLOWS. This
|
||||
* is a whitelist that should slowly go away as we improve the performance of
|
||||
* the front-end. Instead of adding more reflows to the whitelist, you should
|
||||
* be modifying your code to avoid the reflow.
|
||||
*
|
||||
* See https://developer.mozilla.org/en-US/Firefox/Performance_best_practices_for_Firefox_fe_engineers
|
||||
* for tips on how to do that.
|
||||
*/
|
||||
const EXPECTED_REFLOWS = [
|
||||
// Selecting the address bar causes two reflows, unfortunately.
|
||||
[
|
||||
"select@chrome://global/content/bindings/textbox.xml",
|
||||
"focusAndSelectUrlBar@chrome://browser/content/browser.js",
|
||||
"_delayedStartup@chrome://browser/content/browser.js",
|
||||
],
|
||||
|
||||
// Selecting the address bar causes two reflows, unfortunately.
|
||||
[
|
||||
"select@chrome://global/content/bindings/textbox.xml",
|
||||
"focusAndSelectUrlBar@chrome://browser/content/browser.js",
|
||||
"_delayedStartup@chrome://browser/content/browser.js",
|
||||
],
|
||||
];
|
||||
|
||||
if (Services.appinfo.OS == "Darwin") {
|
||||
// TabsInTitlebar._update causes a reflow on OS X trying to do calculations
|
||||
// since layout info is already dirty. This doesn't seem to happen before
|
||||
// MozAfterPaint on Linux.
|
||||
EXPECTED_REFLOWS.push(
|
||||
[
|
||||
"rect@chrome://browser/content/browser-tabsintitlebar.js",
|
||||
"_update@chrome://browser/content/browser-tabsintitlebar.js",
|
||||
"updateAppearance@chrome://browser/content/browser-tabsintitlebar.js",
|
||||
"handleEvent@chrome://browser/content/tabbrowser.xml",
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
if (Services.appinfo.OS == "WINNT" || Services.appinfo.OS == "Darwin") {
|
||||
EXPECTED_REFLOWS.push(
|
||||
[
|
||||
"handleEvent@chrome://browser/content/tabbrowser.xml",
|
||||
"inferFromText@chrome://browser/content/browser.js",
|
||||
"handleEvent@chrome://browser/content/browser.js",
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* This test ensures that there are no unexpected
|
||||
* uninterruptible reflows when opening new windows.
|
||||
*/
|
||||
add_task(async function() {
|
||||
let win = OpenBrowserWindow();
|
||||
|
||||
await withReflowObserver(async function() {
|
||||
let resizeEvent = BrowserTestUtils.waitForEvent(win, "resize");
|
||||
let delayedStartup =
|
||||
TestUtils.topicObserved("browser-delayed-startup-finished",
|
||||
subject => subject == win);
|
||||
await resizeEvent;
|
||||
await delayedStartup;
|
||||
}, EXPECTED_REFLOWS, win);
|
||||
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
});
|
||||
|
155
browser/base/content/test/performance/head.js
Normal file
155
browser/base/content/test/performance/head.js
Normal file
@ -0,0 +1,155 @@
|
||||
/**
|
||||
* Async utility function for ensuring that no unexpected uninterruptible
|
||||
* reflows occur during some period of time in a window.
|
||||
*
|
||||
* The helper works by running a JS function before each event is
|
||||
* dispatched that attempts to dirty the layout tree - the idea being
|
||||
* that this puts us in the "worst case scenario" so that any JS
|
||||
* that attempts to query for layout or style information will cause
|
||||
* a reflow to fire. We also dirty the layout tree after each reflow
|
||||
* occurs, for good measure.
|
||||
*
|
||||
* This sounds good in theory, but it's trickier in practice due to
|
||||
* various optimizations in our Layout engine. The default function
|
||||
* for dirtying the layout tree adds a margin to the first element
|
||||
* child it finds in the window to a maximum of 3px, and then goes
|
||||
* back to 0px again and loops.
|
||||
*
|
||||
* This is not sufficient for reflows that we expect to happen within
|
||||
* scrollable frames, as Gecko is able to side-step reflowing the
|
||||
* contents of a scrollable frame if outer frames are dirtied. Because
|
||||
* of this, it's currently possible to override the default node to
|
||||
* dirty with one more appropriate for the test.
|
||||
*
|
||||
* It is also theoretically possible for enough events to fire between
|
||||
* reflows such that the before and after state of the layout tree is
|
||||
* exactly the same, meaning that no reflow is required, which opens
|
||||
* us up to missing expected reflows. This seems to be possible in
|
||||
* theory, but hasn't yet shown up in practice - it's just something
|
||||
* to be aware of.
|
||||
*
|
||||
* Bug 1363361 has been filed for a more reliable way of dirtying layout.
|
||||
*
|
||||
* @param testFn (async function)
|
||||
* The async function that will exercise the browser activity that is
|
||||
* being tested for reflows.
|
||||
* @param expectedStacks (Array, optional)
|
||||
* An Array of Arrays representing stacks.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* [
|
||||
* // This reflow is caused by lorem ipsum
|
||||
* [
|
||||
* "select@chrome://global/content/bindings/textbox.xml",
|
||||
* "focusAndSelectUrlBar@chrome://browser/content/browser.js",
|
||||
* "openLinkIn@chrome://browser/content/utilityOverlay.js",
|
||||
* "openUILinkIn@chrome://browser/content/utilityOverlay.js",
|
||||
* "BrowserOpenTab@chrome://browser/content/browser.js",
|
||||
* ],
|
||||
*
|
||||
* // This reflow is caused by lorem ipsum
|
||||
* [
|
||||
* "get_scrollPosition@chrome://global/content/bindings/scrollbox.xml",
|
||||
* "_fillTrailingGap@chrome://browser/content/tabbrowser.xml",
|
||||
* "_handleNewTab@chrome://browser/content/tabbrowser.xml",
|
||||
* "onxbltransitionend@chrome://browser/content/tabbrowser.xml",
|
||||
* ],
|
||||
*
|
||||
* ]
|
||||
*
|
||||
* Note that line numbers are not included in the stacks.
|
||||
*
|
||||
* Order of the reflows doesn't matter. Expected reflows that aren't seen
|
||||
* will cause an assertion failure. When this argument is not passed,
|
||||
* it defaults to the empty Array, meaning no reflows are expected.
|
||||
* @param window (browser window, optional)
|
||||
* The browser window to monitor. Defaults to the current window.
|
||||
* @param elemToDirty (DOM node, optional)
|
||||
* Callers can provide a custom DOM node to change some layout style
|
||||
* on in the event that the action being tested is occurring within
|
||||
* a scrollable frame. Otherwise, withReflowObserver defaults to dirtying
|
||||
* the first element child of the window.
|
||||
*/
|
||||
async function withReflowObserver(testFn, expectedStacks = [], win = window, elemToDirty) {
|
||||
if (!elemToDirty) {
|
||||
elemToDirty = win.document.firstElementChild;
|
||||
}
|
||||
|
||||
let i = 0;
|
||||
let dirtyFrameFn = (e) => {
|
||||
elemToDirty.style.margin = (++i % 4) + "px";
|
||||
};
|
||||
|
||||
let els = Cc["@mozilla.org/eventlistenerservice;1"]
|
||||
.getService(Ci.nsIEventListenerService);
|
||||
|
||||
// We're going to remove the stacks one by one as we see them so that
|
||||
// we can check for expected, unseen reflows, so let's clone the array.
|
||||
expectedStacks = expectedStacks.slice(0);
|
||||
|
||||
let observer = {
|
||||
reflow(start, end) {
|
||||
// Gather information about the current code path, slicing out the current
|
||||
// frame.
|
||||
let path = (new Error().stack).split("\n").slice(1).map(line => {
|
||||
return line.replace(/:\d+:\d+$/, "");
|
||||
}).join("|");
|
||||
|
||||
let pathWithLineNumbers = (new Error().stack).split("\n").slice(1);
|
||||
|
||||
// Just in case, dirty the frame now that we've reflowed.
|
||||
dirtyFrameFn();
|
||||
|
||||
// Stack trace is empty. Reflow was triggered by native code, which
|
||||
// we ignore.
|
||||
if (path === "") {
|
||||
return;
|
||||
}
|
||||
|
||||
let index = expectedStacks.findIndex(stack => path.startsWith(stack.join("|")));
|
||||
|
||||
if (index != -1) {
|
||||
Assert.ok(true, "expected uninterruptible reflow: '" +
|
||||
JSON.stringify(pathWithLineNumbers, null, "\t") + "'");
|
||||
expectedStacks.splice(index, 1);
|
||||
} else {
|
||||
Assert.ok(false, "unexpected uninterruptible reflow \n" +
|
||||
JSON.stringify(pathWithLineNumbers, null, "\t") + "\n");
|
||||
}
|
||||
},
|
||||
|
||||
reflowInterruptible(start, end) {
|
||||
// We're not interested in interruptible reflows.
|
||||
},
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIReflowObserver,
|
||||
Ci.nsISupportsWeakReference])
|
||||
};
|
||||
|
||||
let docShell = win.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsIDocShell);
|
||||
docShell.addWeakReflowObserver(observer);
|
||||
|
||||
els.addListenerForAllEvents(win, dirtyFrameFn, true);
|
||||
|
||||
try {
|
||||
dirtyFrameFn();
|
||||
await testFn();
|
||||
} finally {
|
||||
for (let remainder of expectedStacks) {
|
||||
Assert.ok(false,
|
||||
`Unused expected reflow: ${JSON.stringify(remainder, null, "\t")}.\n` +
|
||||
"This is probably a good thing - just remove it from the " +
|
||||
"expected list.");
|
||||
}
|
||||
|
||||
|
||||
els.removeListenerForAllEvents(win, dirtyFrameFn, true);
|
||||
docShell.removeWeakReflowObserver(observer);
|
||||
|
||||
elemToDirty.style.margin = "";
|
||||
}
|
||||
}
|
||||
|
@ -1,2 +0,0 @@
|
||||
[DEFAULT]
|
||||
[browser_toolbariconcolor_restyles.js]
|
@ -129,10 +129,6 @@ browser.jar:
|
||||
content/browser/pageinfo/permissions.js (content/pageinfo/permissions.js)
|
||||
content/browser/pageinfo/security.js (content/pageinfo/security.js)
|
||||
content/browser/robot.ico (content/robot.ico)
|
||||
content/browser/sync/aboutSyncTabs.xul (content/sync/aboutSyncTabs.xul)
|
||||
content/browser/sync/aboutSyncTabs.js (content/sync/aboutSyncTabs.js)
|
||||
content/browser/sync/aboutSyncTabs.css (content/sync/aboutSyncTabs.css)
|
||||
content/browser/sync/aboutSyncTabs-bindings.xml (content/sync/aboutSyncTabs-bindings.xml)
|
||||
content/browser/safeMode.css (content/safeMode.css)
|
||||
content/browser/safeMode.js (content/safeMode.js)
|
||||
content/browser/safeMode.xul (content/safeMode.xul)
|
||||
|
@ -22,6 +22,7 @@ BROWSER_CHROME_MANIFESTS += [
|
||||
'content/test/general/browser.ini',
|
||||
'content/test/newtab/browser.ini',
|
||||
'content/test/pageinfo/browser.ini',
|
||||
'content/test/performance/browser.ini',
|
||||
'content/test/permissions/browser.ini',
|
||||
'content/test/plugins/browser.ini',
|
||||
'content/test/popupNotifications/browser.ini',
|
||||
@ -38,7 +39,6 @@ BROWSER_CHROME_MANIFESTS += [
|
||||
'content/test/urlbar/browser.ini',
|
||||
'content/test/webextensions/browser.ini',
|
||||
'content/test/webrtc/browser.ini',
|
||||
'content/test/windows/browser.ini',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_UPDATER']:
|
||||
|
@ -80,8 +80,6 @@ static const RedirEntry kRedirMap[] = {
|
||||
nsIAboutModule::ALLOW_SCRIPT },
|
||||
{ "welcomeback", "chrome://browser/content/aboutWelcomeBack.xhtml",
|
||||
nsIAboutModule::ALLOW_SCRIPT },
|
||||
{ "sync-tabs", "chrome://browser/content/sync/aboutSyncTabs.xul",
|
||||
nsIAboutModule::ALLOW_SCRIPT },
|
||||
// Linkable because of indexeddb use (bug 1228118)
|
||||
{ "home", "chrome://browser/content/abouthome/aboutHome.xhtml",
|
||||
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
|
||||
|
@ -97,7 +97,6 @@ static const mozilla::Module::ContractIDEntry kBrowserContracts[] = {
|
||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "searchreset", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
|
||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "sessionrestore", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
|
||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "welcomeback", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
|
||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "sync-tabs", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
|
||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "home", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
|
||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "newtab", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
|
||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "preferences", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
|
||||
|
@ -103,7 +103,7 @@ add_task(async function test() {
|
||||
let access = await content.navigator.requestMediaKeySystemAccess("org.w3.clearkey",
|
||||
[{
|
||||
initDataTypes: [aKeyInfo.initDataType],
|
||||
videoCapabilities: [{contentType: "video/webm"}],
|
||||
videoCapabilities: [{contentType: 'video/webm; codecs="vp9"'}],
|
||||
sessionTypes: ["persistent-license"],
|
||||
persistentState: "required",
|
||||
}]);
|
||||
@ -156,7 +156,7 @@ add_task(async function test() {
|
||||
let access = await content.navigator.requestMediaKeySystemAccess("org.w3.clearkey",
|
||||
[{
|
||||
initDataTypes: [aKeyInfo.initDataType],
|
||||
videoCapabilities: [{contentType: "video/webm"}],
|
||||
videoCapabilities: [{contentType: 'video/webm; codecs="vp9"'}],
|
||||
sessionTypes: ["persistent-license"],
|
||||
persistentState: "required",
|
||||
}]);
|
||||
|
@ -98,7 +98,7 @@ async function setupEMEKey(browser) {
|
||||
let access = await content.navigator.requestMediaKeySystemAccess("org.w3.clearkey",
|
||||
[{
|
||||
initDataTypes: [aKeyInfo.initDataType],
|
||||
videoCapabilities: [{contentType: "video/webm"}],
|
||||
videoCapabilities: [{contentType: 'video/webm; codecs="vp9"'}],
|
||||
sessionTypes: ["persistent-license"],
|
||||
persistentState: "required",
|
||||
}]);
|
||||
@ -153,7 +153,7 @@ async function checkEMEKey(browser, emeSessionId) {
|
||||
let access = await content.navigator.requestMediaKeySystemAccess("org.w3.clearkey",
|
||||
[{
|
||||
initDataTypes: [aKeyInfo.initDataType],
|
||||
videoCapabilities: [{contentType: "video/webm"}],
|
||||
videoCapabilities: [{contentType: 'video/webm; codecs="vp9"'}],
|
||||
sessionTypes: ["persistent-license"],
|
||||
persistentState: "required",
|
||||
}]);
|
||||
|
@ -147,6 +147,13 @@ var gMenuBuilder = {
|
||||
let menuPopup = element.firstChild;
|
||||
if (menuPopup && menuPopup.childNodes.length == 1) {
|
||||
let onlyChild = menuPopup.firstChild;
|
||||
|
||||
// Keep single checkbox items in the submenu on Linux since
|
||||
// the extension icon overlaps the checkbox otherwise.
|
||||
if (AppConstants.platform === "linux" && onlyChild.getAttribute("type") === "checkbox") {
|
||||
return element;
|
||||
}
|
||||
|
||||
onlyChild.remove();
|
||||
return onlyChild;
|
||||
}
|
||||
|
@ -24,26 +24,54 @@ add_task(async function() {
|
||||
type: "checkbox",
|
||||
});
|
||||
|
||||
browser.contextMenus.create({
|
||||
type: "separator",
|
||||
});
|
||||
browser.test.sendMessage("single-contextmenu-item-added");
|
||||
|
||||
browser.contextMenus.create({
|
||||
title: "Checkbox",
|
||||
type: "checkbox",
|
||||
checked: true,
|
||||
});
|
||||
browser.test.onMessage.addListener(msg => {
|
||||
if (msg !== "add-additional-menu-items") {
|
||||
return;
|
||||
}
|
||||
|
||||
browser.contextMenus.create({
|
||||
title: "Checkbox",
|
||||
type: "checkbox",
|
||||
});
|
||||
browser.contextMenus.create({
|
||||
type: "separator",
|
||||
});
|
||||
|
||||
browser.test.notifyPass("contextmenus-checkboxes");
|
||||
browser.contextMenus.create({
|
||||
title: "Checkbox",
|
||||
type: "checkbox",
|
||||
checked: true,
|
||||
});
|
||||
|
||||
browser.contextMenus.create({
|
||||
title: "Checkbox",
|
||||
type: "checkbox",
|
||||
});
|
||||
|
||||
browser.test.notifyPass("contextmenus-checkboxes");
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
await extension.startup();
|
||||
|
||||
await extension.awaitMessage("single-contextmenu-item-added");
|
||||
|
||||
async function testSingleCheckboxItem() {
|
||||
let extensionMenuRoot = await openExtensionContextMenu();
|
||||
|
||||
// On Linux, the single menu item should be contained in a submenu.
|
||||
if (AppConstants.platform === "linux") {
|
||||
let items = extensionMenuRoot.getElementsByAttribute("type", "checkbox");
|
||||
is(items.length, 1, "single checkbox should be in the submenu on Linux");
|
||||
await closeContextMenu();
|
||||
} else {
|
||||
is(extensionMenuRoot, null, "there should be no submenu for a single checkbox item");
|
||||
await closeContextMenu();
|
||||
}
|
||||
}
|
||||
|
||||
await testSingleCheckboxItem();
|
||||
|
||||
extension.sendMessage("add-additional-menu-items");
|
||||
await extension.awaitFinish("contextmenus-checkboxes");
|
||||
|
||||
function confirmCheckboxStates(extensionMenuRoot, expectedStates) {
|
||||
|
@ -14,17 +14,12 @@ function genericChecker() {
|
||||
|
||||
browser.test.onMessage.addListener((msg, ...args) => {
|
||||
if (msg == kind + "-check-views") {
|
||||
let windowId = args[0];
|
||||
let counts = {
|
||||
"background": 0,
|
||||
"tab": 0,
|
||||
"popup": 0,
|
||||
"kind": 0,
|
||||
"window": 0,
|
||||
background: 0,
|
||||
tab: 0,
|
||||
popup: 0,
|
||||
kind: 0,
|
||||
};
|
||||
if (Number.isInteger(windowId)) {
|
||||
counts.window = browser.extension.getViews({windowId: windowId}).length;
|
||||
}
|
||||
if (kind !== "background") {
|
||||
counts.kind = browser.extension.getViews({type: kind}).length;
|
||||
}
|
||||
@ -48,8 +43,13 @@ function genericChecker() {
|
||||
} else {
|
||||
browser.test.sendMessage("counts", counts);
|
||||
}
|
||||
} else if (msg == kind + "-getViews-with-filter") {
|
||||
let filter = args[0];
|
||||
let count = browser.extension.getViews(filter).length;
|
||||
browser.test.sendMessage("getViews-count", count);
|
||||
} else if (msg == kind + "-open-tab") {
|
||||
browser.tabs.create({windowId: args[0], url: browser.runtime.getURL("tab.html")});
|
||||
browser.tabs.create({windowId: args[0], url: browser.runtime.getURL("tab.html")})
|
||||
.then((tab) => browser.test.sendMessage("opened-tab", tab.id));
|
||||
} else if (msg == kind + "-close-tab") {
|
||||
browser.tabs.query({
|
||||
windowId: args[0],
|
||||
@ -112,28 +112,40 @@ add_task(async function() {
|
||||
async function openTab(winId) {
|
||||
extension.sendMessage("background-open-tab", winId);
|
||||
await extension.awaitMessage("tab-ready");
|
||||
return extension.awaitMessage("opened-tab");
|
||||
}
|
||||
|
||||
async function checkViews(kind, tabCount, popupCount, kindCount, windowId = undefined, windowCount = 0) {
|
||||
extension.sendMessage(kind + "-check-views", windowId);
|
||||
async function checkViews(kind, tabCount, popupCount, kindCount) {
|
||||
extension.sendMessage(kind + "-check-views");
|
||||
let counts = await extension.awaitMessage("counts");
|
||||
is(counts.background, 1, "background count correct");
|
||||
is(counts.tab, tabCount, "tab count correct");
|
||||
is(counts.popup, popupCount, "popup count correct");
|
||||
is(counts.kind, kindCount, "count for type correct");
|
||||
is(counts.window, windowCount, "count for window correct");
|
||||
}
|
||||
|
||||
async function checkViewsWithFilter(filter, expectedCount) {
|
||||
extension.sendMessage("background-getViews-with-filter", filter);
|
||||
let count = await extension.awaitMessage("getViews-count");
|
||||
is(count, expectedCount, `count for ${JSON.stringify(filter)} correct`);
|
||||
}
|
||||
|
||||
await checkViews("background", 0, 0, 0);
|
||||
await checkViewsWithFilter({windowId: -1}, 1);
|
||||
await checkViewsWithFilter({tabId: -1}, 1);
|
||||
|
||||
await openTab(winId1);
|
||||
let tabId1 = await openTab(winId1);
|
||||
|
||||
await checkViews("background", 1, 0, 0, winId1, 1);
|
||||
await checkViews("background", 1, 0, 0);
|
||||
await checkViews("tab", 1, 0, 1);
|
||||
await checkViewsWithFilter({windowId: winId1}, 1);
|
||||
await checkViewsWithFilter({tabId: tabId1}, 1);
|
||||
|
||||
await openTab(winId2);
|
||||
let tabId2 = await openTab(winId2);
|
||||
|
||||
await checkViews("background", 2, 0, 0, winId2, 1);
|
||||
await checkViews("background", 2, 0, 0);
|
||||
await checkViewsWithFilter({windowId: winId2}, 1);
|
||||
await checkViewsWithFilter({tabId: tabId2}, 1);
|
||||
|
||||
async function triggerPopup(win, callback) {
|
||||
await clickBrowserAction(extension, win);
|
||||
@ -153,18 +165,24 @@ add_task(async function() {
|
||||
await new Promise(resolve => win1.setTimeout(resolve, 10));
|
||||
|
||||
await triggerPopup(win1, async function() {
|
||||
await checkViews("background", 2, 1, 0, winId1, 2);
|
||||
await checkViews("background", 2, 1, 0);
|
||||
await checkViews("popup", 2, 1, 1);
|
||||
await checkViewsWithFilter({windowId: winId1}, 2);
|
||||
await checkViewsWithFilter({type: "popup", tabId: -1}, 1);
|
||||
});
|
||||
|
||||
await triggerPopup(win2, async function() {
|
||||
await checkViews("background", 2, 1, 0, winId2, 2);
|
||||
await checkViews("background", 2, 1, 0);
|
||||
await checkViews("popup", 2, 1, 1);
|
||||
await checkViewsWithFilter({windowId: winId2}, 2);
|
||||
await checkViewsWithFilter({type: "popup", tabId: -1}, 1);
|
||||
});
|
||||
|
||||
info("checking counts after popups");
|
||||
|
||||
await checkViews("background", 2, 0, 0, winId1, 1);
|
||||
await checkViews("background", 2, 0, 0);
|
||||
await checkViewsWithFilter({windowId: winId1}, 1);
|
||||
await checkViewsWithFilter({tabId: -1}, 1);
|
||||
|
||||
info("closing one tab");
|
||||
|
||||
|
@ -170,35 +170,22 @@ class TestFirefoxRefresh(MarionetteTestCase):
|
||||
self.assertEqual(titleInBookmarks, self._bookmarkText)
|
||||
|
||||
def checkHistory(self):
|
||||
historyResults = self.runAsyncCode("""
|
||||
let placeInfos = [];
|
||||
PlacesUtils.asyncHistory.getPlacesInfo(makeURI(arguments[0]), {
|
||||
handleError(resultCode, place) {
|
||||
placeInfos = null;
|
||||
marionetteScriptFinished("Unexpected error in fetching visit: " + resultCode);
|
||||
},
|
||||
handleResult(placeInfo) {
|
||||
placeInfos.push(placeInfo);
|
||||
},
|
||||
handleCompletion() {
|
||||
if (placeInfos) {
|
||||
if (!placeInfos.length) {
|
||||
marionetteScriptFinished("No visits found");
|
||||
} else {
|
||||
marionetteScriptFinished(placeInfos);
|
||||
}
|
||||
}
|
||||
},
|
||||
historyResult = self.runAsyncCode("""
|
||||
PlacesUtils.history.fetch(arguments[0]).then(pageInfo => {
|
||||
if (!pageInfo) {
|
||||
marionetteScriptFinished("No visits found");
|
||||
} else {
|
||||
marionetteScriptFinished(pageInfo);
|
||||
}
|
||||
}).catch(e => {
|
||||
marionetteScriptFinished("Unexpected error in fetching page: " + e);
|
||||
});
|
||||
""", script_args=[self._historyURL])
|
||||
if type(historyResults) == str:
|
||||
self.fail(historyResults)
|
||||
if type(historyResult) == str:
|
||||
self.fail(historyResult)
|
||||
return
|
||||
|
||||
historyCount = len(historyResults)
|
||||
self.assertEqual(historyCount, 1, "Should have exactly 1 entry for URI, got %d" % historyCount)
|
||||
if historyCount == 1:
|
||||
self.assertEqual(historyResults[0]['title'], self._historyTitle)
|
||||
self.assertEqual(historyResult['title'], self._historyTitle)
|
||||
|
||||
def checkFormHistory(self):
|
||||
formFieldResults = self.runAsyncCode("""
|
||||
|
@ -660,7 +660,7 @@ var BookmarkPropertiesPanel = {
|
||||
} else if (this._itemType == BOOKMARK_FOLDER) {
|
||||
itemGuid = await PlacesTransactions.NewFolder(info).transact();
|
||||
for (let uri of this._URIs) {
|
||||
let placeInfo = await PlacesUtils.promisePlaceInfo(uri);
|
||||
let placeInfo = await PlacesUtils.history.fetch(uri);
|
||||
let title = placeInfo ? placeInfo.title : "";
|
||||
await PlacesTransactions.transact({ parentGuid: itemGuid, uri, title });
|
||||
}
|
||||
|
@ -1,20 +0,0 @@
|
||||
<!-- 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/. -->
|
||||
|
||||
<!ENTITY tabs.otherDevices.label "Tabs From Other Devices">
|
||||
|
||||
<!ENTITY tabs.searchText.label "Type here to find tabs…">
|
||||
|
||||
<!-- LOCALIZATION NOTE (tabs.context.openTab.accesskey, tabs.context.openMultipleTabs.accesskey):
|
||||
Only one of these will show at a time (based on selection), so reusing accesskey is ok. -->
|
||||
<!ENTITY tabs.context.openTab.label "Open This Tab">
|
||||
<!ENTITY tabs.context.openTab.accesskey "O">
|
||||
<!ENTITY tabs.context.openMultipleTabs.label "Open Selected Tabs">
|
||||
<!ENTITY tabs.context.openMultipleTabs.accesskey "O">
|
||||
<!ENTITY tabs.context.bookmarkSingleTab.label "Bookmark This Tab…">
|
||||
<!ENTITY tabs.context.bookmarkSingleTab.accesskey "B">
|
||||
<!ENTITY tabs.context.bookmarkMultipleTabs.label "Bookmark Selected Tabs…">
|
||||
<!ENTITY tabs.context.bookmarkMultipleTabs.accesskey "B">
|
||||
<!ENTITY tabs.context.refreshList.label "Refresh List">
|
||||
<!ENTITY tabs.context.refreshList.accesskey "R">
|
@ -20,7 +20,6 @@
|
||||
locale/browser/aboutSearchReset.dtd (%chrome/browser/aboutSearchReset.dtd)
|
||||
locale/browser/aboutSessionRestore.dtd (%chrome/browser/aboutSessionRestore.dtd)
|
||||
locale/browser/aboutTabCrashed.dtd (%chrome/browser/aboutTabCrashed.dtd)
|
||||
locale/browser/aboutSyncTabs.dtd (%chrome/browser/aboutSyncTabs.dtd)
|
||||
locale/browser/browser.dtd (%chrome/browser/browser.dtd)
|
||||
locale/browser/baseMenuOverlay.dtd (%chrome/browser/baseMenuOverlay.dtd)
|
||||
locale/browser/browser.properties (%chrome/browser/browser.properties)
|
||||
|
@ -1,105 +0,0 @@
|
||||
/* 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/. */
|
||||
|
||||
#tabs-display,
|
||||
#tabsList {
|
||||
background-color: transparent;
|
||||
-moz-appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#tabsList {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#tabs-display {
|
||||
background: #fff url(chrome://browser/skin/sync-bg.png) repeat-x center -80px;
|
||||
}
|
||||
|
||||
#headers {
|
||||
background: url(chrome://browser/skin/sync-32.png) no-repeat;
|
||||
margin-top: 4px;
|
||||
width: 45em;
|
||||
height: 32px;
|
||||
margin-inline-start: 2em;
|
||||
margin-inline-end: 2em;
|
||||
}
|
||||
|
||||
#headers:-moz-locale-dir(rtl) {
|
||||
background-position-x: 100%;
|
||||
}
|
||||
|
||||
#tabsListHeading {
|
||||
font-size: 140%;
|
||||
font-weight: bold;
|
||||
margin-inline-start: 40px;
|
||||
}
|
||||
|
||||
richlistitem {
|
||||
margin-inline-end: 2em;
|
||||
}
|
||||
|
||||
richlistitem[selected="true"],
|
||||
richlistitem:focus {
|
||||
outline-style: none;
|
||||
}
|
||||
|
||||
richlistitem[type="tab"] {
|
||||
min-height: 3em;
|
||||
border: #999999 1px solid !important;
|
||||
padding: 2px 5px;
|
||||
margin-bottom: 4px;
|
||||
margin-inline-start: 4em;
|
||||
border-radius: 6px;
|
||||
background-color: menu;
|
||||
width: 44em;
|
||||
opacity: 0.9;
|
||||
box-shadow:
|
||||
inset rgba(255, 255, 255, 0.5) 0 1px 0px,
|
||||
inset rgba(0, 0, 0, 0.1) 0 -2px 0px,
|
||||
rgba(0, 0, 0, 0.1) 0px 1px 0px;
|
||||
}
|
||||
|
||||
richlistitem[type="tab"][selected="true"] {
|
||||
background-color: -moz-MenuHover;
|
||||
}
|
||||
|
||||
richlistitem[type="client"] {
|
||||
min-height: 2em;
|
||||
color: #000000;
|
||||
margin-inline-start: 2em;
|
||||
margin-top: 2px;
|
||||
margin-bottom: 3px;
|
||||
width: 42em;
|
||||
border-radius: 6px;
|
||||
background-color: transparent;
|
||||
-moz-user-focus: ignore !important;
|
||||
}
|
||||
richlistitem.mobile[type="client"] {
|
||||
list-style-image: url("chrome://browser/skin/sync-mobileIcon.svg#icon");
|
||||
}
|
||||
richlistitem.desktop[type="client"] {
|
||||
list-style-image: url("chrome://browser/skin/sync-desktopIcon.svg#icon");
|
||||
}
|
||||
|
||||
.title,
|
||||
.clientName {
|
||||
color: #000000;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
.title[selected="true"],
|
||||
.url[selected="true"] {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.url {
|
||||
color: -moz-nativehyperlinktext;
|
||||
font-size: 0.95em;
|
||||
}
|
||||
|
||||
.tabIcon {
|
||||
padding-inline-start: 2px;
|
||||
padding-top: 2px;
|
||||
}
|
@ -8,7 +8,6 @@ browser.jar:
|
||||
#include ../shared/jar.inc.mn
|
||||
skin/classic/browser/sanitizeDialog.css
|
||||
skin/classic/browser/aboutSessionRestore-window-icon.png
|
||||
skin/classic/browser/aboutSyncTabs.css
|
||||
* skin/classic/browser/syncedtabs/sidebar.css (syncedtabs/sidebar.css)
|
||||
* skin/classic/browser/browser.css
|
||||
* skin/classic/browser/compacttheme.css
|
||||
@ -99,9 +98,6 @@ browser.jar:
|
||||
skin/classic/browser/tabbrowser/tab-stroke-start@2x.png (tabbrowser/tab-stroke-start@2x.png)
|
||||
skin/classic/browser/tabbrowser/tabDragIndicator.png (tabbrowser/tabDragIndicator.png)
|
||||
|
||||
skin/classic/browser/sync-16.png
|
||||
skin/classic/browser/sync-32.png
|
||||
skin/classic/browser/sync-bg.png
|
||||
skin/classic/browser/sync-desktopIcon.svg (../shared/sync-desktopIcon.svg)
|
||||
skin/classic/browser/sync-horizontalbar.png
|
||||
skin/classic/browser/sync-horizontalbar@2x.png
|
||||
|
@ -1,105 +0,0 @@
|
||||
/* 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/. */
|
||||
|
||||
#tabs-display,
|
||||
#tabsList {
|
||||
background-color: transparent;
|
||||
-moz-appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#tabsList {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#tabs-display {
|
||||
background: #fff url(chrome://browser/skin/sync-bg.png) repeat-x center -80px;
|
||||
}
|
||||
|
||||
#headers {
|
||||
background: url(chrome://browser/skin/sync-32.png) no-repeat;
|
||||
margin-top: 4px;
|
||||
width: 45em;
|
||||
height: 32px;
|
||||
margin-inline-start: 2em;
|
||||
margin-inline-end: 2em;
|
||||
}
|
||||
|
||||
#headers:-moz-locale-dir(rtl) {
|
||||
background-position-x: 100%;
|
||||
}
|
||||
|
||||
#tabsListHeading {
|
||||
font-size: 140%;
|
||||
font-weight: bold;
|
||||
margin-inline-start: 40px;
|
||||
}
|
||||
|
||||
richlistitem {
|
||||
margin-inline-end: 2em;
|
||||
}
|
||||
|
||||
richlistitem[selected="true"],
|
||||
richlistitem:focus {
|
||||
outline-style: none;
|
||||
}
|
||||
|
||||
richlistitem[type="tab"] {
|
||||
min-height: 3em;
|
||||
border: #999999 1px solid !important;
|
||||
padding: 2px 5px;
|
||||
margin-bottom: 4px;
|
||||
margin-inline-start: 4em;
|
||||
border-radius: 6px;
|
||||
background-color: menu;
|
||||
width: 44em;
|
||||
opacity: 0.9;
|
||||
box-shadow:
|
||||
inset rgba(255, 255, 255, 0.5) 0 1px 0px,
|
||||
inset rgba(0, 0, 0, 0.1) 0 -2px 0px,
|
||||
rgba(0, 0, 0, 0.1) 0px 1px 0px;
|
||||
}
|
||||
|
||||
richlistitem[type="tab"][selected="true"] {
|
||||
background-color: -moz-MenuHover;
|
||||
}
|
||||
|
||||
richlistitem[type="client"] {
|
||||
min-height: 2em;
|
||||
color: #000000;
|
||||
margin-inline-start: 2em;
|
||||
margin-top: 2px;
|
||||
margin-bottom: 3px;
|
||||
width: 42em;
|
||||
border-radius: 6px;
|
||||
background-color: transparent;
|
||||
-moz-user-focus: ignore !important;
|
||||
}
|
||||
richlistitem.mobile[type="client"] {
|
||||
list-style-image: url("chrome://browser/skin/sync-mobileIcon.svg#icon");
|
||||
}
|
||||
richlistitem.desktop[type="client"] {
|
||||
list-style-image: url("chrome://browser/skin/sync-desktopIcon.svg#icon");
|
||||
}
|
||||
|
||||
.title,
|
||||
.clientName {
|
||||
color: #000000;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
.title[selected="true"],
|
||||
.url[selected="true"] {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.url {
|
||||
color: -moz-nativehyperlinktext;
|
||||
font-size: 0.95em;
|
||||
}
|
||||
|
||||
.tabIcon {
|
||||
padding-inline-start: 2px;
|
||||
padding-top: 2px;
|
||||
}
|
@ -7,7 +7,6 @@ browser.jar:
|
||||
#include ../shared/jar.inc.mn
|
||||
skin/classic/browser/sanitizeDialog.css
|
||||
skin/classic/browser/aboutSessionRestore-window-icon.png
|
||||
skin/classic/browser/aboutSyncTabs.css
|
||||
* skin/classic/browser/syncedtabs/sidebar.css (syncedtabs/sidebar.css)
|
||||
* skin/classic/browser/browser.css
|
||||
* skin/classic/browser/compacttheme.css
|
||||
@ -146,9 +145,6 @@ browser.jar:
|
||||
skin/classic/browser/tabbrowser/tab-stroke-start@2x.png (tabbrowser/tab-stroke-start@2x.png)
|
||||
skin/classic/browser/tabbrowser/tabDragIndicator.png (tabbrowser/tabDragIndicator.png)
|
||||
skin/classic/browser/tabbrowser/tabDragIndicator@2x.png (tabbrowser/tabDragIndicator@2x.png)
|
||||
skin/classic/browser/sync-16.png
|
||||
skin/classic/browser/sync-32.png
|
||||
skin/classic/browser/sync-bg.png
|
||||
skin/classic/browser/sync-desktopIcon.svg (../shared/sync-desktopIcon.svg)
|
||||
skin/classic/browser/sync-horizontalbar.png
|
||||
skin/classic/browser/sync-horizontalbar@2x.png
|
||||
|
@ -170,6 +170,7 @@
|
||||
transition: none;
|
||||
}
|
||||
|
||||
#urlbar[pageproxystate="invalid"] > #identity-box > #extension-icon,
|
||||
#urlbar[pageproxystate="invalid"] > #identity-box > #tracking-protection-icon {
|
||||
visibility: collapse;
|
||||
}
|
||||
|
@ -13,12 +13,18 @@ toolbar[brighttext] :-moz-any(@primaryToolbarButtons@) {
|
||||
fill: var(--toolbarbutton-icon-fill-inverted);
|
||||
}
|
||||
|
||||
#back-button {
|
||||
list-style-image: url("chrome://browser/skin/back-large.svg");
|
||||
#back-button:-moz-locale-dir(rtl) > .toolbarbutton-icon,
|
||||
%ifdef MOZ_PHOTON_THEME
|
||||
#forward-button:-moz-locale-dir(rtl) > .toolbarbutton-icon,
|
||||
#reload-button:-moz-locale-dir(rtl) > .toolbarbutton-icon,
|
||||
%endif
|
||||
#nav-bar-overflow-button:-moz-locale-dir(rtl) > .toolbarbutton-icon,
|
||||
#panic-button:-moz-locale-dir(rtl) > .toolbarbutton-icon {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
#back-button:-moz-locale-dir(rtl) > .toolbarbutton-icon {
|
||||
transform: scaleX(-1);
|
||||
#back-button {
|
||||
list-style-image: url("chrome://browser/skin/back-large.svg");
|
||||
}
|
||||
|
||||
#forward-button {
|
||||
@ -26,10 +32,6 @@ toolbar[brighttext] :-moz-any(@primaryToolbarButtons@) {
|
||||
}
|
||||
|
||||
%ifdef MOZ_PHOTON_THEME
|
||||
#forward-button:-moz-locale-dir(rtl) > .toolbarbutton-icon {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
#reload-button {
|
||||
list-style-image: url("chrome://browser/skin/reload.svg");
|
||||
}
|
||||
@ -171,10 +173,6 @@ toolbar:not([brighttext]) #bookmarks-menu-button[cui-areatype="toolbar"][starred
|
||||
list-style-image: url("chrome://browser/skin/chevron.svg");
|
||||
}
|
||||
|
||||
#nav-bar-overflow-button:-moz-locale-dir(rtl) > .toolbarbutton-icon {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
#email-link-button[cui-areatype="toolbar"] {
|
||||
list-style-image: url("chrome://browser/skin/mail.svg");
|
||||
}
|
||||
@ -191,10 +189,6 @@ toolbar:not([brighttext]) #bookmarks-menu-button[cui-areatype="toolbar"][starred
|
||||
fill: rgb(213, 32, 20);
|
||||
}
|
||||
|
||||
#panic-button:-moz-locale-dir(rtl) > .toolbarbutton-icon {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
#webide-button[cui-areatype="toolbar"] {
|
||||
list-style-image: url("chrome://browser/skin/webIDE.svg");
|
||||
}
|
||||
|
@ -1,105 +0,0 @@
|
||||
/* 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/. */
|
||||
|
||||
#tabs-display,
|
||||
#tabsList {
|
||||
background-color: transparent;
|
||||
-moz-appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#tabsList {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#tabs-display {
|
||||
background: #fff url(chrome://browser/skin/sync-bg.png) repeat-x center -80px;
|
||||
}
|
||||
|
||||
#headers {
|
||||
background: url(chrome://browser/skin/sync-32.png) no-repeat;
|
||||
margin-top: 4px;
|
||||
width: 45em;
|
||||
height: 32px;
|
||||
margin-inline-start: 2em;
|
||||
margin-inline-end: 2em;
|
||||
}
|
||||
|
||||
#headers:-moz-locale-dir(rtl) {
|
||||
background-position-x: 100%;
|
||||
}
|
||||
|
||||
#tabsListHeading {
|
||||
font-size: 140%;
|
||||
font-weight: bold;
|
||||
margin-inline-start: 40px;
|
||||
}
|
||||
|
||||
richlistitem {
|
||||
margin-inline-end: 2em;
|
||||
}
|
||||
|
||||
richlistitem[selected="true"],
|
||||
richlistitem:focus {
|
||||
outline-style: none;
|
||||
}
|
||||
|
||||
richlistitem[type="tab"] {
|
||||
min-height: 3em;
|
||||
border: #999999 1px solid !important;
|
||||
padding: 2px 5px;
|
||||
margin-bottom: 4px;
|
||||
margin-inline-start: 4em;
|
||||
border-radius: 6px;
|
||||
background-color: menu;
|
||||
width: 44em;
|
||||
opacity: 0.9;
|
||||
box-shadow:
|
||||
inset rgba(255, 255, 255, 0.5) 0 1px 0px,
|
||||
inset rgba(0, 0, 0, 0.1) 0 -2px 0px,
|
||||
rgba(0, 0, 0, 0.1) 0px 1px 0px;
|
||||
}
|
||||
|
||||
richlistitem[type="tab"][selected="true"] {
|
||||
background-color: -moz-MenuHover;
|
||||
}
|
||||
|
||||
richlistitem[type="client"] {
|
||||
min-height: 2em;
|
||||
color: #000000;
|
||||
margin-inline-start: 2em;
|
||||
margin-top: 2px;
|
||||
margin-bottom: 3px;
|
||||
width: 42em;
|
||||
border-radius: 6px;
|
||||
background-color: transparent;
|
||||
-moz-user-focus: ignore !important;
|
||||
}
|
||||
richlistitem.mobile[type="client"] {
|
||||
list-style-image: url("chrome://browser/skin/sync-mobileIcon.svg#icon");
|
||||
}
|
||||
richlistitem.desktop[type="client"] {
|
||||
list-style-image: url("chrome://browser/skin/sync-desktopIcon.svg#icon");
|
||||
}
|
||||
|
||||
.title,
|
||||
.clientName {
|
||||
color: #000000;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
.title[selected="true"],
|
||||
.url[selected="true"] {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.url {
|
||||
color: -moz-nativehyperlinktext;
|
||||
font-size: 0.95em;
|
||||
}
|
||||
|
||||
.tabIcon {
|
||||
padding-inline-start: 2px;
|
||||
padding-top: 2px;
|
||||
}
|
@ -7,7 +7,6 @@ browser.jar:
|
||||
#include ../shared/jar.inc.mn
|
||||
skin/classic/browser/sanitizeDialog.css
|
||||
skin/classic/browser/aboutSessionRestore-window-icon.png
|
||||
skin/classic/browser/aboutSyncTabs.css
|
||||
* skin/classic/browser/syncedtabs/sidebar.css (syncedtabs/sidebar.css)
|
||||
* skin/classic/browser/browser.css
|
||||
* skin/classic/browser/compacttheme.css
|
||||
@ -125,9 +124,6 @@ browser.jar:
|
||||
skin/classic/browser/tabbrowser/tab-stroke-start.png (tabbrowser/tab-stroke-start.png)
|
||||
skin/classic/browser/tabbrowser/tab-stroke-start@2x.png (tabbrowser/tab-stroke-start@2x.png)
|
||||
skin/classic/browser/tabbrowser/tabDragIndicator.png (tabbrowser/tabDragIndicator.png)
|
||||
skin/classic/browser/sync-16.png
|
||||
skin/classic/browser/sync-32.png
|
||||
skin/classic/browser/sync-bg.png
|
||||
skin/classic/browser/sync-desktopIcon.svg (../shared/sync-desktopIcon.svg)
|
||||
skin/classic/browser/sync-horizontalbar.png
|
||||
skin/classic/browser/sync-horizontalbar@2x.png
|
||||
|
@ -65,20 +65,19 @@ def check_build_environment(help, dist):
|
||||
|
||||
return result
|
||||
|
||||
set_config('TOPSRCDIR', delayed_getattr(check_build_environment, 'topsrcdir'))
|
||||
set_config('TOPOBJDIR', delayed_getattr(check_build_environment, 'topobjdir'))
|
||||
set_config('MOZ_BUILD_ROOT', delayed_getattr(check_build_environment,
|
||||
'topobjdir'))
|
||||
set_config('DIST', delayed_getattr(check_build_environment, 'dist'))
|
||||
set_config('TOPSRCDIR', check_build_environment.topsrcdir)
|
||||
set_config('TOPOBJDIR', check_build_environment.topobjdir)
|
||||
set_config('MOZ_BUILD_ROOT', check_build_environment.topobjdir)
|
||||
set_config('DIST', check_build_environment.dist)
|
||||
|
||||
add_old_configure_assignment(
|
||||
'_topsrcdir', delayed_getattr(check_build_environment, 'topsrcdir'))
|
||||
'_topsrcdir', check_build_environment.topsrcdir)
|
||||
add_old_configure_assignment(
|
||||
'_objdir', delayed_getattr(check_build_environment, 'topobjdir'))
|
||||
'_objdir', check_build_environment.topobjdir)
|
||||
add_old_configure_assignment(
|
||||
'MOZ_BUILD_ROOT', delayed_getattr(check_build_environment, 'topobjdir'))
|
||||
'MOZ_BUILD_ROOT', check_build_environment.topobjdir)
|
||||
add_old_configure_assignment(
|
||||
'DIST', delayed_getattr(check_build_environment, 'dist'))
|
||||
'DIST', check_build_environment.dist)
|
||||
|
||||
option(env='MOZ_AUTOMATION', help='Enable options for automated builds')
|
||||
set_config('MOZ_AUTOMATION', depends_if('MOZ_AUTOMATION')(lambda x: True))
|
||||
@ -558,21 +557,20 @@ def target_variables(target):
|
||||
INTEL_ARCHITECTURE=target.cpu in ('x86', 'x86_64') or None,
|
||||
)
|
||||
|
||||
set_config('OS_TARGET', delayed_getattr(target_variables, 'OS_TARGET'))
|
||||
set_config('OS_TARGET', target_variables.OS_TARGET)
|
||||
add_old_configure_assignment('OS_TARGET',
|
||||
delayed_getattr(target_variables, 'OS_TARGET'))
|
||||
set_config('OS_ARCH', delayed_getattr(target_variables, 'OS_ARCH'))
|
||||
target_variables.OS_TARGET)
|
||||
set_config('OS_ARCH', target_variables.OS_ARCH)
|
||||
add_old_configure_assignment('OS_ARCH',
|
||||
delayed_getattr(target_variables, 'OS_ARCH'))
|
||||
set_config('OS_TEST', delayed_getattr(target_variables, 'OS_TEST'))
|
||||
target_variables.OS_ARCH)
|
||||
set_config('OS_TEST', target_variables.OS_TEST)
|
||||
add_old_configure_assignment('OS_TEST',
|
||||
delayed_getattr(target_variables, 'OS_TEST'))
|
||||
set_config('CPU_ARCH', delayed_getattr(target, 'cpu'))
|
||||
add_old_configure_assignment('CPU_ARCH', delayed_getattr(target, 'cpu'))
|
||||
set_config('INTEL_ARCHITECTURE', delayed_getattr(target_variables,
|
||||
'INTEL_ARCHITECTURE'))
|
||||
set_config('TARGET_CPU', delayed_getattr(target, 'raw_cpu'))
|
||||
set_config('TARGET_OS', delayed_getattr(target, 'raw_os'))
|
||||
target_variables.OS_TEST)
|
||||
set_config('CPU_ARCH', target.cpu)
|
||||
add_old_configure_assignment('CPU_ARCH', target.cpu)
|
||||
set_config('INTEL_ARCHITECTURE', target_variables.INTEL_ARCHITECTURE)
|
||||
set_config('TARGET_CPU', target.raw_cpu)
|
||||
set_config('TARGET_OS', target.raw_os)
|
||||
|
||||
|
||||
@depends(host)
|
||||
@ -585,10 +583,10 @@ def host_variables(host):
|
||||
HOST_OS_ARCH=os_arch,
|
||||
)
|
||||
|
||||
set_config('HOST_CPU_ARCH', delayed_getattr(host, 'cpu'))
|
||||
set_config('HOST_OS_ARCH', delayed_getattr(host_variables, 'HOST_OS_ARCH'))
|
||||
set_config('HOST_CPU_ARCH', host.cpu)
|
||||
set_config('HOST_OS_ARCH', host_variables.HOST_OS_ARCH)
|
||||
add_old_configure_assignment('HOST_OS_ARCH',
|
||||
delayed_getattr(host_variables, 'HOST_OS_ARCH'))
|
||||
host_variables.HOST_OS_ARCH)
|
||||
|
||||
@depends(target)
|
||||
def target_is_windows(target):
|
||||
@ -717,19 +715,14 @@ def milestone(build_env, _):
|
||||
is_nightly=is_nightly,
|
||||
is_release_or_beta=is_release_or_beta)
|
||||
|
||||
@depends(milestone)
|
||||
def is_nightly(milestone):
|
||||
return milestone.is_nightly
|
||||
|
||||
set_config('GRE_MILESTONE', delayed_getattr(milestone, 'version'))
|
||||
set_config('NIGHTLY_BUILD', is_nightly)
|
||||
set_define('NIGHTLY_BUILD', is_nightly)
|
||||
add_old_configure_assignment('NIGHTLY_BUILD',
|
||||
is_nightly)
|
||||
set_config('RELEASE_OR_BETA', delayed_getattr(milestone, 'is_release_or_beta'))
|
||||
set_define('RELEASE_OR_BETA', delayed_getattr(milestone, 'is_release_or_beta'))
|
||||
set_config('GRE_MILESTONE', milestone.version)
|
||||
set_config('NIGHTLY_BUILD', milestone.is_nightly)
|
||||
set_define('NIGHTLY_BUILD', milestone.is_nightly)
|
||||
add_old_configure_assignment('NIGHTLY_BUILD', milestone.is_nightly)
|
||||
set_config('RELEASE_OR_BETA', milestone.is_release_or_beta)
|
||||
set_define('RELEASE_OR_BETA', milestone.is_release_or_beta)
|
||||
add_old_configure_assignment('RELEASE_OR_BETA',
|
||||
delayed_getattr(milestone, 'is_release_or_beta'))
|
||||
milestone.is_release_or_beta)
|
||||
|
||||
# The app update channel is 'default' when not supplied. The value is used in
|
||||
# the application's confvars.sh (and is made available to a project specific
|
||||
|
@ -60,5 +60,5 @@ def id_and_secret_keyfile(desc):
|
||||
|
||||
|
||||
name = desc.upper().replace(' ', '_')
|
||||
set_config('MOZ_%s_CLIENTID' % name, delayed_getattr(content, 'id'))
|
||||
set_config('MOZ_%s_KEY' % name, delayed_getattr(content, 'secret'))
|
||||
set_config('MOZ_%s_CLIENTID' % name, content.id)
|
||||
set_config('MOZ_%s_KEY' % name, content.secret)
|
||||
|
@ -27,9 +27,9 @@ def yasm_version(yasm):
|
||||
# Until we move all the yasm consumers out of old-configure.
|
||||
# bug 1257904
|
||||
add_old_configure_assignment('_YASM_MAJOR_VERSION',
|
||||
delayed_getattr(yasm_version, 'major'))
|
||||
yasm_version.major)
|
||||
add_old_configure_assignment('_YASM_MINOR_VERSION',
|
||||
delayed_getattr(yasm_version, 'minor'))
|
||||
yasm_version.minor)
|
||||
|
||||
@depends(yasm, target)
|
||||
def yasm_asflags(yasm, target):
|
||||
@ -645,7 +645,7 @@ def compiler(language, host_or_target, c_compiler=None, other_compiler=None,
|
||||
# result from check_prog as CC/CXX/HOST_CC/HOST_CXX and b) have to let
|
||||
# old-configure AC_SUBST it (because it's autoconf doing it, not us)
|
||||
compiler = check_prog('_%s' % var, what=what, progs=default_compilers,
|
||||
input=delayed_getattr(provided_compiler, 'compiler'),
|
||||
input=provided_compiler.compiler,
|
||||
paths=toolchain_search_path)
|
||||
|
||||
@depends(compiler, provided_compiler, compiler_wrapper, host_or_target)
|
||||
@ -791,11 +791,11 @@ def compiler(language, host_or_target, c_compiler=None, other_compiler=None,
|
||||
# old-configure to do some of its still existing checks.
|
||||
if language == 'C':
|
||||
set_config(
|
||||
'%s_TYPE' % var, delayed_getattr(valid_compiler, 'type'))
|
||||
'%s_TYPE' % var, valid_compiler.type)
|
||||
add_old_configure_assignment(
|
||||
'%s_TYPE' % var, delayed_getattr(valid_compiler, 'type'))
|
||||
'%s_TYPE' % var, valid_compiler.type)
|
||||
add_old_configure_assignment(
|
||||
'%s_VERSION' % var, delayed_getattr(valid_compiler, 'version'))
|
||||
'%s_VERSION' % var, valid_compiler.version)
|
||||
|
||||
valid_compiler = compiler_class(valid_compiler)
|
||||
|
||||
|
@ -366,27 +366,6 @@ always = dependable(True)
|
||||
never = dependable(False)
|
||||
|
||||
|
||||
# Some @depends function return namespaces, and one could want to use one
|
||||
# specific attribute from such a namespace as a "value" given to functions
|
||||
# such as `set_config`. But those functions do not take immediate values.
|
||||
# The `delayed_getattr` function allows access to attributes from the result
|
||||
# of a @depends function in a non-immediate manner.
|
||||
# @depends('--option')
|
||||
# def option(value)
|
||||
# return namespace(foo=value)
|
||||
# set_config('FOO', delayed_getattr(option, 'foo')
|
||||
@template
|
||||
def delayed_getattr(func, key):
|
||||
@depends(func)
|
||||
def result(value):
|
||||
# The @depends function we're being passed may have returned
|
||||
# None, or an object that simply doesn't have the wanted key.
|
||||
# In that case, just return None.
|
||||
return getattr(value, key, None)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
# Like @depends, but the decorated function is only called if one of the
|
||||
# arguments it would be called with has a positive value (bool(value) is True)
|
||||
@template
|
||||
|
@ -153,7 +153,7 @@ def valid_windows_sdk_dir(compiler, windows_sdk_dir, target_version,
|
||||
|
||||
add_old_configure_assignment(
|
||||
'WINDOWSSDKDIR',
|
||||
delayed_getattr(valid_windows_sdk_dir, 'path'))
|
||||
valid_windows_sdk_dir.path)
|
||||
add_old_configure_assignment(
|
||||
'MOZ_WINSDK_MAXVER',
|
||||
depends(valid_windows_sdk_dir)(
|
||||
|
@ -973,6 +973,7 @@ define CARGO_BUILD
|
||||
env $(environment_cleaner) $(rustflags_override) \
|
||||
CARGO_TARGET_DIR=$(CARGO_TARGET_DIR) \
|
||||
RUSTC=$(RUSTC) \
|
||||
MOZ_SRC=$(topsrcdir) \
|
||||
MOZ_DIST=$(ABS_DIST) \
|
||||
LIBCLANG_PATH=$(MOZ_LIBCLANG_PATH) \
|
||||
CLANG_PATH=$(MOZ_CLANG_PATH) \
|
||||
|
@ -28,6 +28,8 @@ module.exports = {
|
||||
"setInterval": true,
|
||||
"setTimeout": true,
|
||||
"uneval": true,
|
||||
"TextDecoder": true,
|
||||
"TextEncoder": true,
|
||||
"URL": true,
|
||||
"WebSocket": true,
|
||||
"XMLHttpRequest": true
|
||||
|
@ -83,7 +83,13 @@ SourceMapURLService.prototype.originalPositionFor = async function (url, line, c
|
||||
await this._sourceMapService.getOriginalURLs(urlInfo);
|
||||
const location = { sourceId: urlInfo.id, line, column, sourceUrl: url };
|
||||
let resolvedLocation = await this._sourceMapService.getOriginalLocation(location);
|
||||
return resolvedLocation === location ? null : resolvedLocation;
|
||||
if (!resolvedLocation ||
|
||||
(resolvedLocation.line === location.line &&
|
||||
resolvedLocation.column === location.column &&
|
||||
resolvedLocation.sourceUrl === location.sourceUrl)) {
|
||||
return null;
|
||||
}
|
||||
return resolvedLocation;
|
||||
};
|
||||
|
||||
exports.SourceMapURLService = SourceMapURLService;
|
||||
|
@ -68,6 +68,7 @@ skip-if = os == "mac" # Full keyboard navigation on OSX only works if Full Keybo
|
||||
[browser_inspector_highlighter-02.js]
|
||||
[browser_inspector_highlighter-03.js]
|
||||
[browser_inspector_highlighter-04.js]
|
||||
[browser_inspector_highlighter-05.js]
|
||||
[browser_inspector_highlighter-by-type.js]
|
||||
[browser_inspector_highlighter-cancel.js]
|
||||
[browser_inspector_highlighter-comments.js]
|
||||
|
@ -0,0 +1,69 @@
|
||||
/* 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";
|
||||
|
||||
// This is testing that the Anonymous Content is properly inserted into the document.
|
||||
// Usually that is happening during the "interactive" state of the document, to have them
|
||||
// ready as soon as possible.
|
||||
// However, in some conditions, that's not possible since we don't have access yet to
|
||||
// the `CustomContentContainer`, that is used to add the Anonymous Content.
|
||||
// That can happen if the page has some external resource, as <link>, that takes time
|
||||
// to load and / or returns the wrong content. This is not happening, for instance, with
|
||||
// images.
|
||||
//
|
||||
// In those case, we want to be sure that if we're not able to insert the Anonymous
|
||||
// Content at the "interactive" state, we're doing so when the document is loaded.
|
||||
//
|
||||
// See: https://bugzilla.mozilla.org/show_bug.cgi?id=1365075
|
||||
|
||||
const server = createTestHTTPServer();
|
||||
const filepath = "/slow.css";
|
||||
const cssuri = `http://localhost:${server.identity.primaryPort}${filepath}`;
|
||||
|
||||
// Register a slow css file handler so we can simulate a long loading time.
|
||||
server.registerContentType("css", "text/css");
|
||||
server.registerPathHandler(filepath, (metadata, response) => {
|
||||
info("CSS has been requested");
|
||||
response.processAsync();
|
||||
setTimeout(() => {
|
||||
info("CSS is responding");
|
||||
response.finish();
|
||||
}, 2000);
|
||||
});
|
||||
|
||||
const TEST_URL = "data:text/html," + encodeURIComponent(`
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link href="${cssuri}" rel="stylesheet" />
|
||||
</head>
|
||||
<body>
|
||||
<p>Slow page</p>
|
||||
</body>
|
||||
</html>
|
||||
`);
|
||||
|
||||
add_task(function* () {
|
||||
info("Open the inspector to a blank page.");
|
||||
let { inspector, tab, testActor } = yield openInspectorForURL("about:blank");
|
||||
|
||||
let pageLoaded = waitForPageLoad(tab);
|
||||
|
||||
info("Navigate to the test url and waiting for the page to be loaded.");
|
||||
yield navigateTo(inspector, TEST_URL);
|
||||
yield pageLoaded;
|
||||
|
||||
info("Shows the box model highligher for the <p> node.");
|
||||
let divFront = yield getNodeFront("p", inspector);
|
||||
yield inspector.highlighter.showBoxModel(divFront);
|
||||
|
||||
info("Check the node is highlighted.");
|
||||
is(yield testActor.isHighlighting(), true,
|
||||
"Box Model highlighter is working as expected.");
|
||||
});
|
||||
|
||||
const waitForPageLoad = (tab) => new Promise(resolve => {
|
||||
tab.linkedBrowser.addEventListener("load", resolve, {capture: true, once: true});
|
||||
});
|
@ -35,13 +35,16 @@ const StackTrace = createClass({
|
||||
stacktrace: PropTypes.array.isRequired,
|
||||
onViewSourceInDebugger: PropTypes.func.isRequired,
|
||||
onViewSourceInScratchpad: PropTypes.func,
|
||||
// Service to enable the source map feature.
|
||||
sourceMapService: PropTypes.object,
|
||||
},
|
||||
|
||||
render() {
|
||||
let {
|
||||
stacktrace,
|
||||
onViewSourceInDebugger,
|
||||
onViewSourceInScratchpad
|
||||
onViewSourceInScratchpad,
|
||||
sourceMapService,
|
||||
} = this.props;
|
||||
|
||||
let frames = [];
|
||||
@ -67,7 +70,8 @@ const StackTrace = createClass({
|
||||
showFullSourceUrl: true,
|
||||
onClick: (/^Scratchpad\/\d+$/.test(source))
|
||||
? onViewSourceInScratchpad
|
||||
: onViewSourceInDebugger
|
||||
: onViewSourceInDebugger,
|
||||
sourceMapService,
|
||||
}), "\n");
|
||||
});
|
||||
|
||||
|
@ -11,6 +11,7 @@ support-files =
|
||||
[test_searchbox-with-autocomplete.html]
|
||||
[test_sidebar_toggle.html]
|
||||
[test_stack-trace.html]
|
||||
[test_stack-trace-source-maps.html]
|
||||
[test_tabs_accessibility.html]
|
||||
[test_tabs_menu.html]
|
||||
[test_tree_01.html]
|
||||
|
@ -0,0 +1,105 @@
|
||||
<!-- 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/. -->
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
Test the rendering of a stack trace with source maps
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>StackTrace component test</title>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
<body>
|
||||
<script src="head.js"></script>
|
||||
<script>
|
||||
/* import-globals-from head.js */
|
||||
"use strict";
|
||||
|
||||
window.onload = function () {
|
||||
let ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");
|
||||
let React = browserRequire("devtools/client/shared/vendor/react");
|
||||
let StackTrace = React.createFactory(
|
||||
browserRequire("devtools/client/shared/components/stack-trace")
|
||||
);
|
||||
ok(StackTrace, "Got the StackTrace factory");
|
||||
|
||||
add_task(function* () {
|
||||
let stacktrace = [
|
||||
{
|
||||
filename: "https://bugzilla.mozilla.org/bundle.js",
|
||||
lineNumber: 99,
|
||||
columnNumber: 10
|
||||
},
|
||||
{
|
||||
functionName: "loadFunc",
|
||||
filename: "https://bugzilla.mozilla.org/bundle.js",
|
||||
lineNumber: 108,
|
||||
}
|
||||
];
|
||||
|
||||
let props = {
|
||||
stacktrace,
|
||||
onViewSourceInDebugger: () => {},
|
||||
onViewSourceInScratchpad: () => {},
|
||||
// A mock source map service.
|
||||
sourceMapService: {
|
||||
originalPositionFor: function (url, line, column) {
|
||||
let newLine = line === 99 ? 1 : 7;
|
||||
// Return a phony promise-like thing that resolves
|
||||
// immediately.
|
||||
return {
|
||||
then: function (consequence) {
|
||||
consequence({
|
||||
sourceId: "whatever",
|
||||
sourceUrl: "https://bugzilla.mozilla.org/original.js",
|
||||
line: newLine,
|
||||
column,
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
let trace = ReactDOM.render(StackTrace(props), window.document.body);
|
||||
yield forceRender(trace);
|
||||
|
||||
let traceEl = ReactDOM.findDOMNode(trace);
|
||||
ok(traceEl, "Rendered StackTrace has an element");
|
||||
|
||||
// Get the child nodes and filter out the text-only whitespace ones
|
||||
let frameEls = Array.from(traceEl.childNodes)
|
||||
.filter(n => n.className && n.className.includes("frame"));
|
||||
ok(frameEls, "Rendered StackTrace has frames");
|
||||
is(frameEls.length, 2, "StackTrace has 2 frames");
|
||||
|
||||
checkFrameString({
|
||||
el: frameEls[0],
|
||||
functionName: "<anonymous>",
|
||||
source: "https://bugzilla.mozilla.org/original.js",
|
||||
file: "original.js",
|
||||
line: 1,
|
||||
column: 10,
|
||||
shouldLink: true,
|
||||
tooltip: "View source in Debugger → https://bugzilla.mozilla.org/original.js:1:10",
|
||||
});
|
||||
|
||||
checkFrameString({
|
||||
el: frameEls[1],
|
||||
functionName: "loadFunc",
|
||||
source: "https://bugzilla.mozilla.org/original.js",
|
||||
file: "original.js",
|
||||
line: 7,
|
||||
column: null,
|
||||
shouldLink: true,
|
||||
tooltip: "View source in Debugger → https://bugzilla.mozilla.org/original.js:7",
|
||||
});
|
||||
});
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -21,7 +21,7 @@ const EventEmitter = require("devtools/shared/event-emitter");
|
||||
const {Task} = require("devtools/shared/task");
|
||||
const {FileUtils} = require("resource://gre/modules/FileUtils.jsm");
|
||||
const {NetUtil} = require("resource://gre/modules/NetUtil.jsm");
|
||||
const {TextDecoder, OS} = Cu.import("resource://gre/modules/osfile.jsm", {});
|
||||
const {OS} = Cu.import("resource://gre/modules/osfile.jsm", {});
|
||||
const {
|
||||
getString,
|
||||
showFilePicker,
|
||||
|
@ -19,12 +19,11 @@ loader.lazyRequireGetter(this, "ObjectClient", "devtools/shared/client/main", tr
|
||||
const { extend } = require("sdk/core/heritage");
|
||||
const XHTML_NS = "http://www.w3.org/1999/xhtml";
|
||||
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
const STRINGS_URI = "devtools/client/locales/webconsole.properties";
|
||||
|
||||
const WebConsoleUtils = require("devtools/client/webconsole/utils").Utils;
|
||||
const { getSourceNames } = require("devtools/client/shared/source-utils");
|
||||
const {Task} = require("devtools/shared/task");
|
||||
const l10n = new WebConsoleUtils.L10n(STRINGS_URI);
|
||||
const l10n = require("devtools/client/webconsole/webconsole-l10n");
|
||||
const nodeConstants = require("devtools/shared/dom-node-constants");
|
||||
const {PluralForm} = require("devtools/shared/plural-form");
|
||||
|
||||
@ -3556,9 +3555,12 @@ Widgets.Stacktrace.prototype = extend(Widgets.BaseWidget.prototype, {
|
||||
result.className = "stacktrace devtools-monospace";
|
||||
|
||||
if (this.stacktrace) {
|
||||
const target = this.message.output.toolboxTarget;
|
||||
const toolbox = gDevTools.getToolbox(target);
|
||||
this.output.owner.ReactDOM.render(this.output.owner.StackTraceView({
|
||||
stacktrace: this.stacktrace,
|
||||
onViewSourceInDebugger: frame => this.output.openLocationInDebugger(frame)
|
||||
onViewSourceInDebugger: frame => this.output.openLocationInDebugger(frame),
|
||||
sourceMapService: toolbox ? toolbox.sourceMapURLService : null,
|
||||
}), result);
|
||||
}
|
||||
|
||||
|
@ -22,8 +22,7 @@ loader.lazyRequireGetter(this, "DebuggerClient", "devtools/shared/client/main",
|
||||
loader.lazyRequireGetter(this, "showDoorhanger", "devtools/client/shared/doorhanger", true);
|
||||
loader.lazyRequireGetter(this, "viewSource", "devtools/client/shared/view-source");
|
||||
|
||||
const STRINGS_URI = "devtools/client/locales/webconsole.properties";
|
||||
var l10n = new WebConsoleUtils.L10n(STRINGS_URI);
|
||||
const l10n = require("devtools/client/webconsole/webconsole-l10n");
|
||||
|
||||
const BROWSER_CONSOLE_WINDOW_FEATURES = "chrome,titlebar,toolbar,centerscreen,resizable,dialog=no";
|
||||
|
||||
|
@ -27,8 +27,7 @@ loader.lazyImporter(this, "VariablesView", "resource://devtools/client/shared/wi
|
||||
loader.lazyImporter(this, "VariablesViewController", "resource://devtools/client/shared/widgets/VariablesViewController.jsm");
|
||||
loader.lazyRequireGetter(this, "gDevTools", "devtools/client/framework/devtools", true);
|
||||
|
||||
const STRINGS_URI = "devtools/client/locales/webconsole.properties";
|
||||
var l10n = new WebConsoleUtils.L10n(STRINGS_URI);
|
||||
const l10n = require("devtools/client/webconsole/webconsole-l10n");
|
||||
|
||||
// Constants used for defining the direction of JSTerm input history navigation.
|
||||
const HISTORY_BACK = -1;
|
||||
|
@ -19,8 +19,9 @@ DevToolsModules(
|
||||
'panel.js',
|
||||
'utils.js',
|
||||
'webconsole-connection-proxy.js',
|
||||
'webconsole-l10n.js',
|
||||
'webconsole.js',
|
||||
)
|
||||
|
||||
with Files('**'):
|
||||
BUG_COMPONENT = ('Firefox', 'Developer Tools: Console')
|
||||
with Files('**'):
|
||||
BUG_COMPONENT = ('Firefox', 'Developer Tools: Console')
|
||||
|
@ -38,7 +38,9 @@ var NetInfoBody = React.createClass({
|
||||
data: PropTypes.shape({
|
||||
request: PropTypes.object.isRequired,
|
||||
response: PropTypes.object.isRequired
|
||||
})
|
||||
}),
|
||||
// Service to enable the source map feature.
|
||||
sourceMapService: PropTypes.object,
|
||||
},
|
||||
|
||||
displayName: "NetInfoBody",
|
||||
@ -76,7 +78,7 @@ var NetInfoBody = React.createClass({
|
||||
},
|
||||
|
||||
getTabPanels() {
|
||||
let actions = this.props.actions;
|
||||
let { actions, sourceMapService } = this.props;
|
||||
let data = this.state.data;
|
||||
let {request} = data;
|
||||
|
||||
@ -153,7 +155,8 @@ var NetInfoBody = React.createClass({
|
||||
title: Locale.$STR("netRequest.callstack")},
|
||||
StackTraceTab({
|
||||
data: data,
|
||||
actions: actions
|
||||
actions: actions,
|
||||
sourceMapService: sourceMapService,
|
||||
})
|
||||
)
|
||||
);
|
||||
|
@ -13,15 +13,17 @@ const StackTraceTab = createClass({
|
||||
data: PropTypes.object.isRequired,
|
||||
actions: PropTypes.shape({
|
||||
onViewSourceInDebugger: PropTypes.func.isRequired
|
||||
})
|
||||
}),
|
||||
// Service to enable the source map feature.
|
||||
sourceMapService: PropTypes.object,
|
||||
},
|
||||
|
||||
render() {
|
||||
let { stacktrace } = this.props.data.cause;
|
||||
let { actions } = this.props;
|
||||
let { actions, sourceMapService } = this.props;
|
||||
let onViewSourceInDebugger = actions.onViewSourceInDebugger.bind(actions);
|
||||
|
||||
return StackTrace({ stacktrace, onViewSourceInDebugger });
|
||||
return StackTrace({ stacktrace, onViewSourceInDebugger, sourceMapService });
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -163,7 +163,8 @@ NetRequest.prototype = {
|
||||
// As soon as Redux is in place state and actions will come from
|
||||
// separate modules.
|
||||
let body = NetInfoBody({
|
||||
actions: this
|
||||
actions: this,
|
||||
sourceMapService: this.owner.sourceMapURLService,
|
||||
});
|
||||
|
||||
// Render net info body!
|
||||
|
@ -30,6 +30,7 @@ const ConsoleOutput = createClass({
|
||||
serviceContainer: PropTypes.shape({
|
||||
attachRefToHud: PropTypes.func.isRequired,
|
||||
openContextMenu: PropTypes.func.isRequired,
|
||||
sourceMapService: PropTypes.object,
|
||||
}),
|
||||
autoscroll: PropTypes.bool.isRequired,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
|
@ -13,7 +13,6 @@ const { getAllFilters } = require("devtools/client/webconsole/new-console-output
|
||||
const { getAllUi } = require("devtools/client/webconsole/new-console-output/selectors/ui");
|
||||
const {
|
||||
filterTextSet,
|
||||
filtersClear,
|
||||
filterBarToggle,
|
||||
messagesClear
|
||||
} = require("devtools/client/webconsole/new-console-output/actions/index");
|
||||
@ -49,10 +48,6 @@ const FilterBar = createClass({
|
||||
this.props.dispatch(filterBarToggle());
|
||||
},
|
||||
|
||||
onClickFiltersClear: function () {
|
||||
this.props.dispatch(filtersClear());
|
||||
},
|
||||
|
||||
onSearchInput: function (e) {
|
||||
this.props.dispatch(filterTextSet(e.target.value));
|
||||
},
|
||||
|
@ -20,6 +20,7 @@ ConsoleCommand.propTypes = {
|
||||
autoscroll: PropTypes.bool.isRequired,
|
||||
indent: PropTypes.number.isRequired,
|
||||
timestampsVisible: PropTypes.bool.isRequired,
|
||||
serviceContainer: PropTypes.object,
|
||||
};
|
||||
|
||||
ConsoleCommand.defaultProps = {
|
||||
@ -35,6 +36,7 @@ function ConsoleCommand(props) {
|
||||
indent,
|
||||
message,
|
||||
timestampsVisible,
|
||||
serviceContainer,
|
||||
} = props;
|
||||
|
||||
const {
|
||||
@ -44,10 +46,6 @@ function ConsoleCommand(props) {
|
||||
messageText: messageBody,
|
||||
} = message;
|
||||
|
||||
const {
|
||||
serviceContainer,
|
||||
} = props;
|
||||
|
||||
return Message({
|
||||
source,
|
||||
type,
|
||||
|
@ -20,6 +20,7 @@ EvaluationResult.propTypes = {
|
||||
message: PropTypes.object.isRequired,
|
||||
indent: PropTypes.number.isRequired,
|
||||
timestampsVisible: PropTypes.bool.isRequired,
|
||||
serviceContainer: PropTypes.object,
|
||||
};
|
||||
|
||||
EvaluationResult.defaultProps = {
|
||||
|
@ -20,6 +20,7 @@ PageError.propTypes = {
|
||||
open: PropTypes.bool,
|
||||
indent: PropTypes.number.isRequired,
|
||||
timestampsVisible: PropTypes.bool.isRequired,
|
||||
serviceContainer: PropTypes.object,
|
||||
};
|
||||
|
||||
PageError.defaultProps = {
|
||||
|
@ -148,6 +148,7 @@ const Message = createClass({
|
||||
stacktrace: stacktrace,
|
||||
onViewSourceInDebugger: serviceContainer.onViewSourceInDebugger,
|
||||
onViewSourceInScratchpad: serviceContainer.onViewSourceInScratchpad,
|
||||
sourceMapService: serviceContainer.sourceMapService,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ const { l10n } = require("devtools/client/webconsole/new-console-output/utils/me
|
||||
const { getAllFilters } = require("devtools/client/webconsole/new-console-output/selectors/filters");
|
||||
const { getLogLimit } = require("devtools/client/webconsole/new-console-output/selectors/prefs");
|
||||
const { getGripPreviewItems } = require("devtools/client/shared/components/reps/reps");
|
||||
const { getSourceNames } = require("devtools/client/shared/source-utils");
|
||||
const {
|
||||
MESSAGE_TYPE,
|
||||
MESSAGE_SOURCE
|
||||
@ -131,8 +132,9 @@ function isTextInFrame(text, frame) {
|
||||
if (!frame) {
|
||||
return false;
|
||||
}
|
||||
return Object.values(frame)
|
||||
.join(":")
|
||||
|
||||
const { short } = getSourceNames(frame.source);
|
||||
return `${short}:${frame.line}:${frame.column}`
|
||||
.toLocaleLowerCase()
|
||||
.includes(text.toLocaleLowerCase());
|
||||
}
|
||||
|
@ -99,8 +99,7 @@ describe("ConsoleAPICall component:", () => {
|
||||
serviceContainer,
|
||||
timestampsVisible: true,
|
||||
}));
|
||||
const L10n = require("devtools/client/webconsole/new-console-output/test/fixtures/L10n");
|
||||
const { timestampString } = new L10n();
|
||||
const { timestampString } = require("devtools/client/webconsole/webconsole-l10n");
|
||||
|
||||
expect(wrapper.find(".timestamp").text()).toBe(timestampString(message.timeStamp));
|
||||
});
|
||||
|
@ -97,8 +97,7 @@ describe("EvaluationResult component:", () => {
|
||||
message,
|
||||
timestampsVisible: true,
|
||||
}));
|
||||
const L10n = require("devtools/client/webconsole/new-console-output/test/fixtures/L10n");
|
||||
const { timestampString } = new L10n();
|
||||
const { timestampString } = require("devtools/client/webconsole/webconsole-l10n");
|
||||
|
||||
expect(wrapper.find(".timestamp").text()).toBe(timestampString(message.timeStamp));
|
||||
});
|
||||
|
@ -29,8 +29,7 @@ describe("NetworkEventMessage component:", () => {
|
||||
serviceContainer,
|
||||
timestampsVisible: true,
|
||||
}));
|
||||
const L10n = require("devtools/client/webconsole/new-console-output/test/fixtures/L10n");
|
||||
const { timestampString } = new L10n();
|
||||
const { timestampString } = require("devtools/client/webconsole/webconsole-l10n");
|
||||
|
||||
expect(wrapper.find(".timestamp").text()).toBe(timestampString(message.timeStamp));
|
||||
expect(wrapper.find(".message-body .method").text()).toBe("GET");
|
||||
|
@ -32,8 +32,7 @@ describe("PageError component:", () => {
|
||||
serviceContainer,
|
||||
timestampsVisible: true,
|
||||
}));
|
||||
const L10n = require("devtools/client/webconsole/new-console-output/test/fixtures/L10n");
|
||||
const { timestampString } = new L10n();
|
||||
const { timestampString } = require("devtools/client/webconsole/webconsole-l10n");
|
||||
|
||||
expect(wrapper.find(".timestamp").text()).toBe(timestampString(message.timeStamp));
|
||||
|
||||
|
@ -14,9 +14,7 @@ Services.scriptloader.loadSubScript(
|
||||
"chrome://mochitests/content/browser/devtools/client/framework/test/shared-head.js",
|
||||
this);
|
||||
|
||||
var {Utils: WebConsoleUtils} = require("devtools/client/webconsole/utils");
|
||||
const WEBCONSOLE_STRINGS_URI = "devtools/client/locales/webconsole.properties";
|
||||
var WCUL10n = new WebConsoleUtils.L10n(WEBCONSOLE_STRINGS_URI);
|
||||
var WCUL10n = require("devtools/client/webconsole/webconsole-l10n");
|
||||
|
||||
Services.prefs.setBoolPref("devtools.webconsole.new-frontend-enabled", true);
|
||||
registerCleanupFunction(function* () {
|
||||
|
@ -27,8 +27,6 @@ requireHacker.global_hook("default", path => {
|
||||
// Some modules depend on Chrome APIs which don't work in mocha. When such a module
|
||||
// is required, replace it with a mock version.
|
||||
switch (path) {
|
||||
case "devtools/client/webconsole/utils":
|
||||
return `module.exports = require("devtools/client/webconsole/new-console-output/test/fixtures/WebConsoleUtils")`;
|
||||
case "devtools/shared/l10n":
|
||||
return `module.exports = require("devtools/client/webconsole/new-console-output/test/fixtures/LocalizationHelper")`;
|
||||
case "devtools/shared/plural-form":
|
||||
|
@ -66,6 +66,18 @@ describe("Searching in grips", () => {
|
||||
expect(getAllMessages(store.getState()).size).toEqual(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Search in frame", () => {
|
||||
it("matches on file name", () => {
|
||||
store.dispatch(actions.filterTextSet("test-console-api.html:1:27"));
|
||||
expect(getAllMessages(store.getState()).size).toEqual(7);
|
||||
});
|
||||
|
||||
it("do not match on full url", () => {
|
||||
store.dispatch(actions.filterTextSet("http://example.com/browser/devtools"));
|
||||
expect(getAllMessages(store.getState()).size).toEqual(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function prepareBaseStore() {
|
||||
|
@ -6,9 +6,7 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
const WebConsoleUtils = require("devtools/client/webconsole/utils").Utils;
|
||||
const STRINGS_URI = "devtools/client/locales/webconsole.properties";
|
||||
const l10n = new WebConsoleUtils.L10n(STRINGS_URI);
|
||||
const l10n = require("devtools/client/webconsole/webconsole-l10n");
|
||||
|
||||
const {
|
||||
MESSAGE_SOURCE,
|
||||
|
@ -37,8 +37,7 @@ const SEVERITY_LOG = 3;
|
||||
// The indent of a console group in pixels.
|
||||
const GROUP_INDENT = 12;
|
||||
|
||||
const WEBCONSOLE_STRINGS_URI = "devtools/client/locales/webconsole.properties";
|
||||
var WCUL10n = new WebConsoleUtils.L10n(WEBCONSOLE_STRINGS_URI);
|
||||
var WCUL10n = require("devtools/client/webconsole/webconsole-l10n");
|
||||
|
||||
const DOCS_GA_PARAMS = "?utm_source=mozilla" +
|
||||
"&utm_medium=firefox-console-errors" +
|
||||
|
@ -8,7 +8,6 @@
|
||||
|
||||
const {Cc, Ci} = require("chrome");
|
||||
const Services = require("Services");
|
||||
const {LocalizationHelper} = require("devtools/shared/l10n");
|
||||
|
||||
// Match the function name from the result of toString() or toSource().
|
||||
//
|
||||
@ -285,65 +284,3 @@ var WebConsoleUtils = {
|
||||
|
||||
exports.Utils = WebConsoleUtils;
|
||||
|
||||
// Localization
|
||||
|
||||
WebConsoleUtils.L10n = function (bundleURI) {
|
||||
this._helper = new LocalizationHelper(bundleURI);
|
||||
};
|
||||
|
||||
WebConsoleUtils.L10n.prototype = {
|
||||
/**
|
||||
* Generates a formatted timestamp string for displaying in console messages.
|
||||
*
|
||||
* @param integer [milliseconds]
|
||||
* Optional, allows you to specify the timestamp in milliseconds since
|
||||
* the UNIX epoch.
|
||||
* @return string
|
||||
* The timestamp formatted for display.
|
||||
*/
|
||||
timestampString: function (milliseconds) {
|
||||
let d = new Date(milliseconds ? milliseconds : null);
|
||||
let hours = d.getHours(), minutes = d.getMinutes();
|
||||
let seconds = d.getSeconds();
|
||||
milliseconds = d.getMilliseconds();
|
||||
let parameters = [hours, minutes, seconds, milliseconds];
|
||||
return this.getFormatStr("timestampFormat", parameters);
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieve a localized string.
|
||||
*
|
||||
* @param string name
|
||||
* The string name you want from the Web Console string bundle.
|
||||
* @return string
|
||||
* The localized string.
|
||||
*/
|
||||
getStr: function (name) {
|
||||
try {
|
||||
return this._helper.getStr(name);
|
||||
} catch (ex) {
|
||||
console.error("Failed to get string: " + name);
|
||||
throw ex;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieve a localized string formatted with values coming from the given
|
||||
* array.
|
||||
*
|
||||
* @param string name
|
||||
* The string name you want from the Web Console string bundle.
|
||||
* @param array array
|
||||
* The array of values you want in the formatted string.
|
||||
* @return string
|
||||
* The formatted local string.
|
||||
*/
|
||||
getFormatStr: function (name, array) {
|
||||
try {
|
||||
return this._helper.getFormatStr(name, ...array);
|
||||
} catch (ex) {
|
||||
console.error("Failed to format string: " + name);
|
||||
throw ex;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
@ -10,8 +10,7 @@ const {Utils: WebConsoleUtils} = require("devtools/client/webconsole/utils");
|
||||
const defer = require("devtools/shared/defer");
|
||||
const Services = require("Services");
|
||||
|
||||
const STRINGS_URI = "devtools/client/locales/webconsole.properties";
|
||||
var l10n = new WebConsoleUtils.L10n(STRINGS_URI);
|
||||
const l10n = require("devtools/client/webconsole/webconsole-l10n");
|
||||
|
||||
const PREF_CONNECTION_TIMEOUT = "devtools.debugger.remote-timeout";
|
||||
// Web Console connection proxy
|
||||
|
70
devtools/client/webconsole/webconsole-l10n.js
Normal file
70
devtools/client/webconsole/webconsole-l10n.js
Normal file
@ -0,0 +1,70 @@
|
||||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* 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 {LocalizationHelper} = require("devtools/shared/l10n");
|
||||
const helper = new LocalizationHelper("devtools/client/locales/webconsole.properties");
|
||||
|
||||
const l10n = {
|
||||
|
||||
/**
|
||||
* Generates a formatted timestamp string for displaying in console messages.
|
||||
*
|
||||
* @param integer [milliseconds]
|
||||
* Optional, allows you to specify the timestamp in milliseconds since
|
||||
* the UNIX epoch.
|
||||
* @return string
|
||||
* The timestamp formatted for display.
|
||||
*/
|
||||
timestampString: function (milliseconds) {
|
||||
let d = new Date(milliseconds ? milliseconds : null);
|
||||
let hours = d.getHours(), minutes = d.getMinutes();
|
||||
let seconds = d.getSeconds();
|
||||
milliseconds = d.getMilliseconds();
|
||||
let parameters = [hours, minutes, seconds, milliseconds];
|
||||
return l10n.getFormatStr("timestampFormat", parameters);
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieve a localized string.
|
||||
*
|
||||
* @param string name
|
||||
* The string name you want from the Web Console string bundle.
|
||||
* @return string
|
||||
* The localized string.
|
||||
*/
|
||||
getStr: function (name) {
|
||||
try {
|
||||
return helper.getStr(name);
|
||||
} catch (ex) {
|
||||
console.error("Failed to get string: " + name);
|
||||
throw ex;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieve a localized string formatted with values coming from the given
|
||||
* array.
|
||||
*
|
||||
* @param string name
|
||||
* The string name you want from the Web Console string bundle.
|
||||
* @param array array
|
||||
* The array of values you want in the formatted string.
|
||||
* @return string
|
||||
* The formatted local string.
|
||||
*/
|
||||
getFormatStr: function (name, array) {
|
||||
try {
|
||||
return helper.getFormatStr(name, ...array);
|
||||
} catch (ex) {
|
||||
console.error("Failed to format string: " + name);
|
||||
throw ex;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = l10n;
|
@ -38,8 +38,7 @@ loader.lazyRequireGetter(this, "ZoomKeys", "devtools/client/shared/zoom-keys");
|
||||
loader.lazyRequireGetter(this, "WebConsoleConnectionProxy", "devtools/client/webconsole/webconsole-connection-proxy", true);
|
||||
|
||||
const {PluralForm} = require("devtools/shared/plural-form");
|
||||
const STRINGS_URI = "devtools/client/locales/webconsole.properties";
|
||||
var l10n = new WebConsoleUtils.L10n(STRINGS_URI);
|
||||
const l10n = require("devtools/client/webconsole/webconsole-l10n");
|
||||
|
||||
const XHTML_NS = "http://www.w3.org/1999/xhtml";
|
||||
|
||||
|
@ -49,6 +49,7 @@ webpackConfig.resolve = {
|
||||
"devtools/client/webconsole/utils": path.join(__dirname, "new-console-output/test/fixtures/WebConsoleUtils"),
|
||||
"devtools/client/webconsole/new-console-output": path.join(__dirname, "new-console-output"),
|
||||
"devtools/client/webconsole/webconsole-connection-proxy": path.join(__dirname, "webconsole-connection-proxy"),
|
||||
"devtools/client/webconsole/webconsole-l10n": path.join(__dirname, "webconsole-l10n"),
|
||||
|
||||
"react": path.join(__dirname, "node_modules/react"),
|
||||
"devtools/client/shared/vendor/immutable": "immutable",
|
||||
|
@ -9,7 +9,7 @@ const {TargetFactory} = require("devtools/client/framework/target");
|
||||
const Services = require("Services");
|
||||
const {FileUtils} = Cu.import("resource://gre/modules/FileUtils.jsm", {});
|
||||
const EventEmitter = require("devtools/shared/event-emitter");
|
||||
const {TextEncoder, OS} = Cu.import("resource://gre/modules/osfile.jsm", {});
|
||||
const {OS} = Cu.import("resource://gre/modules/osfile.jsm", {});
|
||||
const {AppProjects} = require("devtools/client/webide/modules/app-projects");
|
||||
const TabStore = require("devtools/client/webide/modules/tab-store");
|
||||
const {AppValidator} = require("devtools/client/webide/modules/app-validator");
|
||||
|
@ -6,7 +6,7 @@ const {Cu, Cc, Ci} = require("chrome");
|
||||
|
||||
const promise = require("promise");
|
||||
const { Task } = require("devtools/shared/task");
|
||||
const { TextDecoder, OS } = Cu.import("resource://gre/modules/osfile.jsm", {});
|
||||
const { OS } = Cu.import("resource://gre/modules/osfile.jsm", {});
|
||||
const Subprocess = require("sdk/system/child_process/subprocess");
|
||||
|
||||
const ProjectBuilding = exports.ProjectBuilding = {
|
||||
|
@ -18,7 +18,7 @@
|
||||
window.onload = function() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
let {TextDecoder, OS} = Cu.import("resource://gre/modules/osfile.jsm", {});
|
||||
let {OS} = Cu.import("resource://gre/modules/osfile.jsm", {});
|
||||
let {ProjectBuilding} = require("devtools/client/webide/modules/build");
|
||||
|
||||
Task.spawn(function* () {
|
||||
|
@ -18,7 +18,7 @@
|
||||
window.onload = function() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
let {TextDecoder, OS} = Cu.import("resource://gre/modules/osfile.jsm", {});
|
||||
let {OS} = Cu.import("resource://gre/modules/osfile.jsm", {});
|
||||
|
||||
Task.spawn(function* () {
|
||||
let win = yield openWebIDE();
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
const { Cc, Ci, Cu } = require("chrome");
|
||||
const { Cc, Ci, Cu, Cr } = require("chrome");
|
||||
const { getCurrentZoom, getWindowDimensions, getViewportDimensions,
|
||||
getRootBindingParent, loadSheet } = require("devtools/shared/layout/utils");
|
||||
const { on, emit } = require("sdk/event/core");
|
||||
@ -270,7 +270,23 @@ CanvasFrameAnonymousContentHelper.prototype = {
|
||||
// at least on desktop. Therefore, removing the code that was dealing with
|
||||
// that scenario, fixes when we're adding anonymous content in a tab that
|
||||
// is not the active one (see bug 1260043 and bug 1260044)
|
||||
this._content = doc.insertAnonymousContent(node);
|
||||
try {
|
||||
this._content = doc.insertAnonymousContent(node);
|
||||
} catch (e) {
|
||||
// If the `insertAnonymousContent` fails throwing a `NS_ERROR_UNEXPECTED`, it means
|
||||
// we don't have access to a `CustomContentContainer` yet (see bug 1365075).
|
||||
// At this point, it could only happen on document's interactive state, and we
|
||||
// need to wait until the `complete` state before inserting the anonymous content
|
||||
// again.
|
||||
if (e.result === Cr.NS_ERROR_UNEXPECTED && doc.readyState === "interactive") {
|
||||
// The next state change will be "complete" since the current is "interactive"
|
||||
doc.addEventListener("readystatechange", () => {
|
||||
this._content = doc.insertAnonymousContent(node);
|
||||
}, { once: true });
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_remove() {
|
||||
|
@ -363,10 +363,6 @@ DevToolsUtils.defineLazyGetter(this, "OS", () => {
|
||||
return Cu.import("resource://gre/modules/osfile.jsm", {}).OS;
|
||||
});
|
||||
|
||||
DevToolsUtils.defineLazyGetter(this, "TextDecoder", () => {
|
||||
return Cu.import("resource://gre/modules/osfile.jsm", {}).TextDecoder;
|
||||
});
|
||||
|
||||
DevToolsUtils.defineLazyGetter(this, "NetworkHelper", () => {
|
||||
return require("devtools/shared/webconsole/network-helper");
|
||||
});
|
||||
|
@ -20,7 +20,7 @@ const jsmScope = Cu.import("resource://gre/modules/Services.jsm", {});
|
||||
const { Services } = jsmScope;
|
||||
// Steal various globals only available in JSM scope (and not Sandbox one)
|
||||
const { PromiseDebugging, ChromeUtils, ThreadSafeChromeUtils, HeapSnapshot,
|
||||
atob, btoa } = jsmScope;
|
||||
atob, btoa, TextEncoder, TextDecoder } = jsmScope;
|
||||
const { URL } = Cu.Sandbox(CC("@mozilla.org/systemprincipal;1", "nsIPrincipal")(),
|
||||
{wantGlobalProperties: ["URL"]});
|
||||
|
||||
@ -215,6 +215,8 @@ exports.globals = {
|
||||
reportError: Cu.reportError,
|
||||
atob: atob,
|
||||
btoa: btoa,
|
||||
TextEncoder: TextEncoder,
|
||||
TextDecoder: TextDecoder,
|
||||
URL,
|
||||
loader: {
|
||||
lazyGetter: defineLazyGetter,
|
||||
|
@ -1234,6 +1234,8 @@ exports.CSS_PROPERTIES = {
|
||||
"supports": [],
|
||||
"values": [
|
||||
"ignore",
|
||||
"ignore-horizontal",
|
||||
"ignore-vertical",
|
||||
"inherit",
|
||||
"initial",
|
||||
"stretch-to-fit",
|
||||
@ -3402,6 +3404,8 @@ exports.CSS_PROPERTIES = {
|
||||
"icon",
|
||||
"ideographic",
|
||||
"ignore",
|
||||
"ignore-horizontal",
|
||||
"ignore-vertical",
|
||||
"inactive",
|
||||
"infinite",
|
||||
"inherit",
|
||||
|
@ -5,7 +5,7 @@
|
||||
"use strict";
|
||||
|
||||
const { Cc, Ci, Cu } = require("chrome");
|
||||
const { OS, TextDecoder } = Cu.import("resource://gre/modules/osfile.jsm", {});
|
||||
const { OS } = Cu.import("resource://gre/modules/osfile.jsm", {});
|
||||
const { Task } = require("devtools/shared/task");
|
||||
|
||||
const gcli = require("gcli/index");
|
||||
|
@ -228,7 +228,8 @@ AnonymousContent::GetComputedStylePropertyValue(const nsAString& aElementId,
|
||||
}
|
||||
|
||||
RefPtr<nsComputedDOMStyle> cs =
|
||||
new nsComputedDOMStyle(element, NS_LITERAL_STRING(""), shell);
|
||||
new nsComputedDOMStyle(element, NS_LITERAL_STRING(""), shell,
|
||||
nsComputedDOMStyle::eAll);
|
||||
aRv = cs->GetPropertyValue(aPropertyName, aResult);
|
||||
}
|
||||
|
||||
|
@ -2299,13 +2299,15 @@ Element::MaybeCheckSameAttrVal(int32_t aNamespaceID,
|
||||
bool aNotify,
|
||||
nsAttrValue& aOldValue,
|
||||
uint8_t* aModType,
|
||||
bool* aHasListeners)
|
||||
bool* aHasListeners,
|
||||
bool* aOldValueSet)
|
||||
{
|
||||
bool modification = false;
|
||||
*aHasListeners = aNotify &&
|
||||
nsContentUtils::HasMutationListeners(this,
|
||||
NS_EVENT_BITS_MUTATION_ATTRMODIFIED,
|
||||
this);
|
||||
*aOldValueSet = false;
|
||||
|
||||
// If we have no listeners and aNotify is false, we are almost certainly
|
||||
// coming from the content sink and will almost certainly have no previous
|
||||
@ -2330,6 +2332,7 @@ Element::MaybeCheckSameAttrVal(int32_t aNamespaceID,
|
||||
// We have to serialize the value anyway in order to create the
|
||||
// mutation event so there's no cost in doing it now.
|
||||
aOldValue.SetToSerialized(*info.mValue);
|
||||
*aOldValueSet = true;
|
||||
}
|
||||
bool valueMatches = aValue.EqualsAsStrings(*info.mValue);
|
||||
if (valueMatches && aPrefix == info.mName->GetPrefix()) {
|
||||
@ -2349,10 +2352,12 @@ Element::OnlyNotifySameValueSet(int32_t aNamespaceID, nsIAtom* aName,
|
||||
nsIAtom* aPrefix,
|
||||
const nsAttrValueOrString& aValue,
|
||||
bool aNotify, nsAttrValue& aOldValue,
|
||||
uint8_t* aModType, bool* aHasListeners)
|
||||
uint8_t* aModType, bool* aHasListeners,
|
||||
bool* aOldValueSet)
|
||||
{
|
||||
if (!MaybeCheckSameAttrVal(aNamespaceID, aName, aPrefix, aValue, aNotify,
|
||||
aOldValue, aModType, aHasListeners)) {
|
||||
aOldValue, aModType, aHasListeners,
|
||||
aOldValueSet)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -2383,9 +2388,10 @@ Element::SetAttr(int32_t aNamespaceID, nsIAtom* aName,
|
||||
// OnlyNotifySameValueSet call.
|
||||
nsAttrValueOrString value(aValue);
|
||||
nsAttrValue oldValue;
|
||||
bool oldValueSet;
|
||||
|
||||
if (OnlyNotifySameValueSet(aNamespaceID, aName, aPrefix, value, aNotify,
|
||||
oldValue, &modType, &hasListeners)) {
|
||||
oldValue, &modType, &hasListeners, &oldValueSet)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -2418,7 +2424,8 @@ Element::SetAttr(int32_t aNamespaceID, nsIAtom* aName,
|
||||
attrValue.SetTo(aValue);
|
||||
}
|
||||
|
||||
return SetAttrAndNotify(aNamespaceID, aName, aPrefix, oldValue,
|
||||
return SetAttrAndNotify(aNamespaceID, aName, aPrefix,
|
||||
oldValueSet ? &oldValue : nullptr,
|
||||
attrValue, modType, hasListeners, aNotify,
|
||||
kCallAfterSetAttr, document, updateBatch);
|
||||
}
|
||||
@ -2443,9 +2450,10 @@ Element::SetParsedAttr(int32_t aNamespaceID, nsIAtom* aName,
|
||||
bool hasListeners;
|
||||
nsAttrValueOrString value(aParsedValue);
|
||||
nsAttrValue oldValue;
|
||||
bool oldValueSet;
|
||||
|
||||
if (OnlyNotifySameValueSet(aNamespaceID, aName, aPrefix, value, aNotify,
|
||||
oldValue, &modType, &hasListeners)) {
|
||||
oldValue, &modType, &hasListeners, &oldValueSet)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -2459,7 +2467,8 @@ Element::SetParsedAttr(int32_t aNamespaceID, nsIAtom* aName,
|
||||
|
||||
nsIDocument* document = GetComposedDoc();
|
||||
mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
|
||||
return SetAttrAndNotify(aNamespaceID, aName, aPrefix, oldValue,
|
||||
return SetAttrAndNotify(aNamespaceID, aName, aPrefix,
|
||||
oldValueSet ? &oldValue : nullptr,
|
||||
aParsedValue, modType, hasListeners, aNotify,
|
||||
kCallAfterSetAttr, document, updateBatch);
|
||||
}
|
||||
@ -2468,7 +2477,7 @@ nsresult
|
||||
Element::SetAttrAndNotify(int32_t aNamespaceID,
|
||||
nsIAtom* aName,
|
||||
nsIAtom* aPrefix,
|
||||
const nsAttrValue& aOldValue,
|
||||
const nsAttrValue* aOldValue,
|
||||
nsAttrValue& aParsedValue,
|
||||
uint8_t aModType,
|
||||
bool aFireMutation,
|
||||
@ -2489,6 +2498,7 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
|
||||
|
||||
bool hadValidDir = false;
|
||||
bool hadDirAuto = false;
|
||||
bool oldValueSet;
|
||||
|
||||
if (aNamespaceID == kNameSpaceID_None) {
|
||||
if (aName == nsGkAtoms::dir) {
|
||||
@ -2499,8 +2509,8 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
|
||||
// XXXbz Perhaps we should push up the attribute mapping function
|
||||
// stuff to Element?
|
||||
if (!IsAttributeMapped(aName) ||
|
||||
!SetMappedAttribute(aName, aParsedValue, &rv)) {
|
||||
rv = mAttrsAndChildren.SetAndSwapAttr(aName, aParsedValue);
|
||||
!SetAndSwapMappedAttribute(aName, aParsedValue, &oldValueSet, &rv)) {
|
||||
rv = mAttrsAndChildren.SetAndSwapAttr(aName, aParsedValue, &oldValueSet);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -2509,14 +2519,24 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
|
||||
aNamespaceID,
|
||||
nsIDOMNode::ATTRIBUTE_NODE);
|
||||
|
||||
rv = mAttrsAndChildren.SetAndSwapAttr(ni, aParsedValue);
|
||||
rv = mAttrsAndChildren.SetAndSwapAttr(ni, aParsedValue, &oldValueSet);
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// If the old value owns its own data, we know it is OK to keep using it.
|
||||
const nsAttrValue* oldValue =
|
||||
aParsedValue.StoresOwnData() ? &aParsedValue : &aOldValue;
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
// oldValue will be null if there was no previously set value
|
||||
const nsAttrValue* oldValue;
|
||||
if (aParsedValue.StoresOwnData()) {
|
||||
if (oldValueSet) {
|
||||
oldValue = &aParsedValue;
|
||||
} else {
|
||||
oldValue = nullptr;
|
||||
}
|
||||
} else {
|
||||
// No need to conditionally assign null here. If there was no previously
|
||||
// set value for the attribute, aOldValue will already be null.
|
||||
oldValue = aOldValue;
|
||||
}
|
||||
|
||||
if (aComposedDocument || HasFlag(NODE_FORCE_XBL_BINDINGS)) {
|
||||
RefPtr<nsXBLBinding> binding = GetXBLBinding();
|
||||
@ -2527,7 +2547,14 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
|
||||
|
||||
nsIDocument* ownerDoc = OwnerDoc();
|
||||
if (ownerDoc && GetCustomElementData()) {
|
||||
nsCOMPtr<nsIAtom> oldValueAtom = oldValue->GetAsAtom();
|
||||
nsCOMPtr<nsIAtom> oldValueAtom;
|
||||
if (oldValue) {
|
||||
oldValueAtom = oldValue->GetAsAtom();
|
||||
} else {
|
||||
// If there is no old value, get the value of the uninitialized attribute
|
||||
// that was swapped with aParsedValue.
|
||||
oldValueAtom = aParsedValue.GetAsAtom();
|
||||
}
|
||||
nsCOMPtr<nsIAtom> newValueAtom = valueForAfterSetAttr.GetAsAtom();
|
||||
LifecycleCallbackArgs args = {
|
||||
nsDependentAtomString(aName),
|
||||
@ -2541,7 +2568,8 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
|
||||
}
|
||||
|
||||
if (aCallAfterSetAttr) {
|
||||
rv = AfterSetAttr(aNamespaceID, aName, &valueForAfterSetAttr, aNotify);
|
||||
rv = AfterSetAttr(aNamespaceID, aName, &valueForAfterSetAttr, oldValue,
|
||||
aNotify);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (aNamespaceID == kNameSpaceID_None && aName == nsGkAtoms::dir) {
|
||||
@ -2557,7 +2585,7 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
|
||||
// Callers only compute aOldValue under certain conditions which may not
|
||||
// be triggered by all nsIMutationObservers.
|
||||
nsNodeUtils::AttributeChanged(this, aNamespaceID, aName, aModType,
|
||||
oldValue == &aParsedValue ? &aParsedValue : nullptr);
|
||||
aParsedValue.StoresOwnData() ? &aParsedValue : nullptr);
|
||||
}
|
||||
|
||||
if (aFireMutation) {
|
||||
@ -2575,7 +2603,7 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
|
||||
if (!newValue.IsEmpty()) {
|
||||
mutation.mNewAttrValue = NS_Atomize(newValue);
|
||||
}
|
||||
if (!oldValue->IsEmptyString()) {
|
||||
if (oldValue && !oldValue->IsEmptyString()) {
|
||||
mutation.mPrevAttrValue = oldValue->GetAsAtom();
|
||||
}
|
||||
mutation.mAttrChange = aModType;
|
||||
@ -2618,9 +2646,10 @@ Element::ParseAttribute(int32_t aNamespaceID,
|
||||
}
|
||||
|
||||
bool
|
||||
Element::SetMappedAttribute(nsIAtom* aName,
|
||||
nsAttrValue& aValue,
|
||||
nsresult* aRetval)
|
||||
Element::SetAndSwapMappedAttribute(nsIAtom* aName,
|
||||
nsAttrValue& aValue,
|
||||
bool* aValueWasSet,
|
||||
nsresult* aRetval)
|
||||
{
|
||||
*aRetval = NS_OK;
|
||||
return false;
|
||||
@ -2775,7 +2804,7 @@ Element::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
ownerDoc, nsIDocument::eAttributeChanged, this, &args);
|
||||
}
|
||||
|
||||
rv = AfterSetAttr(aNameSpaceID, aName, nullptr, aNotify);
|
||||
rv = AfterSetAttr(aNameSpaceID, aName, nullptr, &oldValue, aNotify);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
UpdateState(aNotify);
|
||||
|
@ -631,25 +631,49 @@ public:
|
||||
* values will not actually be compared if we aren't notifying and we don't
|
||||
* have mutation listeners (in which case it's cheap to just return false
|
||||
* and let the caller go ahead and set the value).
|
||||
* @param aOldValue Set to the old value of the attribute, but only if there
|
||||
* are event listeners. If set, the type of aOldValue will be either
|
||||
* @param aOldValue [out] Set to the old value of the attribute, but only if
|
||||
* there are event listeners. If set, the type of aOldValue will be either
|
||||
* nsAttrValue::eString or nsAttrValue::eAtom.
|
||||
* @param aModType Set to nsIDOMMutationEvent::MODIFICATION or to
|
||||
* @param aModType [out] Set to nsIDOMMutationEvent::MODIFICATION or to
|
||||
* nsIDOMMutationEvent::ADDITION, but only if this helper returns true
|
||||
* @param aHasListeners Set to true if there are mutation event listeners
|
||||
* listening for NS_EVENT_BITS_MUTATION_ATTRMODIFIED
|
||||
* @param aHasListeners [out] Set to true if there are mutation event
|
||||
* listeners listening for NS_EVENT_BITS_MUTATION_ATTRMODIFIED
|
||||
* @param aOldValueSet [out] Indicates whether an old attribute value has been
|
||||
* stored in aOldValue. The bool will be set to true if a value was stored.
|
||||
*/
|
||||
bool MaybeCheckSameAttrVal(int32_t aNamespaceID, nsIAtom* aName,
|
||||
nsIAtom* aPrefix,
|
||||
const nsAttrValueOrString& aValue,
|
||||
bool aNotify, nsAttrValue& aOldValue,
|
||||
uint8_t* aModType, bool* aHasListeners);
|
||||
uint8_t* aModType, bool* aHasListeners,
|
||||
bool* aOldValueSet);
|
||||
|
||||
/**
|
||||
* Notifies mutation listeners if aNotify is true, there are mutation
|
||||
* listeners, and the attribute value is changing.
|
||||
*
|
||||
* @param aNamespaceID The namespace of the attribute
|
||||
* @param aName The local name of the attribute
|
||||
* @param aPrefix The prefix of the attribute
|
||||
* @param aValue The value that the attribute is being changed to
|
||||
* @param aNotify If true, mutation listeners will be notified if they exist
|
||||
* and the attribute value is changing
|
||||
* @param aOldValue [out] Set to the old value of the attribute, but only if
|
||||
* there are event listeners. If set, the type of aOldValue will be either
|
||||
* nsAttrValue::eString or nsAttrValue::eAtom.
|
||||
* @param aModType [out] Set to nsIDOMMutationEvent::MODIFICATION or to
|
||||
* nsIDOMMutationEvent::ADDITION, but only if this helper returns true
|
||||
* @param aHasListeners [out] Set to true if there are mutation event
|
||||
* listeners listening for NS_EVENT_BITS_MUTATION_ATTRMODIFIED
|
||||
* @param aOldValueSet [out] Indicates whether an old attribute value has been
|
||||
* stored in aOldValue. The bool will be set to true if a value was stored.
|
||||
*/
|
||||
bool OnlyNotifySameValueSet(int32_t aNamespaceID, nsIAtom* aName,
|
||||
nsIAtom* aPrefix,
|
||||
const nsAttrValueOrString& aValue,
|
||||
bool aNotify, nsAttrValue& aOldValue,
|
||||
uint8_t* aModType, bool* aHasListeners);
|
||||
uint8_t* aModType, bool* aHasListeners,
|
||||
bool* aOldValueSet);
|
||||
|
||||
virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName, nsIAtom* aPrefix,
|
||||
const nsAString& aValue, bool aNotify) override;
|
||||
@ -1352,7 +1376,10 @@ protected:
|
||||
* its current value) is !StoresOwnData() --- in which
|
||||
* case the current value is probably already useless.
|
||||
* If the current value is StoresOwnData() (or absent),
|
||||
* aOldValue will not be used.
|
||||
* aOldValue will not be used. aOldValue will only be set
|
||||
* in certain circumstances (there are mutation
|
||||
* listeners, element is a custom element, attribute was
|
||||
* not previously unset). Otherwise it will be null.
|
||||
* @param aParsedValue parsed new value of attribute. Replaced by the
|
||||
* old value of the attribute. This old value is only
|
||||
* useful if either it or the new value is StoresOwnData.
|
||||
@ -1366,7 +1393,7 @@ protected:
|
||||
nsresult SetAttrAndNotify(int32_t aNamespaceID,
|
||||
nsIAtom* aName,
|
||||
nsIAtom* aPrefix,
|
||||
const nsAttrValue& aOldValue,
|
||||
const nsAttrValue* aOldValue,
|
||||
nsAttrValue& aParsedValue,
|
||||
uint8_t aModType,
|
||||
bool aFireMutation,
|
||||
@ -1410,13 +1437,20 @@ protected:
|
||||
* returns true (the value of aRetval does not matter for that purpose).
|
||||
*
|
||||
* @param aName the name of the attribute
|
||||
* @param aValue the nsAttrValue to set
|
||||
* @param aValue the nsAttrValue to set. Will be swapped with the existing
|
||||
* value of the attribute if the attribute already exists.
|
||||
* @param [out] aValueWasSet If the attribute was not set previously,
|
||||
* aValue will be swapped with an empty attribute
|
||||
* and aValueWasSet will be set to false. Otherwise,
|
||||
* aValueWasSet will be set to true and aValue will
|
||||
* contain the previous value set.
|
||||
* @param [out] aRetval the nsresult status of the operation, if any.
|
||||
* @return true if the setting was attempted, false otherwise.
|
||||
*/
|
||||
virtual bool SetMappedAttribute(nsIAtom* aName,
|
||||
nsAttrValue& aValue,
|
||||
nsresult* aRetval);
|
||||
virtual bool SetAndSwapMappedAttribute(nsIAtom* aName,
|
||||
nsAttrValue& aValue,
|
||||
bool* aValueWasSet,
|
||||
nsresult* aRetval);
|
||||
|
||||
/**
|
||||
* Hook that is called by Element::SetAttr to allow subclasses to
|
||||
@ -1444,19 +1478,24 @@ protected:
|
||||
/**
|
||||
* Hook that is called by Element::SetAttr to allow subclasses to
|
||||
* deal with attribute sets. This will only be called after we have called
|
||||
* SetAndTakeAttr and AttributeChanged (that is, after we have actually set
|
||||
* the attr). It will always be called under a scriptblocker.
|
||||
* SetAndSwapAttr (that is, after we have actually set the attr). It will
|
||||
* always be called under a scriptblocker.
|
||||
*
|
||||
* @param aNamespaceID the namespace of the attr being set
|
||||
* @param aName the localname of the attribute being set
|
||||
* @param aValue the value it's being set to. If null, the attr is being
|
||||
* removed.
|
||||
* @param aOldValue the value that the attribute had previously. If null,
|
||||
* the attr was not previously set. This argument may not have the
|
||||
* correct value for SVG elements, or other cases in which the
|
||||
* attribute value doesn't store its own data
|
||||
* @param aNotify Whether we plan to notify document observers.
|
||||
*/
|
||||
// Note that this is inlined so that when subclasses call it it gets
|
||||
// inlined. Those calls don't go through a vtable.
|
||||
virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
|
||||
const nsAttrValue* aValue, bool aNotify)
|
||||
const nsAttrValue* aValue,
|
||||
const nsAttrValue* aOldValue, bool aNotify)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -389,12 +389,15 @@ nsAttrAndChildArray::AttrAt(uint32_t aPos) const
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsAttrAndChildArray::SetAndSwapAttr(nsIAtom* aLocalName, nsAttrValue& aValue)
|
||||
nsAttrAndChildArray::SetAndSwapAttr(nsIAtom* aLocalName, nsAttrValue& aValue,
|
||||
bool* aHadValue)
|
||||
{
|
||||
*aHadValue = false;
|
||||
uint32_t i, slotCount = AttrSlotCount();
|
||||
for (i = 0; i < slotCount && AttrSlotIsTaken(i); ++i) {
|
||||
if (ATTRS(mImpl)[i].mName.Equals(aLocalName)) {
|
||||
ATTRS(mImpl)[i].mValue.SwapValueWith(aValue);
|
||||
*aHadValue = true;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
@ -414,21 +417,22 @@ nsAttrAndChildArray::SetAndSwapAttr(nsIAtom* aLocalName, nsAttrValue& aValue)
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsAttrAndChildArray::SetAndSwapAttr(mozilla::dom::NodeInfo* aName, nsAttrValue& aValue)
|
||||
nsAttrAndChildArray::SetAndSwapAttr(mozilla::dom::NodeInfo* aName,
|
||||
nsAttrValue& aValue, bool* aHadValue)
|
||||
{
|
||||
int32_t namespaceID = aName->NamespaceID();
|
||||
nsIAtom* localName = aName->NameAtom();
|
||||
if (namespaceID == kNameSpaceID_None) {
|
||||
return SetAndSwapAttr(localName, aValue);
|
||||
return SetAndSwapAttr(localName, aValue, aHadValue);
|
||||
}
|
||||
|
||||
*aHadValue = false;
|
||||
uint32_t i, slotCount = AttrSlotCount();
|
||||
for (i = 0; i < slotCount && AttrSlotIsTaken(i); ++i) {
|
||||
if (ATTRS(mImpl)[i].mName.Equals(localName, namespaceID)) {
|
||||
ATTRS(mImpl)[i].mName.SetTo(aName);
|
||||
ATTRS(mImpl)[i].mValue.Reset();
|
||||
ATTRS(mImpl)[i].mValue.SwapValueWith(aValue);
|
||||
|
||||
*aHadValue = true;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
@ -583,10 +587,11 @@ nsAttrAndChildArray::IndexOfAttr(nsIAtom* aLocalName, int32_t aNamespaceID) cons
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsAttrAndChildArray::SetAndTakeMappedAttr(nsIAtom* aLocalName,
|
||||
nsAttrAndChildArray::SetAndSwapMappedAttr(nsIAtom* aLocalName,
|
||||
nsAttrValue& aValue,
|
||||
nsMappedAttributeElement* aContent,
|
||||
nsHTMLStyleSheet* aSheet)
|
||||
nsHTMLStyleSheet* aSheet,
|
||||
bool* aHadValue)
|
||||
{
|
||||
bool willAdd = true;
|
||||
if (mImpl && mImpl->mMappedAttrs) {
|
||||
@ -596,7 +601,7 @@ nsAttrAndChildArray::SetAndTakeMappedAttr(nsIAtom* aLocalName,
|
||||
RefPtr<nsMappedAttributes> mapped =
|
||||
GetModifiableMapped(aContent, aSheet, willAdd);
|
||||
|
||||
mapped->SetAndTakeAttr(aLocalName, aValue);
|
||||
mapped->SetAndSwapAttr(aLocalName, aValue, aHadValue);
|
||||
|
||||
return MakeMappedUnique(mapped);
|
||||
}
|
||||
|
@ -91,8 +91,13 @@ public:
|
||||
nsCaseTreatment aCaseSensitive) const;
|
||||
const nsAttrValue* AttrAt(uint32_t aPos) const;
|
||||
// SetAndSwapAttr swaps the current attribute value with aValue.
|
||||
nsresult SetAndSwapAttr(nsIAtom* aLocalName, nsAttrValue& aValue);
|
||||
nsresult SetAndSwapAttr(mozilla::dom::NodeInfo* aName, nsAttrValue& aValue);
|
||||
// If the attribute was unset, an empty value will be swapped into aValue
|
||||
// and aHadValue will be set to false. Otherwise, aHadValue will be set to
|
||||
// true.
|
||||
nsresult SetAndSwapAttr(nsIAtom* aLocalName, nsAttrValue& aValue,
|
||||
bool* aHadValue);
|
||||
nsresult SetAndSwapAttr(mozilla::dom::NodeInfo* aName, nsAttrValue& aValue,
|
||||
bool* aHadValue);
|
||||
|
||||
// Remove the attr at position aPos. The value of the attr is placed in
|
||||
// aValue; any value that was already in aValue is destroyed.
|
||||
@ -110,9 +115,14 @@ public:
|
||||
const nsAttrName* GetExistingAttrNameFromQName(const nsAString& aName) const;
|
||||
int32_t IndexOfAttr(nsIAtom* aLocalName, int32_t aNamespaceID = kNameSpaceID_None) const;
|
||||
|
||||
nsresult SetAndTakeMappedAttr(nsIAtom* aLocalName, nsAttrValue& aValue,
|
||||
// SetAndSwapMappedAttr swaps the current attribute value with aValue.
|
||||
// If the attribute was unset, an empty value will be swapped into aValue
|
||||
// and aHadValue will be set to false. Otherwise, aHadValue will be set to
|
||||
// true.
|
||||
nsresult SetAndSwapMappedAttr(nsIAtom* aLocalName, nsAttrValue& aValue,
|
||||
nsMappedAttributeElement* aContent,
|
||||
nsHTMLStyleSheet* aSheet);
|
||||
nsHTMLStyleSheet* aSheet,
|
||||
bool* aHadValue);
|
||||
nsresult SetMappedAttrStyleSheet(nsHTMLStyleSheet* aSheet) {
|
||||
if (!mImpl || !mImpl->mMappedAttrs) {
|
||||
return NS_OK;
|
||||
|
@ -21,13 +21,6 @@
|
||||
0x45f27d10, 0x987b, 0x11d2, \
|
||||
{0xbd, 0x40, 0x00, 0x10, 0x5a, 0xa4, 0x5e, 0x89} }
|
||||
|
||||
//The dom cannot provide the crypto or pkcs11 classes that
|
||||
//were used in older days, so if someone wants to provide
|
||||
//the service they must implement an object and give it
|
||||
//this class ID
|
||||
#define NS_CRYPTO_CONTRACTID "@mozilla.org/security/crypto;1"
|
||||
#define NS_PKCS11_CONTRACTID "@mozilla.org/security/pkcs11;1"
|
||||
|
||||
#define NS_XPATH_EVALUATOR_CONTRACTID "@mozilla.org/dom/xpath-evaluator;1"
|
||||
|
||||
#endif /* nsDOMCID_h__ */
|
||||
|
@ -2807,6 +2807,7 @@ nsDOMWindowUtils::GetUnanimatedComputedStyle(nsIDOMElement* aElement,
|
||||
RefPtr<nsComputedDOMStyle> computedStyle =
|
||||
NS_NewComputedDOMStyle(
|
||||
element, aPseudoElement, shell,
|
||||
nsComputedDOMStyle::StyleType::eAll,
|
||||
nsComputedDOMStyle::AnimationFlag::eWithoutAnimation);
|
||||
computedStyle->GetPropertyValue(propertyID, aResult);
|
||||
return NS_OK;
|
||||
|
@ -11062,13 +11062,46 @@ nsGlobalWindow::GetComputedStyle(Element& aElt, const nsAString& aPseudoElt,
|
||||
ErrorResult& aError)
|
||||
{
|
||||
MOZ_ASSERT(IsInnerWindow());
|
||||
FORWARD_TO_OUTER_OR_THROW(GetComputedStyleOuter,
|
||||
(aElt, aPseudoElt), aError, nullptr);
|
||||
return GetComputedStyleHelper(aElt, aPseudoElt, false, aError);
|
||||
}
|
||||
|
||||
already_AddRefed<nsICSSDeclaration>
|
||||
nsGlobalWindow::GetComputedStyleOuter(Element& aElt,
|
||||
const nsAString& aPseudoElt)
|
||||
nsGlobalWindow::GetDefaultComputedStyle(Element& aElt,
|
||||
const nsAString& aPseudoElt,
|
||||
ErrorResult& aError)
|
||||
{
|
||||
MOZ_ASSERT(IsInnerWindow());
|
||||
return GetComputedStyleHelper(aElt, aPseudoElt, true, aError);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsGlobalWindow::GetComputedStyleHelper(nsIDOMElement* aElt,
|
||||
const nsAString& aPseudoElt,
|
||||
bool aDefaultStylesOnly,
|
||||
nsIDOMCSSStyleDeclaration** aReturn)
|
||||
{
|
||||
MOZ_ASSERT(IsInnerWindow());
|
||||
|
||||
NS_ENSURE_ARG_POINTER(aReturn);
|
||||
*aReturn = nullptr;
|
||||
|
||||
nsCOMPtr<dom::Element> element = do_QueryInterface(aElt);
|
||||
if (!element) {
|
||||
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||
}
|
||||
|
||||
ErrorResult rv;
|
||||
nsCOMPtr<nsIDOMCSSStyleDeclaration> declaration =
|
||||
GetComputedStyleHelper(*element, aPseudoElt, aDefaultStylesOnly, rv);
|
||||
declaration.forget(aReturn);
|
||||
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
already_AddRefed<nsICSSDeclaration>
|
||||
nsGlobalWindow::GetComputedStyleHelperOuter(Element& aElt,
|
||||
const nsAString& aPseudoElt,
|
||||
bool aDefaultStylesOnly)
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(IsOuterWindow());
|
||||
|
||||
@ -11100,11 +11133,24 @@ nsGlobalWindow::GetComputedStyleOuter(Element& aElt,
|
||||
}
|
||||
|
||||
RefPtr<nsComputedDOMStyle> compStyle =
|
||||
NS_NewComputedDOMStyle(&aElt, aPseudoElt, presShell);
|
||||
NS_NewComputedDOMStyle(&aElt, aPseudoElt, presShell,
|
||||
aDefaultStylesOnly ? nsComputedDOMStyle::eDefaultOnly :
|
||||
nsComputedDOMStyle::eAll);
|
||||
|
||||
return compStyle.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<nsICSSDeclaration>
|
||||
nsGlobalWindow::GetComputedStyleHelper(Element& aElt,
|
||||
const nsAString& aPseudoElt,
|
||||
bool aDefaultStylesOnly,
|
||||
ErrorResult& aError)
|
||||
{
|
||||
FORWARD_TO_OUTER_OR_THROW(GetComputedStyleHelperOuter,
|
||||
(aElt, aPseudoElt, aDefaultStylesOnly),
|
||||
aError, nullptr);
|
||||
}
|
||||
|
||||
Storage*
|
||||
nsGlobalWindow::GetSessionStorage(ErrorResult& aError)
|
||||
{
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user