This commit is contained in:
Mike Conley 2013-04-24 10:54:12 -04:00
commit 2b35279a27
443 changed files with 12312 additions and 5525 deletions

View File

@ -39,12 +39,9 @@ this.AccessFu = {
Services.obs.addObserver(this, 'Accessibility:Settings', false);
} catch (x) {
// Not on Android
aWindow.addEventListener(
'ContentStart',
(function(event) {
let content = aWindow.shell.contentBrowser.contentWindow;
content.addEventListener('mozContentEvent', this, false, true);
}).bind(this), false);
if (Utils.MozBuildApp === 'b2g') {
aWindow.addEventListener('ContentStart', this, false);
}
}
try {
@ -58,6 +55,25 @@ this.AccessFu = {
this._enableOrDisable();
},
/**
* Shut down chrome-layer accessibility functionality from the outside.
*/
detach: function detach() {
// Avoid disabling twice.
if (this._enabled) {
this._disable();
}
if (Utils.MozBuildApp === 'mobile/android') {
Services.obs.removeObserver(this, 'Accessibility:Settings');
} else if (Utils.MozBuildApp === 'b2g') {
Utils.win.shell.contentBrowser.contentWindow.removeEventListener(
'mozContentEvent', this);
Utils.win.removeEventListener('ContentStart', this);
}
this.prefsBranch.removeObserver('activate', this);
Utils.uninit();
},
/**
* Start AccessFu mode, this primarily means controlling the virtual cursor
* with arrow keys.
@ -73,8 +89,10 @@ this.AccessFu = {
Logger.info('enable');
for each (let mm in Utils.AllMessageManagers)
for each (let mm in Utils.AllMessageManagers) {
this._addMessageListeners(mm);
this._loadFrameScript(mm);
}
// Add stylesheet
let stylesheetURL = 'chrome://global/content/accessibility/AccessFu.css';
@ -93,6 +111,11 @@ this.AccessFu = {
Services.obs.addObserver(this, 'Accessibility:Focus', false);
Utils.win.addEventListener('TabOpen', this);
Utils.win.addEventListener('TabSelect', this);
if (this.readyCallback) {
this.readyCallback();
delete this.readyCallback;
}
},
/**
@ -108,8 +131,10 @@ this.AccessFu = {
Utils.win.document.removeChild(this.stylesheet.get());
for each (let mm in Utils.AllMessageManagers)
for each (let mm in Utils.AllMessageManagers) {
mm.sendAsyncMessage('AccessFu:Stop');
this._removeMessageListeners(mm);
}
Input.stop();
Output.stop();
@ -122,6 +147,11 @@ this.AccessFu = {
Services.obs.removeObserver(this, 'Accessibility:NextObject');
Services.obs.removeObserver(this, 'Accessibility:PreviousObject');
Services.obs.removeObserver(this, 'Accessibility:Focus');
if (this.doneCallback) {
this.doneCallback();
delete this.doneCallback;
}
},
_enableOrDisable: function _enableOrDisable() {
@ -143,8 +173,10 @@ this.AccessFu = {
switch (aMessage.name) {
case 'AccessFu:Ready':
let mm = Utils.getMessageManager(aMessage.target);
mm.sendAsyncMessage('AccessFu:Start',
{method: 'start', buildApp: Utils.MozBuildApp});
if (this._enabled) {
mm.sendAsyncMessage('AccessFu:Start',
{method: 'start', buildApp: Utils.MozBuildApp});
}
break;
case 'AccessFu:Present':
this._output(aMessage.json, aMessage.target);
@ -169,12 +201,35 @@ this.AccessFu = {
},
_loadFrameScript: function _loadFrameScript(aMessageManager) {
if (this._processedMessageManagers.indexOf(aMessageManager) < 0) {
aMessageManager.loadFrameScript(
'chrome://global/content/accessibility/content-script.js', true);
this._processedMessageManagers.push(aMessageManager);
} else if (this._enabled) {
// If the content-script is already loaded and AccessFu is enabled,
// send an AccessFu:Start message.
aMessageManager.sendAsyncMessage('AccessFu:Start',
{method: 'start', buildApp: Utils.MozBuildApp});
}
},
_addMessageListeners: function _addMessageListeners(aMessageManager) {
aMessageManager.addMessageListener('AccessFu:Present', this);
aMessageManager.addMessageListener('AccessFu:Input', this);
aMessageManager.addMessageListener('AccessFu:Ready', this);
aMessageManager.
loadFrameScript(
'chrome://global/content/accessibility/content-script.js', true);
},
_removeMessageListeners: function _removeMessageListeners(aMessageManager) {
aMessageManager.removeMessageListener('AccessFu:Present', this);
aMessageManager.removeMessageListener('AccessFu:Input', this);
aMessageManager.removeMessageListener('AccessFu:Ready', this);
},
_handleMessageManager: function _handleMessageManager(aMessageManager) {
if (this._enabled) {
this._addMessageListeners(aMessageManager);
}
this._loadFrameScript(aMessageManager);
},
observe: function observe(aSubject, aTopic, aData) {
@ -207,8 +262,8 @@ this.AccessFu = {
break;
case 'remote-browser-frame-shown':
{
this._loadFrameScript(
aSubject.QueryInterface(Ci.nsIFrameLoader).messageManager);
let mm = aSubject.QueryInterface(Ci.nsIFrameLoader).messageManager;
this._handleMessageManager(mm);
break;
}
}
@ -216,6 +271,12 @@ this.AccessFu = {
handleEvent: function handleEvent(aEvent) {
switch (aEvent.type) {
case 'ContentStart':
{
Utils.win.shell.contentBrowser.contentWindow.addEventListener(
'mozContentEvent', this, false, true);
break;
}
case 'mozContentEvent':
{
if (aEvent.detail.type == 'accessibility-screenreader') {
@ -226,7 +287,8 @@ this.AccessFu = {
}
case 'TabOpen':
{
this._loadFrameScript(Utils.getMessageManager(aEvent.target));
let mm = Utils.getMessageManager(aEvent.target);
this._handleMessageManager(mm);
break;
}
case 'TabSelect':
@ -255,7 +317,11 @@ this.AccessFu = {
_enabled: false,
// Layerview is focused
_focused: false
_focused: false,
// Keep track of message managers tha already have a 'content-script.js'
// injected.
_processedMessageManagers: []
};
var Output = {

View File

@ -38,6 +38,10 @@ this.EventManager = {
},
stop: function stop() {
if (!this._started) {
return;
}
Logger.info('EventManager.stop', Utils.MozBuildApp);
Services.obs.removeObserver(this, 'accessible-event');
this._started = false;
},

View File

@ -29,6 +29,13 @@ this.Utils = {
this._win = Cu.getWeakReference(aWindow);
},
uninit: function Utils_uninit() {
if (!this._win) {
return;
}
delete this._win;
},
get win() {
return this._win.get();
},
@ -178,13 +185,25 @@ this.Logger = {
logLevel: 1, // INFO;
test: false,
log: function log(aLogLevel) {
if (aLogLevel < this.logLevel)
return;
let message = Array.prototype.slice.call(arguments, 1).join(' ');
dump('[' + Utils.ScriptName + '] ' +
this._LEVEL_NAMES[aLogLevel] +' ' + message + '\n');
message = '[' + Utils.ScriptName + '] ' + this._LEVEL_NAMES[aLogLevel] +
' ' + message + '\n';
dump(message);
// Note: used for testing purposes. If |this.test| is true, also log to
// the console service.
if (this.test) {
try {
Services.console.logStringMessage(message);
} catch (ex) {
// There was an exception logging to the console service.
}
}
},
info: function info() {

View File

@ -216,16 +216,17 @@ function scroll(aMessage) {
}
}
addMessageListener('AccessFu:VirtualCursor', virtualCursorControl);
addMessageListener('AccessFu:Activate', activateCurrent);
addMessageListener('AccessFu:Scroll', scroll);
addMessageListener(
'AccessFu:Start',
function(m) {
Logger.debug('AccessFu:Start');
if (m.json.buildApp)
Utils.MozBuildApp = m.json.buildApp;
addMessageListener('AccessFu:VirtualCursor', virtualCursorControl);
addMessageListener('AccessFu:Activate', activateCurrent);
addMessageListener('AccessFu:Scroll', scroll);
EventManager.start(
function sendMessage(aName, aDetails) {
sendAsyncMessage(aName, aDetails);
@ -247,6 +248,10 @@ addMessageListener(
function(m) {
Logger.debug('AccessFu:Stop');
removeMessageListener('AccessFu:VirtualCursor', virtualCursorControl);
removeMessageListener('AccessFu:Activate', activateCurrent);
removeMessageListener('AccessFu:Scroll', scroll);
EventManager.stop();
docShell.QueryInterface(Ci.nsIInterfaceRequestor).

View File

@ -9,8 +9,9 @@
#include "nsCOMPtr.h"
#include "nsObjCExceptions.h"
#include "nsIFrame.h"
#include "nsView.h"
#include "nsIWidget.h"
#include "nsViewManager.h"
using namespace mozilla::a11y;

View File

@ -661,6 +661,23 @@ function shortenString(aString, aMaxLength)
aString.substring(aString.length - trimOffset, aString.length);
}
////////////////////////////////////////////////////////////////////////////////
// General Utils
////////////////////////////////////////////////////////////////////////////////
/**
* Return main chrome window (crosses chrome boundary)
*/
function getMainChromeWindow(aWindow)
{
return aWindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIWebNavigation)
.QueryInterface(Components.interfaces.nsIDocShellTreeItem)
.rootTreeItem
.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIDOMWindow);
}
////////////////////////////////////////////////////////////////////////////////
// Private
////////////////////////////////////////////////////////////////////////////////

View File

@ -12,6 +12,8 @@ relativesrcdir = @relativesrcdir@
include $(DEPTH)/config/autoconf.mk
MOCHITEST_A11Y_FILES =\
jsatcommon.js \
test_alive.html \
test_utterance_order.html \
$(NULL)

View File

@ -0,0 +1,91 @@
// A common module to run tests on the AccessFu module
/**
* A global variable holding an array of test functions.
*/
var gTestFuncs = [];
/**
* A global Iterator for the array of test functions.
*/
var gIterator;
Components.utils.import('resource://gre/modules/Services.jsm');
Components.utils.import("resource://gre/modules/accessibility/Utils.jsm");
Components.utils.import("resource://gre/modules/accessibility/EventManager.jsm");
var AccessFuTest = {
addFunc: function AccessFuTest_addFunc(aFunc) {
if (aFunc) {
gTestFuncs.push(aFunc);
}
},
_waitForExplicitFinish: false,
waitForExplicitFinish: function AccessFuTest_waitForExplicitFinish() {
this._waitForExplicitFinish = true;
},
finish: function AccessFuTest_finish() {
// Disable the console service logging.
Logger.test = false;
AccessFu.doneCallback = function doneCallback() {
// This is being called once AccessFu has been shut down.
// Detach AccessFu from everything it attached itself to.
AccessFu.detach();
// and finish the test run.
SimpleTest.finish();
};
// Tear down accessibility and make AccessFu stop.
SpecialPowers.setIntPref("accessibility.accessfu.activate", 0);
},
nextTest: function AccessFuTest_nextTest() {
var testFunc;
try {
// Get the next test function from the iterator. If none left,
// StopIteration exception is thrown.
testFunc = gIterator.next()[1];
} catch (ex) {
// StopIteration exception.
this.finish();
return;
}
testFunc();
},
runTests: function AccessFuTest_runTests() {
if (gTestFuncs.length === 0) {
ok(false, "No tests specified!");
simpleTest.finish();
return;
}
// Create an Iterator for gTestFuncs array.
gIterator = Iterator(gTestFuncs);
// Start AccessFu and put it in stand-by.
Components.utils.import("resource://gre/modules/accessibility/AccessFu.jsm");
AccessFu.attach(getMainChromeWindow(window));
AccessFu.readyCallback = function readyCallback() {
// Enable logging to the console service.
Logger.test = true;
// This is being called once accessibility has been turned on.
if (AccessFuTest._waitForExplicitFinish) {
// Run all test functions asynchronously.
AccessFuTest.nextTest();
} else {
// Run all test functions synchronously.
[testFunc() for (testFunc of gTestFuncs)];
AccessFuTest.finish();
}
};
// Invoke the whole thing.
SpecialPowers.setIntPref("accessibility.accessfu.activate", 1);
}
};

View File

@ -0,0 +1,81 @@
<html>
<head>
<title>AccessFu test for enabling</title>
<link rel="stylesheet" type="text/css"
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript"
src="../common.js"></script>
<script type="application/javascript"
src="./jsatcommon.js"></script>
<script type="application/javascript">
function confirmAccessFuStart() {
ok(AccessFu._enabled, "AccessFu was started and enabled.");
AccessFuTest.nextTest();
}
function makeEventManagerListener(waitForMessage, callback) {
return {
observe: function observe(aMessage) {
// Ignore unexpected messages.
if (!(aMessage instanceof Components.interfaces.nsIConsoleMessage)) {
return;
}
if (aMessage.message.indexOf(waitForMessage) < 0) {
return;
}
Services.console.unregisterListener(this);
callback();
}
};
}
function testEventManagerStartStop() {
// Firs listen for initial 'EventManager.start' and disable AccessFu.
var initialStartListener = makeEventManagerListener("EventManager.start",
function () {
ok(EventManager._started, "EventManager was started.");
Services.console.registerListener(stopListener);
AccessFu._disable();
});
// Listen for 'EventManager.stop' and enable AccessFu again.
var stopListener = makeEventManagerListener("EventManager.stop",
function () {
isnot(EventManager._started, true, "EventManager was stopped.");
Services.console.registerListener(finalStartListener);
AccessFu._enable();
});
// Make sure EventManager is started again.
var finalStartListener = makeEventManagerListener("EventManager.start",
function () {
ok(EventManager._started, "EventManager was started again.");
AccessFuTest.finish();
});
Services.console.registerListener(initialStartListener);
}
function doTest() {
AccessFuTest.addFunc(confirmAccessFuStart);
AccessFuTest.addFunc(testEventManagerStartStop);
AccessFuTest.waitForExplicitFinish();
AccessFuTest.runTests(); // Will call SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTest);
</script>
</head>
<body>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=811307"
title="[AccessFu] Add mochitest for enabling">
Mozilla Bug 811307
</a>
</body>
</html>

View File

@ -91,7 +91,7 @@ DirectoryProvider.prototype = {
if (!Services.volumeService) {
return false;
}
let volume = Services.volumeService.getVolumeByPath(volumePath);
let volume = Services.volumeService.createOrGetVolumeByPath(volumePath);
if (!volume || volume.state !== Ci.nsIVolume.STATE_MOUNTED) {
return false;
}
@ -201,7 +201,7 @@ DirectoryProvider.prototype = {
}
if (Services.volumeService) {
let extVolume = Services.volumeService.getVolumeByPath(path);
let extVolume = Services.volumeService.createOrGetVolumeByPath(path);
if (!extVolume) {
path = LOCAL_DIR;
}

View File

@ -1,8 +1,8 @@
{
"config_version": 1,
"config_version": 2,
"tooltool_manifest": "releng-pandaboard.tt",
"mock_target": "mozilla-centos6-i386",
"mock_packages": ["ccache", "make", "bison", "flex", "gcc", "g++", "mpfr", "zlib-devel", "ncurses-devel", "zip", "autoconf213", "glibc-static", "perl-Digest-SHA", "wget", "alsa-lib", "atk", "cairo", "dbus-glib", "fontconfig", "freetype", "glib2", "gtk2", "libXRender", "libXt", "pango", "mozilla-python27-mercurial", "openssh-clients", "nss-devel"],
"mock_packages": ["ccache", "make", "bison", "flex", "gcc", "g++", "mpfr", "zlib-devel", "ncurses-devel", "zip", "autoconf213", "glibc-static", "perl-Digest-SHA", "wget", "alsa-lib", "atk", "cairo", "dbus-glib", "fontconfig", "freetype", "glib2", "gtk2", "libXRender", "libXt", "pango", "mozilla-python27-mercurial", "openssh-clients", "nss-devel", "git"],
"mock_files": [["/home/cltbld/.ssh", "/home/mock_mozilla/.ssh"]],
"build_targets": ["boottarball", "systemtarball", "userdatatarball", "package-tests"],
"upload_files": [
@ -12,6 +12,7 @@
"{srcdir}/b2g/config/panda/README",
"{workdir}/sources.xml"
],
"b2g_manifest": "pandaboard.xml",
"gecko_l10n_root": "http://hg.mozilla.org/l10n-central",
"gaia": {
"vcs": "hgtool",

View File

@ -1,11 +1,5 @@
[
{
"size": 678265436,
"digest": "36d05d77831be476e639095c04f25557171bb61c6764b2f6a49e253471aac8855adff17989089f1dce790d7e860c91d0b1d0f268fbc8fc661fca0c83ca7d65f5",
"algorithm": "sha512",
"filename": "gonk.tar.xz"
},
{
"size": 2116507,
"digest": "be67a012963a5c162834f9fcb989bcebd2d047dcb4e17ee23031b694dcf7cdfd6d7a6545d7a1f5e7293b6d24415403972f4ea1ab8c6c78fefcabfaf3f6875214",
"algorithm": "sha512",

View File

@ -1,8 +1,8 @@
{
"config_version": 1,
"config_version": 2,
"tooltool_manifest": "releng-unagi.tt",
"mock_target": "mozilla-centos6-i386",
"mock_packages": ["ccache", "make", "bison", "flex", "gcc", "g++", "mpfr", "zlib-devel", "ncurses-devel", "zip", "autoconf213", "glibc-static", "perl-Digest-SHA", "wget", "alsa-lib", "atk", "cairo", "dbus-glib", "fontconfig", "freetype", "glib2", "gtk2", "libXRender", "libXt", "pango", "mozilla-python27-mercurial", "openssh-clients", "nss-devel", "java-1.6.0-openjdk-devel"],
"mock_packages": ["ccache", "make", "bison", "flex", "gcc", "g++", "mpfr", "zlib-devel", "ncurses-devel", "zip", "autoconf213", "glibc-static", "perl-Digest-SHA", "wget", "alsa-lib", "atk", "cairo", "dbus-glib", "fontconfig", "freetype", "glib2", "gtk2", "libXRender", "libXt", "pango", "mozilla-python27-mercurial", "openssh-clients", "nss-devel", "java-1.6.0-openjdk-devel", "git"],
"mock_files": [["/home/cltbld/.ssh", "/home/mock_mozilla/.ssh"]],
"build_targets": [],
"upload_files": [
@ -10,6 +10,8 @@
"{objdir}/dist/b2g-*.crashreporter-symbols.zip",
"{workdir}/sources.xml"
],
"b2g_manifest": "unagi.xml",
"additional_source_tarballs": ["backup-unagi.tar.bz2"],
"zip_files": [
["{workdir}/out/target/product/unagi/*.img", "out/target/product/unagi/"],
["{workdir}/boot.img", "out/target/product/unagi/"],

View File

@ -1,9 +1,15 @@
[
{
"size": 833424196,
"digest": "f47e040bac9a0e872dc7289993093c3d1be1befbab2d7caad17645a222147398573aa563f5485ca00ccfbf8c3cefc12d09fe91bf10499baa6d373e80de6bdd70",
"size": 84128995,
"digest": "b833dae269b02fec9a0549f467a78717a7b2bf96512caafa3736efe72610b50c5d2073b68afcdb2fea0779e2007e5ec9efc25b14d94f06e194e4ac66d49c676e",
"algorithm": "sha512",
"filename": "gonk.tar.xz"
"filename": "backup-unagi.tar.bz2"
},
{
"size": 1570553,
"digest": "ea03de74df73b05e939c314cd15c54aac7b5488a407b7cc4f5f263f3049a1f69642c567dd35c43d0bc3f0d599d0385a26ab2dd947a6b18f9044e4918b382eea7",
"algorithm": "sha512",
"filename": "Adreno200-AU_LINUX_ANDROID_ICS_CHOCO_CS.04.00.03.06.001.zip"
},
{
"size": 8622080,

View File

@ -1082,6 +1082,7 @@ pref("devtools.netmonitor.enabled", true);
// The default Network Monitor UI settings
pref("devtools.netmonitor.panes-network-details-width", 450);
pref("devtools.netmonitor.panes-network-details-height", 450);
// Enable the Tilt inspector
pref("devtools.tilt.enabled", true);

View File

@ -2,6 +2,8 @@
# 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/.
////////////////////////////////////////////////////////////////////////////////
//// StarUI
var StarUI = {
_itemId: -1,
@ -218,10 +220,6 @@ var StarUI = {
gEditItemOverlay.uninitPanel(true);
},
editButtonCommand: function SU_editButtonCommand() {
this.showEditBookmarkPopup();
},
cancelButtonOnCommand: function SU_cancelButtonOnCommand() {
this._actionOnHide = "cancel";
this.panel.hidePopup();
@ -241,6 +239,9 @@ var StarUI = {
}
}
////////////////////////////////////////////////////////////////////////////////
//// PlacesCommandHook
var PlacesCommandHook = {
/**
* Adds a bookmark to the page loaded in the given browser.
@ -293,28 +294,37 @@ var PlacesCommandHook = {
PlacesUtils.bookmarks.DEFAULT_INDEX,
title, null, [descAnno]);
PlacesUtils.transactionManager.doTransaction(txn);
itemId = txn.item.id;
// Set the character-set
if (charset && !PrivateBrowsingUtils.isWindowPrivate(aBrowser.contentWindow))
PlacesUtils.setCharsetForURI(uri, charset);
itemId = PlacesUtils.getMostRecentBookmarkForURI(uri);
}
// Revert the contents of the location bar
if (gURLBar)
gURLBar.handleRevert();
// dock the panel to the star icon when possible, otherwise dock
// it to the content area
if (aBrowser.contentWindow == window.content) {
var starIcon = aBrowser.ownerDocument.getElementById("star-button");
if (starIcon && isElementVisible(starIcon)) {
if (aShowEditUI)
StarUI.showEditBookmarkPopup(itemId, starIcon, "bottomcenter topright");
return;
}
// If it was not requested to open directly in "edit" mode, we are done.
if (!aShowEditUI)
return;
// Try to dock the panel to:
// 1. the bookmarks menu button
// 2. the page-proxy-favicon
// 3. the content area
if (BookmarksMenuButton.anchor) {
StarUI.showEditBookmarkPopup(itemId, BookmarksMenuButton.anchor,
"bottomcenter topright");
return;
}
StarUI.showEditBookmarkPopup(itemId, aBrowser, "overlap");
let pageProxyFavicon = document.getElementById("page-proxy-favicon");
if (isElementVisible(pageProxyFavicon)) {
StarUI.showEditBookmarkPopup(itemId, pageProxyFavicon,
"bottomcenter topright");
} else {
StarUI.showEditBookmarkPopup(itemId, aBrowser, "overlap");
}
},
/**
@ -460,6 +470,9 @@ var PlacesCommandHook = {
}
};
////////////////////////////////////////////////////////////////////////////////
//// HistoryMenu
// View for the history menu.
function HistoryMenu(aPopupShowingEvent) {
// Workaround for Bug 610187. The sidebar does not include all the Places
@ -686,6 +699,9 @@ HistoryMenu.prototype = {
}
};
////////////////////////////////////////////////////////////////////////////////
//// BookmarksEventHandler
/**
* Functions for handling events in the Bookmarks Toolbar and menu.
*/
@ -811,6 +827,8 @@ var BookmarksEventHandler = {
}
};
////////////////////////////////////////////////////////////////////////////////
//// PlacesMenuDNDHandler
// Handles special drag and drop functionality for Places menus that are not
// part of a Places view (e.g. the bookmarks menu in the menubar).
@ -829,26 +847,37 @@ var PlacesMenuDNDHandler = {
if (!this._isStaticContainer(event.target))
return;
let popup = event.target.lastChild;
if (this._loadTimer || popup.state === "showing" || popup.state === "open")
return;
this._loadTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
this._loadTimer.initWithCallback(function() {
PlacesMenuDNDHandler._loadTimer = null;
event.target.lastChild.setAttribute("autoopened", "true");
event.target.lastChild.showPopup(event.target.lastChild);
this._loadTimer.initWithCallback(() => {
this._loadTimer = null;
popup.setAttribute("autoopened", "true");
popup.showPopup(popup);
}, this._springLoadDelay, Ci.nsITimer.TYPE_ONE_SHOT);
event.preventDefault();
event.stopPropagation();
},
/**
* Handles dragexit on the <menu> element.
* Handles dragleave on the <menu> element.
* @returns true if the element is a container element (menu or
* menu-toolbarbutton), false otherwise.
*/
onDragExit: function PMDH_onDragExit(event) {
onDragLeave: function PMDH_onDragLeave(event) {
// Handle menu-button separate targets.
if (event.relatedTarget === event.currentTarget ||
event.relatedTarget.parentNode === event.currentTarget)
return;
// Closing menus in a Places popup is handled by the view itself.
if (!this._isStaticContainer(event.target))
return;
let popup = event.target.lastChild;
if (this._loadTimer) {
this._loadTimer.cancel();
this._loadTimer = null;
@ -862,10 +891,9 @@ var PlacesMenuDNDHandler = {
inHierarchy = node == event.target;
node = node.parentNode;
}
if (!inHierarchy && event.target.lastChild &&
event.target.lastChild.hasAttribute("autoopened")) {
event.target.lastChild.removeAttribute("autoopened");
event.target.lastChild.hidePopup();
if (!inHierarchy && popup && popup.hasAttribute("autoopened")) {
popup.removeAttribute("autoopened");
popup.hidePopup();
}
}, this._springLoadDelay, Ci.nsITimer.TYPE_ONE_SHOT);
},
@ -878,7 +906,8 @@ var PlacesMenuDNDHandler = {
_isStaticContainer: function PMDH__isContainer(node) {
let isMenu = node.localName == "menu" ||
(node.localName == "toolbarbutton" &&
node.getAttribute("type") == "menu");
(node.getAttribute("type") == "menu" ||
node.getAttribute("type") == "menu-button"));
let isStatic = !("_placesNode" in node) && node.lastChild &&
node.lastChild.hasAttribute("placespopup") &&
!node.parentNode.hasAttribute("placespopup");
@ -915,179 +944,13 @@ var PlacesMenuDNDHandler = {
}
};
////////////////////////////////////////////////////////////////////////////////
//// PlacesToolbarHelper
var PlacesStarButton = {
_hasBookmarksObserver: false,
uninit: function PSB_uninit()
{
if (this._hasBookmarksObserver) {
PlacesUtils.removeLazyBookmarkObserver(this);
}
if (this._pendingStmt) {
this._pendingStmt.cancel();
delete this._pendingStmt;
}
},
QueryInterface: XPCOMUtils.generateQI([
Ci.nsINavBookmarkObserver
]),
get _starredTooltip()
{
delete this._starredTooltip;
return this._starredTooltip =
gNavigatorBundle.getString("starButtonOn.tooltip");
},
get _unstarredTooltip()
{
delete this._unstarredTooltip;
return this._unstarredTooltip =
gNavigatorBundle.getString("starButtonOff.tooltip");
},
updateState: function PSB_updateState()
{
this._starIcon = document.getElementById("star-button");
if (!this._starIcon || (this._uri && gBrowser.currentURI.equals(this._uri))) {
return;
}
// Reset tracked values.
this._uri = gBrowser.currentURI;
this._itemIds = [];
if (this._pendingStmt) {
this._pendingStmt.cancel();
delete this._pendingStmt;
}
// We can load about:blank before the actual page, but there is no point in handling that page.
if (isBlankPageURL(this._uri.spec)) {
return;
}
this._pendingStmt = PlacesUtils.asyncGetBookmarkIds(this._uri, function (aItemIds, aURI) {
// Safety check that the bookmarked URI equals the tracked one.
if (!aURI.equals(this._uri)) {
Components.utils.reportError("PlacesStarButton did not receive current URI");
return;
}
// It's possible that onItemAdded gets called before the async statement
// calls back. For such an edge case, retain all unique entries from both
// arrays.
this._itemIds = this._itemIds.filter(
function (id) aItemIds.indexOf(id) == -1
).concat(aItemIds);
this._updateStateInternal();
// Start observing bookmarks if needed.
if (!this._hasBookmarksObserver) {
try {
PlacesUtils.addLazyBookmarkObserver(this);
this._hasBookmarksObserver = true;
} catch(ex) {
Components.utils.reportError("PlacesStarButton failed adding a bookmarks observer: " + ex);
}
}
delete this._pendingStmt;
}, this);
},
_updateStateInternal: function PSB__updateStateInternal()
{
if (!this._starIcon) {
return;
}
if (this._itemIds.length > 0) {
this._starIcon.setAttribute("starred", "true");
this._starIcon.setAttribute("tooltiptext", this._starredTooltip);
}
else {
this._starIcon.removeAttribute("starred");
this._starIcon.setAttribute("tooltiptext", this._unstarredTooltip);
}
},
onClick: function PSB_onClick(aEvent)
{
// Ignore clicks on the star while we update its state.
if (aEvent.button == 0 && !this._pendingStmt) {
PlacesCommandHook.bookmarkCurrentPage(this._itemIds.length > 0);
}
// Don't bubble to the textbox, to avoid unwanted selection of the address.
aEvent.stopPropagation();
},
// nsINavBookmarkObserver
onItemAdded:
function PSB_onItemAdded(aItemId, aFolder, aIndex, aItemType, aURI)
{
if (!this._starIcon) {
return;
}
if (aURI && aURI.equals(this._uri)) {
// If a new bookmark has been added to the tracked uri, register it.
if (this._itemIds.indexOf(aItemId) == -1) {
this._itemIds.push(aItemId);
this._updateStateInternal();
}
}
},
onItemRemoved:
function PSB_onItemRemoved(aItemId, aFolder, aIndex, aItemType)
{
if (!this._starIcon) {
return;
}
let index = this._itemIds.indexOf(aItemId);
// If one of the tracked bookmarks has been removed, unregister it.
if (index != -1) {
this._itemIds.splice(index, 1);
this._updateStateInternal();
}
},
onItemChanged:
function PSB_onItemChanged(aItemId, aProperty, aIsAnnotationProperty,
aNewValue, aLastModified, aItemType)
{
if (!this._starIcon) {
return;
}
if (aProperty == "uri") {
let index = this._itemIds.indexOf(aItemId);
// If the changed bookmark was tracked, check if it is now pointing to
// a different uri and unregister it.
if (index != -1 && aNewValue != this._uri.spec) {
this._itemIds.splice(index, 1);
this._updateStateInternal();
}
// If another bookmark is now pointing to the tracked uri, register it.
else if (index == -1 && aNewValue == this._uri.spec) {
this._itemIds.push(aItemId);
this._updateStateInternal();
}
}
},
onBeginUpdateBatch: function () {},
onEndUpdateBatch: function () {},
onItemVisited: function () {},
onItemMoved: function () {}
};
// This object handles the initialization and uninitialization of the bookmarks
// toolbar. updateState is called when the browser window is opened and
// after closing the toolbar customization dialog.
/**
* This object handles the initialization and uninitialization of the bookmarks
* toolbar.
*/
let PlacesToolbarHelper = {
_place: "place:folder=TOOLBAR",
@ -1127,58 +990,95 @@ let PlacesToolbarHelper = {
}
};
////////////////////////////////////////////////////////////////////////////////
//// BookmarksMenuButton
// Handles the bookmarks menu button shown when the main menubar is hidden.
/**
* Handles the bookmarks menu-button in the toolbar.
*/
let BookmarksMenuButton = {
get button() {
return document.getElementById("bookmarks-menu-button");
if (!this._button) {
this._button = document.getElementById("bookmarks-menu-button");
}
return this._button;
},
get buttonContainer() {
return document.getElementById("bookmarks-menu-button-container");
get star() {
if (!this._star && this.button) {
this._star = document.getAnonymousElementByAttribute(this.button,
"anonid",
"button");
}
return this._star;
},
get personalToolbar() {
delete this.personalToolbar;
return this.personalToolbar = document.getElementById("PersonalToolbar");
get anchor() {
if (!this._anchor && this.star && isElementVisible(this.star)) {
// Anchor to the icon, so the panel looks more natural.
this._anchor = document.getAnonymousElementByAttribute(this.star,
"class",
"toolbarbutton-icon");
}
return this._anchor;
},
get bookmarksToolbarItem() {
return document.getElementById("personal-bookmarks");
STATUS_UPDATING: -1,
STATUS_UNSTARRED: 0,
STATUS_STARRED: 1,
get status() {
if (this._pendingStmt)
return this.STATUS_UPDATING;
return this.button &&
this.button.hasAttribute("starred") ? this.STATUS_STARRED
: this.STATUS_UNSTARRED;
},
init: function BMB_init() {
this.updatePosition();
// Any other stuff that does not regard the button itself should be
// handled in the onPopupShowing handler, so it does not hit Ts.
get _starredTooltip()
{
delete this._starredTooltip;
return this._starredTooltip =
gNavigatorBundle.getString("starButtonOn.tooltip");
},
get _unstarredTooltip()
{
delete this._unstarredTooltip;
return this._unstarredTooltip =
gNavigatorBundle.getString("starButtonOff.tooltip");
},
/**
* The popup contents must be updated when the user customizes the UI, or
* changes the personal toolbar collapsed status. In such a case, any needed
* change should be handled in the popupshowing helper, for performance
* reasons.
*/
_popupNeedsUpdate: true,
onToolbarVisibilityChange: function BMB_onToolbarVisibilityChange() {
this._popupNeedsUpdate = true;
},
_popupNeedsUpdate: {},
onPopupShowing: function BMB_onPopupShowing(event) {
// Don't handle events for submenus.
if (event.target != event.currentTarget)
return;
let popup = event.target;
let needsUpdate = this._popupNeedsUpdate[popup.id];
// Check if popup contents need to be updated. Note that if needsUpdate is
// undefined we have never seen the popup, thus it should be updated.
if (needsUpdate === false)
if (!this._popupNeedsUpdate)
return;
this._popupNeedsUpdate[popup.id] = false;
this._popupNeedsUpdate = false;
function getPlacesAnonymousElement(aAnonId)
document.getAnonymousElementByAttribute(popup.parentNode,
"placesanonid",
aAnonId);
let popup = event.target;
let getPlacesAnonymousElement =
aAnonId => document.getAnonymousElementByAttribute(popup.parentNode,
"placesanonid",
aAnonId);
let viewToolbarMenuitem = getPlacesAnonymousElement("view-toolbar");
if (viewToolbarMenuitem) {
// Update View bookmarks toolbar checkbox menuitem.
viewToolbarMenuitem.setAttribute("checked",
!this.personalToolbar.collapsed);
let personalToolbar = document.getElementById("PersonalToolbar");
viewToolbarMenuitem.setAttribute("checked", !personalToolbar.collapsed);
}
let toolbarMenuitem = getPlacesAnonymousElement("toolbar-autohide");
@ -1186,68 +1086,44 @@ let BookmarksMenuButton = {
// If bookmarks items are visible, hide Bookmarks Toolbar menu and the
// separator after it.
toolbarMenuitem.collapsed = toolbarMenuitem.nextSibling.collapsed =
isElementVisible(this.bookmarksToolbarItem);
isElementVisible(document.getElementById("personal-bookmarks"));
}
},
updatePosition: function BMB_updatePosition() {
// Popups will have to be updated when the user customizes the UI, or
// changes personal toolbar collapsed status. Both of those location call
// updatePosition(), so this is the only point asking for popup updates.
for (let popupId in this._popupNeedsUpdate) {
this._popupNeedsUpdate[popupId] = true;
/**
* Handles star styling based on page proxy state changes.
*/
onPageProxyStateChanged: function BMB_onPageProxyStateChanged(aState) {
if (!this.star) {
return;
}
let button = this.button;
if (!button)
return;
// If the toolbar containing bookmarks is visible, we want to move the
// button to bookmarksToolbarItem.
let bookmarksToolbarItem = this.bookmarksToolbarItem;
let bookmarksOnVisibleToolbar = bookmarksToolbarItem &&
!bookmarksToolbarItem.parentNode.collapsed &&
bookmarksToolbarItem.parentNode.getAttribute("autohide") != "true";
// If the container has been moved by the user to the toolbar containing
// bookmarks, we want to preserve the desired position.
let container = this.buttonContainer;
let containerNearBookmarks = container && bookmarksToolbarItem &&
container.parentNode == bookmarksToolbarItem.parentNode;
if (bookmarksOnVisibleToolbar && !containerNearBookmarks) {
if (button.parentNode != bookmarksToolbarItem) {
this._uninitView();
bookmarksToolbarItem.appendChild(button);
}
if (aState == "invalid") {
this.star.setAttribute("disabled", "true");
this.button.removeAttribute("starred");
}
else {
if (container && button.parentNode != container) {
this._uninitView();
container.appendChild(button);
}
this.star.removeAttribute("disabled");
}
this._updateStyle();
},
_updateStyle: function BMB__updateStyle() {
let button = this.button;
if (!button)
if (!this.star) {
return;
}
let container = this.buttonContainer;
let containerOnPersonalToolbar = container &&
(container.parentNode == this.personalToolbar ||
container.parentNode.parentNode == this.personalToolbar);
let personalToolbar = document.getElementById("PersonalToolbar");
let onPersonalToolbar = this.button.parentNode == personalToolbar ||
this.button.parentNode.parentNode == personalToolbar;
if (button.parentNode == this.bookmarksToolbarItem ||
containerOnPersonalToolbar) {
button.classList.add("bookmark-item");
button.classList.remove("toolbarbutton-1");
if (onPersonalToolbar) {
this.button.classList.add("bookmark-item");
this.button.classList.remove("toolbarbutton-1");
}
else {
button.classList.remove("bookmark-item");
button.classList.add("toolbarbutton-1");
this.button.classList.remove("bookmark-item");
this.button.classList.add("toolbarbutton-1");
}
},
@ -1255,20 +1131,13 @@ let BookmarksMenuButton = {
// When an element with a placesView attached is removed and re-inserted,
// XBL reapplies the binding causing any kind of issues and possible leaks,
// so kill current view and let popupshowing generate a new one.
let button = this.button;
if (button && button._placesView)
button._placesView.uninit();
if (this.button && this.button._placesView) {
this.button._placesView.uninit();
}
},
customizeStart: function BMB_customizeStart() {
this._uninitView();
let button = this.button;
let container = this.buttonContainer;
if (button && container && button.parentNode != container) {
// Move button back to the container, so user can move or remove it.
container.appendChild(button);
this._updateStyle();
}
},
customizeChange: function BMB_customizeChange() {
@ -1276,6 +1145,159 @@ let BookmarksMenuButton = {
},
customizeDone: function BMB_customizeDone() {
this.updatePosition();
}
delete this._button;
delete this._star;
delete this._anchor;
this.onToolbarVisibilityChange();
this._updateStyle();
},
_hasBookmarksObserver: false,
uninit: function BMB_uninit() {
this._uninitView();
if (this._hasBookmarksObserver) {
PlacesUtils.removeLazyBookmarkObserver(this);
}
if (this._pendingStmt) {
this._pendingStmt.cancel();
delete this._pendingStmt;
}
},
updateStarState: function BMB_updateStarState() {
if (!this.button || (this._uri && gBrowser.currentURI.equals(this._uri))) {
return;
}
// Reset tracked values.
this._uri = gBrowser.currentURI;
this._itemIds = [];
if (this._pendingStmt) {
this._pendingStmt.cancel();
delete this._pendingStmt;
}
// We can load about:blank before the actual page, but there is no point in handling that page.
if (isBlankPageURL(this._uri.spec)) {
return;
}
this._pendingStmt = PlacesUtils.asyncGetBookmarkIds(this._uri, function (aItemIds, aURI) {
// Safety check that the bookmarked URI equals the tracked one.
if (!aURI.equals(this._uri)) {
Components.utils.reportError("BookmarksMenuButton did not receive current URI");
return;
}
// It's possible that onItemAdded gets called before the async statement
// calls back. For such an edge case, retain all unique entries from both
// arrays.
this._itemIds = this._itemIds.filter(
function (id) aItemIds.indexOf(id) == -1
).concat(aItemIds);
this._updateStar();
// Start observing bookmarks if needed.
if (!this._hasBookmarksObserver) {
try {
PlacesUtils.addLazyBookmarkObserver(this);
this._hasBookmarksObserver = true;
} catch(ex) {
Components.utils.reportError("BookmarksMenuButton failed adding a bookmarks observer: " + ex);
}
}
delete this._pendingStmt;
}, this);
},
_updateStar: function BMB__updateStar() {
if (!this.button) {
return;
}
if (this._itemIds.length > 0) {
this.button.setAttribute("starred", "true");
this.button.setAttribute("tooltiptext", this._starredTooltip);
}
else {
this.button.removeAttribute("starred");
this.button.setAttribute("tooltiptext", this._unstarredTooltip);
}
},
onCommand: function BMB_onCommand(aEvent) {
if (aEvent.target != aEvent.currentTarget) {
return;
}
// Ignore clicks on the star if we are updating its state.
if (!this._pendingStmt) {
PlacesCommandHook.bookmarkCurrentPage(this._itemIds.length > 0);
}
},
// nsINavBookmarkObserver
onItemAdded: function BMB_onItemAdded(aItemId, aParentId, aIndex, aItemType,
aURI) {
if (!this.button) {
return;
}
if (aURI && aURI.equals(this._uri)) {
// If a new bookmark has been added to the tracked uri, register it.
if (this._itemIds.indexOf(aItemId) == -1) {
this._itemIds.push(aItemId);
this._updateStar();
}
}
},
onItemRemoved: function BMB_onItemRemoved(aItemId) {
if (!this.button) {
return;
}
let index = this._itemIds.indexOf(aItemId);
// If one of the tracked bookmarks has been removed, unregister it.
if (index != -1) {
this._itemIds.splice(index, 1);
this._updateStar();
}
},
onItemChanged: function BMB_onItemChanged(aItemId, aProperty,
aIsAnnotationProperty, aNewValue) {
if (!this.button) {
return;
}
if (aProperty == "uri") {
let index = this._itemIds.indexOf(aItemId);
// If the changed bookmark was tracked, check if it is now pointing to
// a different uri and unregister it.
if (index != -1 && aNewValue != this._uri.spec) {
this._itemIds.splice(index, 1);
this._updateStar();
}
// If another bookmark is now pointing to the tracked uri, register it.
else if (index == -1 && aNewValue == this._uri.spec) {
this._itemIds.push(aItemId);
this._updateStar();
}
}
},
onBeginUpdateBatch: function () {},
onEndUpdateBatch: function () {},
onBeforeItemRemoved: function () {},
onItemVisited: function () {},
onItemMoved: function () {},
QueryInterface: XPCOMUtils.generateQI([
Ci.nsINavBookmarkObserver
]),
};

View File

@ -308,19 +308,20 @@ toolbarbutton.bookmark-item {
max-width: 13em;
}
%ifdef MENUBAR_CAN_AUTOHIDE
#toolbar-menubar:not([autohide="true"]) ~ #nav-bar > #bookmarks-menu-button-container,
#toolbar-menubar:not([autohide="true"]) ~ toolbar > #personal-bookmarks > #bookmarks-menu-button,
#toolbar-menubar:not([autohide="true"]) > #personal-bookmarks > #bookmarks-menu-button {
display: none;
}
%endif
#editBMPanel_tagsSelector {
/* override default listbox width from xul.css */
width: auto;
}
/* The star doesn't make sense as text */
toolbar[mode="text"] #bookmarks-menu-button > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
display: -moz-box !important;
}
toolbar[mode="text"] #bookmarks-menu-button > .toolbarbutton-menubutton-button > .toolbarbutton-text,
toolbar[mode="full"] #bookmarks-menu-button.bookmark-item > .toolbarbutton-menubutton-button > .toolbarbutton-text {
display: none;
}
menupopup[emptyplacesresult="true"] > .hide-if-empty-places-result {
display: none;
}

View File

@ -953,7 +953,6 @@ var gBrowserInit = {
// Misc. inits.
CombinedStopReload.init();
TabsOnTop.init();
BookmarksMenuButton.init();
gPrivateBrowsingUI.init();
TabsInTitlebar.init();
retrieveToolbarIconsizesFromTheme();
@ -1331,7 +1330,7 @@ var gBrowserInit = {
} catch (ex) {
}
PlacesStarButton.uninit();
BookmarksMenuButton.uninit();
TabsOnTop.uninit();
@ -2252,6 +2251,8 @@ function UpdatePageProxyState()
function SetPageProxyState(aState)
{
BookmarksMenuButton.onPageProxyStateChanged(aState);
if (!gURLBar)
return;
@ -3794,7 +3795,7 @@ var XULBrowserWindow = {
URLBarSetURI(aLocationURI);
// Update starring UI
PlacesStarButton.updateState();
BookmarksMenuButton.updateStarState();
SocialShareButton.updateShareState();
}
@ -4412,7 +4413,7 @@ function setToolbarVisibility(toolbar, isVisible) {
document.persist(toolbar.id, hidingAttribute);
PlacesToolbarHelper.init();
BookmarksMenuButton.updatePosition();
BookmarksMenuButton.onToolbarVisibilityChange();
gBrowser.updateWindowResizers();
#ifdef MENUBAR_CAN_AUTOHIDE
@ -6778,8 +6779,10 @@ let gPrivateBrowsingUI = {
}
}
if (gURLBar) {
// Disable switch to tab autocompletion for private windows
if (gURLBar &&
!PrivateBrowsingUtils.permanentPrivateBrowsing) {
// Disable switch to tab autocompletion for private windows
// (not for "Always use private browsing" mode)
gURLBar.setAttribute("autocompletesearchparam", "");
}
}
@ -6802,9 +6805,10 @@ function switchToTabHavingURI(aURI, aOpenNew) {
// This will switch to the tab in aWindow having aURI, if present.
function switchIfURIInWindow(aWindow) {
// Only switch to the tab if neither the source and desination window are
// private.
if (PrivateBrowsingUtils.isWindowPrivate(window) ||
PrivateBrowsingUtils.isWindowPrivate(aWindow)) {
// private and they are not in permanent private borwsing mode
if ((PrivateBrowsingUtils.isWindowPrivate(window) ||
PrivateBrowsingUtils.isWindowPrivate(aWindow)) &&
!PrivateBrowsingUtils.permanentPrivateBrowsing) {
return false;
}

View File

@ -528,7 +528,7 @@
toolbarname="&navbarCmd.label;" accesskey="&navbarCmd.accesskey;"
fullscreentoolbar="true" mode="icons" customizable="true"
iconsize="large"
defaultset="unified-back-forward-button,urlbar-container,reload-button,stop-button,search-container,webrtc-status-button,downloads-button,home-button,bookmarks-menu-button-container,window-controls"
defaultset="unified-back-forward-button,urlbar-container,reload-button,stop-button,search-container,webrtc-status-button,bookmarks-menu-button,downloads-button,home-button,window-controls"
customizationtarget="nav-bar-customizationtarget"
context="toolbar-context-menu">
@ -626,9 +626,6 @@
hidden="true"
onclick="SocialShareButton.onClick(event);"/>
<image id="star-button"
class="urlbar-icon"
onclick="PlacesStarButton.onClick(event);"/>
<image id="go-button"
class="urlbar-icon"
tooltiptext="&goEndCap.tooltip;"
@ -846,6 +843,82 @@
<searchbar id="searchbar" flex="1"/>
</toolbaritem>
<toolbarbutton id="bookmarks-menu-button"
class="toolbarbutton-1 chromeclass-toolbar-additional"
persist="class"
removable="true"
type="menu-button"
label="&bookmarksMenuButton.label;"
tooltiptext="&bookmarksMenuButton.tooltip;"
ondragenter="PlacesMenuDNDHandler.onDragEnter(event);"
ondragover="PlacesMenuDNDHandler.onDragOver(event);"
ondragleave="PlacesMenuDNDHandler.onDragLeave(event);"
ondrop="PlacesMenuDNDHandler.onDrop(event);"
oncommand="BookmarksMenuButton.onCommand(event);">
<menupopup id="BMB_bookmarksPopup"
placespopup="true"
context="placesContext"
openInTabs="children"
oncommand="BookmarksEventHandler.onCommand(event, this.parentNode._placesView);"
onclick="BookmarksEventHandler.onClick(event, this.parentNode._placesView);"
onpopupshowing="BookmarksMenuButton.onPopupShowing(event);
if (!this.parentNode._placesView)
new PlacesMenu(event, 'place:folder=BOOKMARKS_MENU');"
tooltip="bhTooltip" popupsinherittooltip="true">
<menuitem id="BMB_viewBookmarksToolbar"
placesanonid="view-toolbar"
toolbarId="PersonalToolbar"
type="checkbox"
oncommand="onViewToolbarCommand(event)"
label="&viewBookmarksToolbar.label;"/>
<menuseparator/>
<menuitem id="BMB_bookmarksShowAll"
label="&showAllBookmarks2.label;"
command="Browser:ShowAllBookmarks"
key="manBookmarkKb"/>
<menuseparator/>
<menuitem id="BMB_subscribeToPageMenuitem"
#ifndef XP_MACOSX
class="menuitem-iconic"
#endif
label="&subscribeToPageMenuitem.label;"
oncommand="return FeedHandler.subscribeToFeed(null, event);"
onclick="checkForMiddleClick(this, event);"
observes="singleFeedMenuitemState"/>
<menu id="BMB_subscribeToPageMenupopup"
#ifndef XP_MACOSX
class="menu-iconic"
#endif
label="&subscribeToPageMenupopup.label;"
observes="multipleFeedsMenuState">
<menupopup id="BMB_subscribeToPageSubmenuMenupopup"
onpopupshowing="return FeedHandler.buildFeedList(event.target);"
oncommand="return FeedHandler.subscribeToFeed(null, event);"
onclick="checkForMiddleClick(this, event);"/>
</menu>
<menuseparator/>
<menu id="BMB_bookmarksToolbar"
placesanonid="toolbar-autohide"
class="menu-iconic bookmark-item"
label="&personalbarCmd.label;"
container="true">
<menupopup id="BMB_bookmarksToolbarPopup"
placespopup="true"
context="placesContext"
onpopupshowing="if (!this.parentNode._placesView)
new PlacesMenu(event, 'place:folder=TOOLBAR');"/>
</menu>
<menuseparator/>
<!-- Bookmarks menu items -->
<menuseparator builder="end"
class="hide-if-empty-places-result"/>
<menuitem id="BMB_unsortedBookmarks"
label="&bookmarksMenuButton.unsorted.label;"
oncommand="PlacesCommandHook.showPlacesOrganizer('UnfiledBookmarks');"
class="menuitem-iconic"/>
</menupopup>
</toolbarbutton>
<toolbarbutton id="home-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
persist="class" removable="true"
label="&homeButton.label;"
@ -856,13 +929,6 @@
onclick="BrowserGoHome(event);"
aboutHomeOverrideTooltip="&abouthome.pageTitle;"/>
<toolbaritem id="social-toolbar-item"
class="chromeclass-toolbar-additional"
removable="false"
title="&socialToolbar.title;"
hidden="true"
skipintoolbarset="true"
observes="socialActiveBroadcaster">
<toolbarbutton id="social-provider-button"
class="toolbarbutton-1"
type="menu">
@ -904,91 +970,6 @@
</toolbarbutton>
</toolbaritem>
<toolbaritem id="bookmarks-menu-button-container"
class="chromeclass-toolbar-additional"
removable="true"
title="&bookmarksMenuButton.label;">
<toolbarbutton id="bookmarks-menu-button"
type="menu"
class="toolbarbutton-1"
label="&bookmarksMenuButton.label;"
tooltiptext="&bookmarksMenuButton.tooltip;"
ondragenter="PlacesMenuDNDHandler.onDragEnter(event);"
ondragover="PlacesMenuDNDHandler.onDragOver(event);"
ondragexit="PlacesMenuDNDHandler.onDragExit(event);"
ondrop="PlacesMenuDNDHandler.onDrop(event);">
<menupopup id="BMB_bookmarksPopup"
placespopup="true"
context="placesContext"
openInTabs="children"
oncommand="BookmarksEventHandler.onCommand(event, this.parentNode._placesView);"
onclick="BookmarksEventHandler.onClick(event, this.parentNode._placesView);"
onpopupshowing="BookmarksMenuButton.onPopupShowing(event);
if (!this.parentNode._placesView)
new PlacesMenu(event, 'place:folder=BOOKMARKS_MENU');"
tooltip="bhTooltip" popupsinherittooltip="true">
<menuitem id="BMB_viewBookmarksToolbar"
placesanonid="view-toolbar"
toolbarId="PersonalToolbar"
type="checkbox"
oncommand="onViewToolbarCommand(event)"
label="&viewBookmarksToolbar.label;"/>
<menuseparator/>
<menuitem id="BMB_bookmarksShowAll"
label="&showAllBookmarks2.label;"
command="Browser:ShowAllBookmarks"
key="manBookmarkKb"/>
<menuseparator/>
<menuitem id="BMB_bookmarkThisPage"
#ifndef XP_MACOSX
class="menuitem-iconic"
#endif
label="&bookmarkThisPageCmd.label;"
command="Browser:AddBookmarkAs"
key="addBookmarkAsKb"/>
<menuitem id="BMB_subscribeToPageMenuitem"
#ifndef XP_MACOSX
class="menuitem-iconic"
#endif
label="&subscribeToPageMenuitem.label;"
oncommand="return FeedHandler.subscribeToFeed(null, event);"
onclick="checkForMiddleClick(this, event);"
observes="singleFeedMenuitemState"/>
<menu id="BMB_subscribeToPageMenupopup"
#ifndef XP_MACOSX
class="menu-iconic"
#endif
label="&subscribeToPageMenupopup.label;"
observes="multipleFeedsMenuState">
<menupopup id="BMB_subscribeToPageSubmenuMenupopup"
onpopupshowing="return FeedHandler.buildFeedList(event.target);"
oncommand="return FeedHandler.subscribeToFeed(null, event);"
onclick="checkForMiddleClick(this, event);"/>
</menu>
<menuseparator/>
<menu id="BMB_bookmarksToolbar"
placesanonid="toolbar-autohide"
class="menu-iconic bookmark-item"
label="&personalbarCmd.label;"
container="true">
<menupopup id="BMB_bookmarksToolbarPopup"
placespopup="true"
context="placesContext"
onpopupshowing="if (!this.parentNode._placesView)
new PlacesMenu(event, 'place:folder=TOOLBAR');"/>
</menu>
<menuseparator/>
<!-- Bookmarks menu items -->
<menuseparator builder="end"
class="hide-if-empty-places-result"/>
<menuitem id="BMB_unsortedBookmarks"
label="&bookmarksMenuButton.unsorted.label;"
oncommand="PlacesCommandHook.showPlacesOrganizer('UnfiledBookmarks');"
class="menuitem-iconic"/>
</menupopup>
</toolbarbutton>
</toolbaritem>
<toolbarbutton id="print-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
label="&printButton.label;" command="cmd_print"
tooltiptext="&printButton.tooltip;"/>

View File

@ -2,6 +2,11 @@
* 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/. */
// Equivalent to 0600 permissions; used for saved Sync Recovery Key.
// This constant can be replaced when the equivalent values are available to
// chrome JS; see Bug 433295 and Bug 757351.
const PERMISSIONS_RWUSR = 0x180;
// Weave should always exist before before this file gets included.
let gSyncUtils = {
get bundle() {
@ -157,7 +162,7 @@ let gSyncUtils = {
aResult == Ci.nsIFilePicker.returnReplace) {
let stream = Cc["@mozilla.org/network/file-output-stream;1"].
createInstance(Ci.nsIFileOutputStream);
stream.init(fp.file, -1, 0600, 0);
stream.init(fp.file, -1, PERMISSIONS_RWUSR, 0);
let serializer = new XMLSerializer();
let output = serializer.serializeToString(iframe.contentDocument);

View File

@ -650,7 +650,8 @@
// Tabs in private windows aren't registered as "Open" so
// that they don't appear as switch-to-tab candidates.
if (!isBlankPageURL(aLocation.spec) &&
!PrivateBrowsingUtils.isWindowPrivate(window)) {
(!PrivateBrowsingUtils.isWindowPrivate(window) ||
PrivateBrowsingUtils.permanentPrivateBrowsing)) {
autocomplete.registerOpenPage(aLocation);
this.mBrowser.registeredOpenURI = aLocation;
}

View File

@ -17,15 +17,15 @@ function invokeUsingCtrlD(phase) {
function invokeUsingStarButton(phase) {
switch (phase) {
case 1:
EventUtils.sendMouseEvent({ type: "click" }, "star-button");
EventUtils.synthesizeMouseAtCenter(BookmarksMenuButton.star, {});
break;
case 2:
case 4:
EventUtils.synthesizeKey("VK_ESCAPE", {});
break;
case 3:
EventUtils.synthesizeMouse(document.getElementById("star-button"),
1, 1, { clickCount: 2 });
EventUtils.synthesizeMouseAtCenter(BookmarksMenuButton.star,
{ clickCount: 2 });
break;
}
}
@ -44,8 +44,8 @@ function test() {
waitForExplicitFinish();
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function () {
gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
gBrowser.selectedBrowser.addEventListener("load", function onLoad() {
gBrowser.selectedBrowser.removeEventListener("load", onLoad, true);
waitForStarChange(false, initTest);
}, true);
@ -60,10 +60,12 @@ function initTest() {
}
function waitForStarChange(aValue, aCallback) {
let starButton = document.getElementById("star-button");
if (PlacesStarButton._pendingStmt || starButton.hasAttribute("starred") != aValue) {
let expectedStatus = aValue ? BookmarksMenuButton.STATUS_STARRED
: BookmarksMenuButton.STATUS_UNSTARRED;
if (BookmarksMenuButton.status == BookmarksMenuButton.STATUS_UPDATING ||
BookmarksMenuButton.status != expectedStatus) {
info("Waiting for star button change.");
setTimeout(arguments.callee, 50, aValue, aCallback);
setTimeout(waitForStarChange, 50, aValue, aCallback);
return;
}
aCallback();

View File

@ -4,7 +4,6 @@
let testURL = "data:text/plain,nothing but plain text";
let testTag = "581253_tag";
let starButton = document.getElementById("star-button");
let timerID = -1;
function test() {
@ -35,18 +34,19 @@ function test() {
}
function waitForStarChange(aValue, aCallback) {
if (PlacesStarButton._pendingStmt || starButton.hasAttribute("starred") != aValue) {
let expectedStatus = aValue ? BookmarksMenuButton.STATUS_STARRED
: BookmarksMenuButton.STATUS_UNSTARRED;
if (BookmarksMenuButton.status == BookmarksMenuButton.STATUS_UPDATING ||
BookmarksMenuButton.status != expectedStatus) {
info("Waiting for star button change.");
info("pendingStmt: " + (!!PlacesStarButton._pendingStmt) + ", hasAttribute: " + starButton.hasAttribute("starred") + ", tracked uri: " + PlacesStarButton._uri.spec);
timerID = setTimeout(arguments.callee, 50, aValue, aCallback);
setTimeout(waitForStarChange, 50, aValue, aCallback);
return;
}
timerID = -1;
aCallback();
}
function onStarred() {
ok(starButton.getAttribute("starred") == "true",
is(BookmarksMenuButton.status, BookmarksMenuButton.STATUS_STARRED,
"star button indicates that the page is bookmarked");
let uri = makeURI(testURL);
@ -54,7 +54,7 @@ function onStarred() {
PlacesUtils.transactionManager.doTransaction(tagTxn);
StarUI.panel.addEventListener("popupshown", onPanelShown, false);
starButton.click();
BookmarksMenuButton.star.click();
}
function onPanelShown(aEvent) {
@ -93,7 +93,7 @@ function onPanelHidden(aEvent) {
executeSoon(function() {
ok(!PlacesUtils.bookmarks.isBookmarked(makeURI(testURL)),
"the bookmark for the test url has been removed");
ok(!starButton.hasAttribute("starred"),
is(BookmarksMenuButton.status, BookmarksMenuButton.STATUS_UNSTARRED,
"star button indicates that the bookmark has been removed");
gBrowser.removeCurrentTab();
waitForClearHistory(finish);

View File

@ -11,7 +11,8 @@ function test() {
tab.linkedBrowser.addEventListener("load", (function(event) {
tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
is(PlacesStarButton._starIcon.getAttribute("tooltiptext"), PlacesStarButton._unstarredTooltip,
is(BookmarksMenuButton.button.getAttribute("tooltiptext"),
BookmarksMenuButton._unstarredTooltip,
"Star icon should have the unstarred tooltip text");
gBrowser.removeCurrentTab();

View File

@ -91,6 +91,11 @@ richlistitem[type="download"]:not([selected]) button {
visibility: hidden;
}
.download-state[state="1"]:not([exists]) .downloadShow
{
display: none;
}
#downloadsSummary:not([inprogress]) > vbox > #downloadsSummaryProgress,
#downloadsSummary:not([inprogress]) > vbox > #downloadsSummaryDetails,
#downloadsFooter[showingsummary] > #downloadsHistory,

View File

@ -71,6 +71,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "DownloadUtils",
"resource://gre/modules/DownloadUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "DownloadsCommon",
"resource:///modules/DownloadsCommon.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "OS",
"resource://gre/modules/osfile.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
"resource://gre/modules/PrivateBrowsingUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
@ -553,6 +555,14 @@ const DownloadsPanel = {
return;
}
// When the panel is opened, we check if the target files of visible items
// still exist, and update the allowed items interactions accordingly. We
// do these checks on a background thread, and don't prevent the panel to
// be displayed while these checks are being performed.
for each (let viewItem in DownloadsView._viewItems) {
viewItem.verifyTargetExists();
}
if (aAnchor) {
DownloadsCommon.log("Opening downloads panel popup.");
this.panel.openPopup(aAnchor, "bottomcenter topright", 0, 0, false,
@ -1074,6 +1084,7 @@ function DownloadsViewItem(aDataItem, aElement)
// Initialize more complex attributes.
this._updateProgress();
this._updateStatusLine();
this.verifyTargetExists();
}
DownloadsViewItem.prototype = {
@ -1111,6 +1122,12 @@ DownloadsViewItem.prototype = {
if (aOldState != Ci.nsIDownloadManager.DOWNLOAD_FINISHED &&
aOldState != this.dataItem.state) {
this._element.setAttribute("image", this.image + "&state=normal");
// We assume the existence of the target of a download that just completed
// successfully, without checking the condition in the background. If the
// panel is already open, this will take effect immediately. If the panel
// is opened later, a new background existence check will be performed.
this._element.setAttribute("exists", "true");
}
// Update the user interface after switching states.
@ -1252,7 +1269,33 @@ DownloadsViewItem.prototype = {
}
let [size, unit] = DownloadUtils.convertByteUnits(fileSize);
return DownloadsCommon.strings.sizeWithUnits(size, unit);
}
},
//////////////////////////////////////////////////////////////////////////////
//// Functions called by the panel
/**
* Starts checking whether the target file of a finished download is still
* available on disk, and sets an attribute that controls how the item is
* presented visually.
*
* The existence check is executed on a background thread.
*/
verifyTargetExists: function DVI_verifyTargetExists() {
// We don't need to check if the download is not finished successfully.
if (!this.dataItem.openable) {
return;
}
OS.File.exists(this.dataItem.localFile.path).then(
function DVI_RTE_onSuccess(aExists) {
if (aExists) {
this._element.setAttribute("exists", "true");
} else {
this._element.removeAttribute("exists");
}
}.bind(this), Cu.reportError);
},
};
////////////////////////////////////////////////////////////////////////////////

View File

@ -1170,7 +1170,7 @@ BrowserGlue.prototype = {
},
_migrateUI: function BG__migrateUI() {
const UI_VERSION = 11;
const UI_VERSION = 12;
const BROWSER_DOCURL = "chrome://browser/content/browser.xul#";
let currentUIVersion = 0;
try {
@ -1336,6 +1336,33 @@ BrowserGlue.prototype = {
Services.prefs.clearUserPref("permissions.default.image");
}
if (currentUIVersion < 12) {
// Remove bookmarks-menu-button-container, then place
// bookmarks-menu-button into its position.
let currentsetResource = this._rdf.GetResource("currentset");
let toolbarResource = this._rdf.GetResource(BROWSER_DOCURL + "nav-bar");
let currentset = this._getPersist(toolbarResource, currentsetResource);
// Need to migrate only if toolbar is customized.
if (currentset) {
if (currentset.contains("bookmarks-menu-button-container"))
currentset = currentset.replace(/(^|,)bookmarks-menu-button-container($|,)/,"$2");
// Now insert the new button.
if (currentset.contains("downloads-button")) {
currentset = currentset.replace(/(^|,)downloads-button($|,)/,
"$1bookmarks-menu-button,downloads-button$2");
} else if (currentset.contains("home-button")) {
currentset = currentset.replace(/(^|,)home-button($|,)/,
"$1bookmarks-menu-button,home-button$2");
} else {
// Just append.
currentset = currentset.replace(/(^|,)window-controls($|,)/,
"$1bookmarks-menu-button,window-controls$2")
}
this._setPersist(toolbarResource, currentsetResource, currentset);
}
}
if (this._dirty)
this._dataSource.QueryInterface(Ci.nsIRDFRemoteDataSource).Flush();

View File

@ -7308,12 +7308,10 @@ exports.Output = Output;
* Functions and data related to the execution of a command
*/
exports.createExecutionContext = function(requisition) {
return {
var context = {
exec: requisition.exec.bind(requisition),
update: requisition.update.bind(requisition),
updateExec: requisition.updateExec.bind(requisition),
document: requisition.document,
environment: requisition.environment,
createView: view.createView,
typedData: function(data, type) {
return {
@ -7334,6 +7332,18 @@ exports.createExecutionContext = function(requisition) {
return Promise.defer();
}
};
Object.defineProperty(context, 'environment', {
get: function() { return requisition.environment; },
enumerable : true
});
Object.defineProperty(context, 'document', {
get: function() { return requisition.document; },
enumerable : true
});
return context;
};

View File

@ -653,12 +653,12 @@ function testKeyboardAccessibility(callback) {
"The 0 item should be focused now.");
EventUtils.sendKey("END", gDebugger);
is(gVariablesView.getFocusedItem().name, "foo",
"The foo item should be focused now.");
is(gVariablesView.getFocusedItem().name, "bar",
"The bar item should be focused now.");
EventUtils.sendKey("DOWN", gDebugger);
is(gVariablesView.getFocusedItem().name, "bar",
"The bar item should be focused now.");
"The bar item should still be focused now.");
EventUtils.sendKey("UP", gDebugger);
is(gVariablesView.getFocusedItem().name, "foo",
@ -669,10 +669,14 @@ function testKeyboardAccessibility(callback) {
"The foo item should still be focused now.");
EventUtils.sendKey("PAGE_DOWN", gDebugger);
is(gVariablesView.getFocusedItem().name, "foo",
"The foo item should still be focused now.");
is(gVariablesView.getFocusedItem().name, "bar",
"The bar item should be focused now.");
EventUtils.sendKey("PAGE_UP", gDebugger);
is(gVariablesView.getFocusedItem().name, "someProp7",
"The someProp7 item should be focused now.");
EventUtils.sendKey("UP", gDebugger);
is(gVariablesView.getFocusedItem().name, "__proto__",
"The __proto__ item should be focused now.");
@ -684,10 +688,6 @@ function testKeyboardAccessibility(callback) {
is(gVariablesView.getFocusedItem().name, "get",
"The get item should be focused now.");
EventUtils.sendKey("UP", gDebugger);
is(gVariablesView.getFocusedItem().name, "p8",
"The p8 item should be focused now.");
EventUtils.sendKey("HOME", gDebugger);
is(gVariablesView.getFocusedItem().name, "someProp0",
"The someProp0 item should be focused now.");
@ -828,6 +828,18 @@ function testKeyboardAccessibility(callback) {
is(gVariablesView.getFocusedItem().expanded, false,
"The top-level __proto__ item should not be expanded.");
EventUtils.sendKey("END", gDebugger);
is(gVariablesView.getFocusedItem().name, "foo",
"The foo scope should be focused.");
EventUtils.sendKey("PAGE_UP", gDebugger);
is(gVariablesView.getFocusedItem().name, "__proto__",
"The __proto__ property should be focused.");
EventUtils.sendKey("PAGE_DOWN", gDebugger);
is(gVariablesView.getFocusedItem().name, "foo",
"The foo scope should be focused.");
executeSoon(callback);
});
});

View File

@ -275,25 +275,31 @@ TabTarget.prototype = {
this._setupRemoteListeners();
if (this.isRemote) {
// In the remote debugging case, the protocol connection will have been
// already initialized in the connection screen code.
this._remote.resolve(null);
} else {
let attachTab = () => {
this._client.attachTab(this._form.actor, (aResponse, aTabClient) => {
if (!aTabClient) {
this._remote.reject("Unable to attach to the tab");
return;
}
this.threadActor = aResponse.threadActor;
this._remote.resolve(null);
});
};
if (this.isLocalTab) {
this._client.connect((aType, aTraits) => {
this._client.listTabs(aResponse => {
this._form = aResponse.tabs[aResponse.selected];
this._client.attachTab(this._form.actor, (aResponse, aTabClient) => {
if (!aTabClient) {
this._remote.reject("Unable to attach to the tab");
return;
}
this.threadActor = aResponse.threadActor;
this._remote.resolve(null);
});
attachTab();
});
});
} else if (!this.chrome) {
// In the remote debugging case, the protocol connection will have been
// already initialized in the connection screen code.
attachTab();
} else {
// Remote chrome debugging doesn't need anything at this point.
this._remote.resolve(null);
}
return this._remote.promise;

View File

@ -515,7 +515,8 @@ let L10N = new ViewHelpers.L10N(NET_STRINGS_URI);
* Shortcuts for accessing various network monitor preferences.
*/
let Prefs = new ViewHelpers.Prefs("devtools.netmonitor", {
networkDetailsWidth: ["Int", "panes-network-details-width"]
networkDetailsWidth: ["Int", "panes-network-details-width"],
networkDetailsHeight: ["Int", "panes-network-details-height"]
});
/**

View File

@ -7,6 +7,7 @@
const EPSILON = 0.001;
const REQUESTS_REFRESH_RATE = 50; // ms
const REQUESTS_HEADERS_SAFE_BOUNDS = 30; // px
const REQUESTS_WATERFALL_SAFE_BOUNDS = 100; // px
const REQUESTS_WATERFALL_BACKGROUND_PATTERN = [5, 250, 1000, 2000]; // ms
const DEFAULT_HTTP_VERSION = "HTTP/1.1";
@ -102,6 +103,7 @@ let NetMonitorView = {
this._expandPaneString = L10N.getStr("expandDetailsPane");
this._detailsPane.setAttribute("width", Prefs.networkDetailsWidth);
this._detailsPane.setAttribute("height", Prefs.networkDetailsHeight);
this.toggleDetailsPane({ visible: false });
},
@ -112,6 +114,7 @@ let NetMonitorView = {
dumpn("Destroying the NetMonitorView panes");
Prefs.networkDetailsWidth = this._detailsPane.getAttribute("width");
Prefs.networkDetailsHeight = this._detailsPane.getAttribute("height");
this._detailsPane = null;
this._detailsPaneToggleButton = null;
@ -592,6 +595,27 @@ create({ constructor: RequestsMenuView, proto: MenuContainer.prototype }, {
// the window is resized, this needs to be invalidated.
if (aReset) {
this._cachedWaterfallWidth = 0;
let table = $("#network-table");
let toolbar = $("#requests-menu-toolbar");
let columns = [
[".requests-menu-waterfall", "waterfall-overflows"],
[".requests-menu-size", "size-overflows"],
[".requests-menu-type", "type-overflows"],
[".requests-menu-domain", "domain-overflows"]
];
// Flush headers.
columns.forEach(([, attribute]) => table.removeAttribute(attribute));
let availableWidth = toolbar.getBoundingClientRect().width;
// Hide overflowing columns.
columns.forEach(([className, attribute]) => {
let bounds = $(".requests-menu-header" + className).getBoundingClientRect();
if (bounds.right > availableWidth - REQUESTS_HEADERS_SAFE_BOUNDS) {
table.setAttribute(attribute, "");
}
});
}
// Determine the scaling to be applied to all the waterfalls so that

View File

@ -13,8 +13,36 @@
/* Responsive sidebar */
@media (max-width: 700px) {
#toolbar-spacer,
#details-pane-toggle,
#details-pane[pane-collapsed],
.requests-menu-waterfall {
display: none;
}
}
@media (min-width: 701px) {
#network-table[waterfall-overflows] .requests-menu-waterfall {
display: none;
}
#network-table[size-overflows] .requests-menu-size {
display: none;
}
#network-table[type-overflows] .requests-menu-type {
display: none;
}
#network-table[domain-overflows] .requests-menu-domain {
display: none;
}
#network-table[type-overflows] .requests-menu-domain {
-moz-box-flex: 1;
}
#network-table[domain-overflows] .requests-menu-file {
-moz-box-flex: 1;
}
}

View File

@ -46,7 +46,7 @@
class="plain requests-menu-header requests-menu-waterfall"
value="&netmonitorUI.toolbar.waterfall;"
crop="end"/>
<spacer flex="1"/>
<spacer id="toolbar-spacer" flex="1"/>
<toolbarbutton id="details-pane-toggle"
class="devtools-toolbarbutton"
tooltiptext="&netmonitorUI.panesButton.tooltip;"

View File

@ -25,7 +25,7 @@ function test() {
statusText: "OK",
type: "json",
fullMimeType: "text/json; charset=utf-8",
size: L10N.getFormatStr("networkMenu.sizeKB", 83.95),
size: L10N.getFormatStr("networkMenu.sizeKB", L10N.numberWithDecimals(85975/1024, 2)),
time: true
});

View File

@ -9,13 +9,20 @@ function test() {
initNetMonitor(SIMPLE_URL).then(([aTab, aDebuggee, aMonitor]) => {
info("Starting test... ");
// This test reopens the network monitor a bunch of times, for different
// hosts (bottom, side, window). This seems to be slow on debug builds.
requestLongerTimeout(2);
let prefsToCheck = {
networkDetailsWidth: {
newValue: ~~(Math.random() * 200 + 100),
validate: () =>
~~aMonitor._view._detailsPane.getAttribute("width"),
modifyFrontend: (aValue) =>
aMonitor._view._detailsPane.setAttribute("width", aValue)
validate: ($) => ~~$("#details-pane").getAttribute("width"),
modifyFrontend: ($, aValue) => $("#details-pane").setAttribute("width", aValue)
},
networkDetailsHeight: {
newValue: ~~(Math.random() * 300 + 100),
validate: ($) => ~~$("#details-pane").getAttribute("height"),
modifyFrontend: ($, aValue) => $("#details-pane").setAttribute("height", aValue)
},
/* add more prefs here... */
};
@ -39,7 +46,7 @@ function test() {
is(currentValue, firstValue,
"Pref " + name + " should be equal to first value: " + firstValue);
is(currentValue, validate(),
is(currentValue, validate(aMonitor.panelWin.$),
"Pref " + name + " should validate: " + currentValue);
}
}
@ -54,14 +61,14 @@ function test() {
let validate = prefsToCheck[name].validate;
let modifyFrontend = prefsToCheck[name].modifyFrontend;
modifyFrontend(newValue);
modifyFrontend(aMonitor.panelWin.$, newValue);
info("Modified UI element affecting " + name + " to: " + newValue);
is(currentValue, firstValue,
"Pref " + name + " should still be equal to first value: " + firstValue);
isnot(currentValue, newValue,
"Pref " + name + " should't yet be equal to second value: " + newValue);
is(newValue, validate(),
is(newValue, validate(aMonitor.panelWin.$),
"The UI element affecting " + name + " should validate: " + newValue);
}
}
@ -74,13 +81,12 @@ function test() {
let firstValue = prefsToCheck[name].firstValue;
let newValue = prefsToCheck[name].newValue;
let validate = prefsToCheck[name].validate;
let modifyFrontend = prefsToCheck[name].modifyFrontend;
isnot(currentValue, firstValue,
"Pref " + name + " should't be equal to first value: " + firstValue);
is(currentValue, newValue,
"Pref " + name + " should now be equal to second value: " + newValue);
is(newValue, validate(),
is(newValue, validate(aMonitor.panelWin.$),
"The UI element affecting " + name + " should validate: " + newValue);
}
}
@ -95,36 +101,117 @@ function test() {
let validate = prefsToCheck[name].validate;
let modifyFrontend = prefsToCheck[name].modifyFrontend;
modifyFrontend(firstValue);
modifyFrontend(aMonitor.panelWin.$, firstValue);
info("Modified UI element affecting " + name + " to: " + firstValue);
isnot(currentValue, firstValue,
"Pref " + name + " should't yet be equal to first value: " + firstValue);
is(currentValue, newValue,
"Pref " + name + " should still be equal to second value: " + newValue);
is(firstValue, validate(),
is(firstValue, validate(aMonitor.panelWin.$),
"The UI element affecting " + name + " should validate: " + firstValue);
}
}
storeFirstPrefValues();
function testBottom() {
info("Testing prefs reload for a bottom host.");
storeFirstPrefValues();
// Validate and modify.
validateFirstPrefValues();
modifyFrontend();
restartNetMonitor(aMonitor).then(([,, aNewMonitor]) => {
aMonitor = aNewMonitor;
// Validate and modify while toolbox is on the bottom.
validateFirstPrefValues();
modifyFrontend();
// Revalidate and reset.
validateNewPrefValues();
resetFrontend();
restartNetMonitor(aMonitor).then(([,, aNewMonitor]) => {
aMonitor = aNewMonitor;
return restartNetMonitor(aMonitor)
.then(([,, aNewMonitor]) => {
aMonitor = aNewMonitor;
// Revalidate and finish.
validateFirstPrefValues();
teardown(aMonitor).then(finish);
});
});
// Revalidate and reset frontend while toolbox is on the bottom.
validateNewPrefValues();
resetFrontend();
return restartNetMonitor(aMonitor);
})
.then(([,, aNewMonitor]) => {
aMonitor = aNewMonitor;
// Revalidate.
validateFirstPrefValues();
});
}
function testSide() {
info("Moving toolbox to the side...");
return aMonitor._toolbox.switchHost(Toolbox.HostType.SIDE)
.then(() => {
info("Testing prefs reload for a side host.");
storeFirstPrefValues();
// Validate and modify frontend while toolbox is on the side.
validateFirstPrefValues();
modifyFrontend();
return restartNetMonitor(aMonitor);
})
.then(([,, aNewMonitor]) => {
aMonitor = aNewMonitor;
// Revalidate and reset frontend while toolbox is on the side.
validateNewPrefValues();
resetFrontend();
return restartNetMonitor(aMonitor);
})
.then(([,, aNewMonitor]) => {
aMonitor = aNewMonitor;
// Revalidate.
validateFirstPrefValues();
});
}
function testWindow() {
info("Moving toolbox into a window...");
return aMonitor._toolbox.switchHost(Toolbox.HostType.WINDOW)
.then(() => {
info("Testing prefs reload for a window host.");
storeFirstPrefValues();
// Validate and modify frontend while toolbox is in a window.
validateFirstPrefValues();
modifyFrontend();
return restartNetMonitor(aMonitor);
})
.then(([,, aNewMonitor]) => {
aMonitor = aNewMonitor;
// Revalidate and reset frontend while toolbox is in a window.
validateNewPrefValues();
resetFrontend();
return restartNetMonitor(aMonitor);
})
.then(([,, aNewMonitor]) => {
aMonitor = aNewMonitor;
// Revalidate.
validateFirstPrefValues();
});
}
function cleanupAndFinish() {
info("Moving toolbox back to the bottom...");
aMonitor._toolbox.switchHost(Toolbox.HostType.BOTTOM)
.then(() => teardown(aMonitor))
.then(finish);
}
testBottom()
.then(testSide)
.then(testWindow)
.then(cleanupAndFinish);
});
}

View File

@ -73,7 +73,7 @@ function test() {
is(responseScope.querySelector(".name").getAttribute("value"),
L10N.getStr("responseHeaders") + " (" +
L10N.getFormatStr("networkMenu.sizeKB", L10N.numberWithDecimals(0.168, 3)) + ")",
L10N.getFormatStr("networkMenu.sizeKB", L10N.numberWithDecimals(173/1024, 3)) + ")",
"The response headers scope doesn't have the correct title.");
ok(requestScope.querySelector(".name").getAttribute("value").contains(

View File

@ -7,6 +7,7 @@ const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
let { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
let { Promise } = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {});
let { TargetFactory } = Cu.import("resource:///modules/devtools/Target.jsm", {});
let { Toolbox } = Cu.import("resource:///modules/devtools/Toolbox.jsm", {});
let { gDevTools } = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
const EXAMPLE_URL = "http://example.com/browser/browser/devtools/netmonitor/test/";

View File

@ -506,7 +506,7 @@ DeveloperToolbar.prototype.destroy = function DT_destroy()
let tabbrowser = this._chromeWindow.getBrowser();
tabbrowser.tabContainer.removeEventListener("TabSelect", this, false);
tabbrowser.tabContainer.removeEventListener("TabClose", this, false);
tabbrowser.removeEventListener("load", this, true);
tabbrowser.removeEventListener("load", this, true);
tabbrowser.removeEventListener("beforeunload", this, true);
Array.prototype.forEach.call(tabbrowser.tabs, this._stopErrorsCount, this);

View File

@ -52,6 +52,7 @@ const STR = Services.strings.createBundle(DBG_STRINGS_URI);
*/
this.VariablesView = function VariablesView(aParentNode, aFlags = {}) {
this._store = new Map();
this._items = [];
this._itemsByElement = new WeakMap();
this._prevHierarchy = new Map();
this._currHierarchy = new Map();
@ -103,6 +104,7 @@ VariablesView.prototype = {
let scope = new Scope(this, aName);
this._store.set(scope.id, scope);
this._items.push(scope);
this._currHierarchy.set(aName, scope);
this._itemsByElement.set(scope._target, scope);
scope.header = !!aName;
@ -135,6 +137,7 @@ VariablesView.prototype = {
}
this._store.clear();
this._items.length = 0;
this._itemsByElement.clear();
this._appendEmptyNotice();
@ -161,6 +164,7 @@ VariablesView.prototype = {
let currList = this._list = this.document.createElement("scrollbox");
this._store.clear();
this._items.length = 0;
this._itemsByElement.clear();
this._emptyTimeout = this.window.setTimeout(function() {
@ -529,64 +533,73 @@ VariablesView.prototype = {
},
/**
* Focuses the first visible variable or property in this container.
* Find the first item in the tree of visible items in this container that
* matches the predicate. Searches in visual order (the order seen by the
* user). Descends into each scope to check the scope and its children.
*
* @param function aPredicate
* A function that returns true when a match is found.
* @return Scope | Variable | Property
* The first visible scope, variable or property, or null if nothing
* is found.
*/
focusFirstVisibleNode: function VV_focusFirstVisibleNode() {
let property, variable, scope;
for (let [, item] of this._currHierarchy) {
if (!item.focusable) {
continue;
}
if (item instanceof Property) {
property = item;
break;
} else if (item instanceof Variable) {
variable = item;
break;
} else if (item instanceof Scope) {
scope = item;
break;
_findInVisibleItems: function VV__findInVisibleItems(aPredicate) {
for (let scope of this._items) {
let result = scope._findInVisibleItems(aPredicate);
if (result) {
return result;
}
}
if (scope) {
this._focusItem(scope);
} else if (variable) {
this._focusItem(variable);
} else if (property) {
this._focusItem(property);
return null;
},
/**
* Find the last item in the tree of visible items in this container that
* matches the predicate. Searches in reverse visual order (opposite of the
* order seen by the user). Descends into each scope to check the scope and
* its children.
*
* @param function aPredicate
* A function that returns true when a match is found.
* @return Scope | Variable | Property
* The last visible scope, variable or property, or null if nothing
* is found.
*/
_findInVisibleItemsReverse: function VV__findInVisibleItemsReverse(aPredicate) {
for (let i = this._items.length - 1; i >= 0; i--) {
let scope = this._items[i];
let result = scope._findInVisibleItemsReverse(aPredicate);
if (result) {
return result;
}
}
return null;
},
/**
* Focuses the first visible scope, variable, or property in this container.
*/
focusFirstVisibleNode: function VV_focusFirstVisibleNode() {
let focusableItem = this._findInVisibleItems(item => item.focusable);
if (focusableItem) {
this._focusItem(focusableItem);
}
this._parent.scrollTop = 0;
this._parent.scrollLeft = 0;
},
/**
* Focuses the last visible variable or property in this container.
* Focuses the last visible scope, variable, or property in this container.
*/
focusLastVisibleNode: function VV_focusLastVisibleNode() {
let property, variable, scope;
let focusableItem = this._findInVisibleItemsReverse(item => item.focusable);
for (let [, item] of this._currHierarchy) {
if (!item.focusable) {
continue;
}
if (item instanceof Property) {
property = item;
} else if (item instanceof Variable) {
variable = item;
} else if (item instanceof Scope) {
scope = item;
}
}
if (property && (!variable || property.isDescendantOf(variable))) {
this._focusItem(property);
} else if (variable && (!scope || variable.isDescendantOf(scope))) {
this._focusItem(variable);
} else if (scope) {
this._focusItem(scope);
this._parent.scrollTop = this._parent.scrollHeight;
this._parent.scrollLeft = 0;
if (focusableItem) {
this._focusItem(focusableItem);
}
this._parent.scrollTop = this._parent.scrollHeight;
this._parent.scrollLeft = 0;
},
/**
@ -888,6 +901,7 @@ VariablesView.prototype = {
_window: null,
_store: null,
_items: null,
_prevHierarchy: null,
_currHierarchy: null,
_enumVisible: true,
@ -1082,6 +1096,8 @@ function Scope(aView, aName, aFlags = {}) {
this.separatorStr = aView.separatorStr;
this._store = new Map();
this._enumItems = [];
this._nonEnumItems = [];
this._init(aName.trim(), aFlags);
}
@ -1785,6 +1801,89 @@ Scope.prototype = {
return null;
},
/**
* Find the first item in the tree of visible items in this item that matches
* the predicate. Searches in visual order (the order seen by the user).
* Tests itself, then descends into first the enumerable children and then
* the non-enumerable children (since they are presented in separate groups).
*
* @param function aPredicate
* A function that returns true when a match is found.
* @return Scope | Variable | Property
* The first visible scope, variable or property, or null if nothing
* is found.
*/
_findInVisibleItems: function S__findInVisibleItems(aPredicate) {
if (aPredicate(this)) {
return this;
}
if (this._isExpanded) {
if (this._variablesView._enumVisible) {
for (let item of this._enumItems) {
let result = item._findInVisibleItems(aPredicate);
if (result) {
return result;
}
}
}
if (this._variablesView._nonEnumVisible) {
for (let item of this._nonEnumItems) {
let result = item._findInVisibleItems(aPredicate);
if (result) {
return result;
}
}
}
}
return null;
},
/**
* Find the last item in the tree of visible items in this item that matches
* the predicate. Searches in reverse visual order (opposite of the order
* seen by the user). Descends into first the non-enumerable children, then
* the enumerable children (since they are presented in separate groups), and
* finally tests itself.
*
* @param function aPredicate
* A function that returns true when a match is found.
* @return Scope | Variable | Property
* The last visible scope, variable or property, or null if nothing
* is found.
*/
_findInVisibleItemsReverse: function S__findInVisibleItemsReverse(aPredicate) {
if (this._isExpanded) {
if (this._variablesView._nonEnumVisible) {
for (let i = this._nonEnumItems.length - 1; i >= 0; i--) {
let item = this._nonEnumItems[i];
let result = item._findInVisibleItemsReverse(aPredicate);
if (result) {
return result;
}
}
}
if (this._variablesView._enumVisible) {
for (let i = this._enumItems.length - 1; i >= 0; i--) {
let item = this._enumItems[i];
let result = item._findInVisibleItemsReverse(aPredicate);
if (result) {
return result;
}
}
}
}
if (aPredicate(this)) {
return this;
}
return null;
},
/**
* Gets top level variables view instance.
* @return VariablesView
@ -1854,7 +1953,9 @@ Scope.prototype = {
_name: null,
_title: null,
_enum: null,
_enumItems: null,
_nonenum: null,
_nonEnumItems: null,
_throbber: null
};
@ -2167,8 +2268,10 @@ ViewHelpers.create({ constructor: Variable, proto: Scope.prototype }, {
this._nameString == "this" ||
this._nameString == "<exception>") {
this.ownerView._lazyAppend(aImmediateFlag, true, this._target);
this.ownerView._enumItems.push(this);
} else {
this.ownerView._lazyAppend(aImmediateFlag, false, this._target);
this.ownerView._nonEnumItems.push(this);
}
},
@ -2674,8 +2777,10 @@ ViewHelpers.create({ constructor: Property, proto: Variable.prototype }, {
_onInit: function P__onInit(aImmediateFlag) {
if (this._initialDescriptor.enumerable) {
this.ownerView._lazyAppend(aImmediateFlag, true, this._target);
this.ownerView._enumItems.push(this);
} else {
this.ownerView._lazyAppend(aImmediateFlag, false, this._target);
this.ownerView._nonEnumItems.push(this);
}
}
});

View File

@ -663,9 +663,19 @@ var HeadsUpDisplayUICommands = {
let client = new DebuggerClient(DebuggerServer.connectPipe());
client.connect(() =>
client.listTabs((aResponse) =>
deferred.resolve({ form: aResponse, client: client })
));
client.listTabs((aResponse) => {
// Add Global Process debugging...
let globals = JSON.parse(JSON.stringify(aResponse));
delete globals.tabs;
delete globals.selected;
// ...only if there are appropriate actors (a 'from' property will
// always be there).
if (Object.keys(globals).length > 1) {
deferred.resolve({ form: globals, client: client, chrome: true });
} else {
deferred.reject("Global console not found!");
}
}));
return deferred.promise;
}

View File

@ -12,14 +12,17 @@ function test()
browser.addEventListener("load", function onLoad(aEvent) {
browser.removeEventListener(aEvent.type, onLoad, true);
openConsole(null, function testCSPErrorLogged (hud) {
waitForSuccess({
name: "CSP error displayed successfully",
validatorFn: function () {
return hud.outputNode.textContent.indexOf(CSP_DEPRECATED_HEADER_MSG) > -1;
},
successFn: finishTest,
failureFn: finishTest,
});
waitForMessages({
webconsole: hud,
messages: [
{
name: "Deprecated CSP header error displayed successfully",
text: CSP_DEPRECATED_HEADER_MSG,
category: CATEGORY_SECURITY,
severity: SEVERITY_WARNING
},
],
}).then(finishTest);
});
}, true);
}

View File

@ -4278,6 +4278,7 @@ var Utils = {
return CATEGORY_CSS;
case "Mixed Content Blocker":
case "CSP":
return CATEGORY_SECURITY;
default:

View File

@ -62,8 +62,8 @@
<menuitem id="menu_copyURL" label="&copyURLCmd.label;"
accesskey="&copyURLCmd.accesskey;" command="consoleCmd_copyURL"
selection="network" selectionType="single"/>
<menuitem id="menu_copy"/>
<menuitem id="menu_selectAll"/>
<menuitem id="cMenu_copy"/>
<menuitem id="cMenu_selectAll"/>
</menupopup>
</popupset>

View File

@ -315,6 +315,30 @@ let Util = {
* Screen and layout utilities
*/
/*
* translateToTopLevelWindow - Given an element potentially within
* a subframe, calculate the offsets up to the top level browser.
*/
translateToTopLevelWindow: function translateToTopLevelWindow(aElement) {
let offsetX = 0;
let offsetY = 0;
let element = aElement;
while (element &&
element.ownerDocument &&
element.ownerDocument.defaultView != content) {
element = element.ownerDocument.defaultView.frameElement;
let rect = element.getBoundingClientRect();
offsetX += rect.left;
offsetY += rect.top;
}
let win = null;
if (element == aElement)
win = content;
else
win = element.contentDocument.defaultView;
return { targetWindow: win, offsetX: offsetX, offsetY: offsetY };
},
get displayDPI() {
delete this.displayDPI;
return this.displayDPI = this.getWindowUtils(window).displayDPI;

View File

@ -412,7 +412,7 @@
if (this.controller && this.controller.gridBoundCallback != undefined)
this.controller.gridBoundCallback();
// set up cross-slide gesture handling for multiple-selection grids
if (CrossSlide && "multiple" == this.getAttribute("seltype")) {
if ("undefined" !== typeof CrossSlide && "multiple" == this.getAttribute("seltype")) {
this._xslideHandler = new CrossSlide.Handler(this, {
REARRANGESTART: this.crossSlideBoundary
});

View File

@ -46,161 +46,6 @@ const kReferenceDpi = 240; // standard "pixel" size used in some preferences
const kStateActive = 0x00000001; // :active pseudoclass for elements
/*
* ElementTouchHelper
*
* Assists users by watching for mouse clicks in content and redirect
* them to the best found target.
*/
const ElementTouchHelper = {
get radius() {
let prefs = Services.prefs;
delete this.radius;
return this.radius = { "top": prefs.getIntPref("ui.touch.radius.topmm"),
"right": prefs.getIntPref("ui.touch.radius.rightmm"),
"bottom": prefs.getIntPref("ui.touch.radius.bottommm"),
"left": prefs.getIntPref("ui.touch.radius.leftmm")
};
},
get weight() {
delete this.weight;
return this.weight = { "visited": Services.prefs.getIntPref("ui.touch.radius.visitedWeight")
};
},
/* Retrieve the closest element to a point by looking at borders position */
getClosest: function getClosest(aWindowUtils, aX, aY) {
if (!this.dpiRatio)
this.dpiRatio = aWindowUtils.displayDPI / kReferenceDpi;
let dpiRatio = this.dpiRatio;
let target = aWindowUtils.elementFromPoint(aX, aY,
true, /* ignore root scroll frame*/
false); /* don't flush layout */
// return early if the click is just over a clickable element
if (this._isElementClickable(target))
return target;
let nodes = aWindowUtils.nodesFromRect(aX, aY, this.radius.top * dpiRatio,
this.radius.right * dpiRatio,
this.radius.bottom * dpiRatio,
this.radius.left * dpiRatio, true, false);
let threshold = Number.POSITIVE_INFINITY;
for (let i = 0; i < nodes.length; i++) {
let current = nodes[i];
if (!current.mozMatchesSelector || !this._isElementClickable(current))
continue;
let rect = current.getBoundingClientRect();
let distance = this._computeDistanceFromRect(aX, aY, rect);
// increase a little bit the weight for already visited items
if (current && current.mozMatchesSelector("*:visited"))
distance *= (this.weight.visited / 100);
if (distance < threshold) {
target = current;
threshold = distance;
}
}
return target;
},
_isElementClickable: function _isElementClickable(aElement) {
const selector = "a,:link,:visited,[role=button],button,input,select,textarea,label";
for (let elem = aElement; elem; elem = elem.parentNode) {
if (this._hasMouseListener(elem))
return true;
if (elem.mozMatchesSelector && elem.mozMatchesSelector(selector))
return true;
}
return false;
},
_computeDistanceFromRect: function _computeDistanceFromRect(aX, aY, aRect) {
let x = 0, y = 0;
let xmost = aRect.left + aRect.width;
let ymost = aRect.top + aRect.height;
// compute horizontal distance from left/right border depending if X is
// before/inside/after the element's rectangle
if (aRect.left < aX && aX < xmost)
x = Math.min(xmost - aX, aX - aRect.left);
else if (aX < aRect.left)
x = aRect.left - aX;
else if (aX > xmost)
x = aX - xmost;
// compute vertical distance from top/bottom border depending if Y is
// above/inside/below the element's rectangle
if (aRect.top < aY && aY < ymost)
y = Math.min(ymost - aY, aY - aRect.top);
else if (aY < aRect.top)
y = aRect.top - aY;
if (aY > ymost)
y = aY - ymost;
return Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
},
_els: Cc["@mozilla.org/eventlistenerservice;1"].getService(Ci.nsIEventListenerService),
_clickableEvents: ["mousedown", "mouseup", "click"],
_hasMouseListener: function _hasMouseListener(aElement) {
let els = this._els;
let listeners = els.getListenerInfoFor(aElement, {});
for (let i = 0; i < listeners.length; i++) {
if (this._clickableEvents.indexOf(listeners[i].type) != -1)
return true;
}
return false;
}
};
/*
* Global functions
*/
/*
* elementFromPoint - find the closes element at a point. searches
* sub-frames.
*
* @param aX, aY browser coordinates
* @return
* element - element at the position, or null if no active browser or
* element was found.
* frameX - x position within the subframe element was found. aX if no
* sub-frame was found.
* frameY - y position within the subframe element was found. aY if no
* sub-frame was found.
*/
function elementFromPoint(aX, aY) {
// browser's elementFromPoint expect browser-relative client coordinates.
// subtract browser's scroll values to adjust
let cwu = Util.getWindowUtils(content);
let elem = ElementTouchHelper.getClosest(cwu, aX, aY);
// step through layers of IFRAMEs and FRAMES to find innermost element
while (elem && (elem instanceof HTMLIFrameElement ||
elem instanceof HTMLFrameElement)) {
// adjust client coordinates' origin to be top left of iframe viewport
let rect = elem.getBoundingClientRect();
aX -= rect.left;
aY -= rect.top;
let windowUtils = elem.contentDocument
.defaultView
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
elem = ElementTouchHelper.getClosest(windowUtils, aX, aY);
}
return { element: elem, frameX: aX, frameY: aY };
}
/*
* getBoundingContentRect
*
@ -349,8 +194,7 @@ let Content = {
break;
case "touchstart":
let touch = aEvent.changedTouches[0];
this._onTouchStart(touch.clientX, touch.clientY);
this._onTouchStart(aEvent);
break;
}
},
@ -403,10 +247,8 @@ let Content = {
* Event handlers
*/
_onTouchStart: function _onTouchStart(x, y) {
let { element } = elementFromPoint(x, y);
if (!element)
return;
_onTouchStart: function _onTouchStart(aEvent) {
let element = aEvent.target;
// There is no need to have a feedback for disabled element
let isDisabled = element instanceof HTMLOptionElement ?
@ -419,11 +261,9 @@ let Content = {
},
_onClickCapture: function _onClickCapture(aEvent) {
ContextMenuHandler.reset();
let element = aEvent.target;
let { element: element } = elementFromPoint(aEvent.clientX, aEvent.clientY);
if (!element)
return;
ContextMenuHandler.reset();
// Only show autocomplete after the item is clicked
if (!this.lastClickElement || this.lastClickElement != element) {
@ -442,9 +282,10 @@ let Content = {
// A tap on a form input triggers touch input caret selection
if (Util.isTextInput(element) &&
aEvent.mozInputSource == Ci.nsIDOMMouseEvent.MOZ_SOURCE_TOUCH) {
let { offsetX, offsetY } = Util.translateToTopLevelWindow(element);
sendAsyncMessage("Content:SelectionCaret", {
xPos: aEvent.clientX,
yPos: aEvent.clientY
xPos: aEvent.clientX + offsetX,
yPos: aEvent.clientY + offsetY
});
}
},

View File

@ -159,31 +159,6 @@ var ContextMenuHandler = {
* Utility routines
*/
/*
* _translateToTopLevelWindow - Given a potential coordinate set within
* a subframe, translate up to the parent window which is what front
* end code expect.
*/
_translateToTopLevelWindow: function _translateToTopLevelWindow(aPopupNode) {
let offsetX = 0;
let offsetY = 0;
let element = aPopupNode;
while (element &&
element.ownerDocument &&
element.ownerDocument.defaultView != content) {
element = element.ownerDocument.defaultView.frameElement;
let rect = element.getBoundingClientRect();
offsetX += rect.left;
offsetY += rect.top;
}
let win = null;
if (element == aPopupNode)
win = content;
else
win = element.contentDocument.defaultView;
return { targetWindow: win, offsetX: offsetX, offsetY: offsetY };
},
/*
* _processPopupNode - Generate and send a Content:ContextMenu message
* to browser detailing the underlying content types at this.popupNode.
@ -197,7 +172,7 @@ var ContextMenuHandler = {
let { targetWindow: targetWindow,
offsetX: offsetX,
offsetY: offsetY } =
this._translateToTopLevelWindow(aPopupNode);
Util.translateToTopLevelWindow(aPopupNode);
let popupNode = this.popupNode = aPopupNode;
let imageUrl = "";

View File

@ -574,7 +574,8 @@ var SelectionHandler = {
_restrictSelectionRectToEditBounds: function _restrictSelectionRectToEditBounds() {
if (!this._targetIsEditable)
return;
let bounds = this._getTargetClientRect();
let bounds = this._getTargetBrowserRect();
if (this._cache.start.xPos < bounds.left)
this._cache.start.xPos = bounds.left;
if (this._cache.end.xPos < bounds.left)
@ -794,7 +795,7 @@ var SelectionHandler = {
* @return new constrained point struct
*/
_constrainPointWithinControl: function _cpwc(aPoint, aHalfLineHeight) {
let bounds = this._getTargetClientRect();
let bounds = this._getTargetBrowserRect();
let point = { xPos: aPoint.xPos, yPos: aPoint.yPos };
if (point.xPos <= bounds.left)
point.xPos = bounds.left + 2;
@ -815,7 +816,7 @@ var SelectionHandler = {
* Works on client coordinates.
*/
_pointOrientationToRect: function _pointOrientationToRect(aPoint) {
let bounds = this._targetElement.getBoundingClientRect();
let bounds = this._getTargetBrowserRect();
let result = { left: 0, right: 0, top: 0, bottom: 0 };
if (aPoint.xPos <= bounds.left)
result.left = bounds.left - aPoint.xPos;
@ -1103,7 +1104,7 @@ var SelectionHandler = {
// height of the target element
let targetHeight = this._cache.element.bottom - this._cache.element.top;
// height of the browser view.
let viewBottom = this._targetElement.ownerDocument.defaultView.innerHeight;
let viewBottom = content.innerHeight;
// If the target is shorter than the new content height, we can go ahead
// and center it.
@ -1294,10 +1295,27 @@ var SelectionHandler = {
return seldata;
},
/*
* Returns bounds of the element relative to the inner sub frame it sits
* in.
*/
_getTargetClientRect: function _getTargetClientRect() {
return this._targetElement.getBoundingClientRect();
},
/*
* Returns bounds of the element relative to the top level browser.
*/
_getTargetBrowserRect: function _getTargetBrowserRect() {
let client = this._getTargetClientRect();
return {
left: client.left + this._contentOffset.x,
top: client.top + this._contentOffset.y,
right: client.right + this._contentOffset.x,
bottom: client.bottom + this._contentOffset.y
};
},
/*
* Translate a top level client point to frame relative client point.
*/

View File

@ -21,19 +21,20 @@ BROWSER_TESTS = \
browser_onscreen_keyboard.html \
browser_remotetabs.js \
browser_downloads.js \
browser_plugin_input.html \
browser_plugin_input_mouse.js \
browser_plugin_input_keyboard.js \
browser_context_menu_tests.js \
browser_context_menu_tests_01.html \
browser_context_menu_tests_02.html \
browser_context_menu_tests_03.html \
text-block.html \
browser_prefs_ui.js \
browser_topsites.js \
browser_tabs.js \
$(NULL)
# disabled due to timeouts and lack of plugin support.
# browser_plugin_input.html \
# browser_plugin_input_mouse.js \
# browser_plugin_input_keyboard.js \
ifndef MOZ_DEBUG
BROWSER_TESTS += \
browser_selection_basic.js \
@ -42,11 +43,19 @@ BROWSER_TESTS += \
browser_selection_textarea.html \
browser_selection_frame_content.js \
browser_selection_frame_content.html \
browser_selection_inputs.js \
browser_selection_inputs.html \
browser_selection_frame_textarea.js \
browser_selection_frame_textarea.html \
browser_selection_frame_inputs.js \
browser_selection_frame_inputs.html \
$(NULL)
endif
BROWSER_TEST_RESOURCES = \
res/image01.png \
res/textblock01.html \
res/textinput01.html \
$(NULL)
libs:: $(BROWSER_TESTS)

View File

@ -9,7 +9,7 @@
Hello there. <a href="#hello">hello there.</a>
<div style="margin-left: 280px;">
<iframe id="frame1" width="800" height="600" src="text-block.html"></iframe>
<iframe id="frame1" width="800" height="600" src="res/textblock01.html"></iframe>
<br />
<br />

View File

@ -25,7 +25,6 @@ function setUpAndTearDown() {
yield waitForCondition(function () {
return !SelectionHelperUI.isSelectionUIVisible;
}, kCommonWaitMs, kCommonPollMs);
yield hideContextUI();
}
gTests.push({
@ -40,6 +39,8 @@ gTests.push({
return !StartUI.isStartPageVisible;
}, 10000, 100);
yield hideContextUI();
gWindow = Browser.selectedTab.browser.contentWindow;
InputSourceHelper.isPrecise = false;
},

View File

@ -4,7 +4,7 @@
</head>
<body>
<div>
<iframe id="frame1" width="800" height="600" src="text-block.html"></iframe>
<iframe id="frame1" width="800" height="600" src="res/textblock01.html"></iframe>
<br />
<br />
Hello there. <a id="rlink1" href="#hello">Hi!</a>

View File

@ -25,7 +25,6 @@ function setUpAndTearDown() {
yield waitForCondition(function () {
return !SelectionHelperUI.isSelectionUIVisible;
}, kCommonWaitMs, kCommonPollMs);
yield hideContextUI();
}
gTests.push({
@ -40,6 +39,8 @@ gTests.push({
return !StartUI.isStartPageVisible;
}, 10000, 100);
yield hideContextUI();
gWindow = Browser.selectedTab.browser.contentWindow;
gFrame = gWindow.document.getElementById("frame1");
@ -212,11 +213,6 @@ gTests.push({
});
function test() {
if (isDebugBuild()) {
todo(false, "selection tests can't run in debug builds.");
return;
}
if (!isLandscapeMode()) {
todo(false, "browser_selection_tests need landscape mode to run.");
return;

View File

@ -0,0 +1,82 @@
<!DOCTYPE html>
<html>
<head>
<style>
</style>
</head>
<body style="margin: 5px 5px 5px 85px;">
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<div><p>
<iframe id="frame1" style="border: 0px;" height="200" src="res/textinput01.html" width="600"></iframe>
</p></div>
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
</body>
</html>

View File

@ -0,0 +1,162 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
let gWindow = null;
var gFrame = null;
var gInput = null;
const kMarkerOffsetY = 12;
const kCommonWaitMs = 5000;
const kCommonPollMs = 100;
///////////////////////////////////////////////////
// form input tests
///////////////////////////////////////////////////
function setUpAndTearDown() {
emptyClipboard();
if (gWindow)
clearSelection(gWindow);
if (gFrame)
clearSelection(gFrame);
if (gInput)
clearSelection(gInput);
yield waitForCondition(function () {
return !SelectionHelperUI.isSelectionUIVisible;
}, kCommonWaitMs, kCommonPollMs);
}
gTests.push({
desc: "normalize browser",
setUp: setUpAndTearDown,
tearDown: setUpAndTearDown,
run: function test() {
info(chromeRoot + "browser_selection_frame_inputs.html");
yield addTab(chromeRoot + "browser_selection_frame_inputs.html");
yield waitForCondition(function () {
return !StartUI.isStartPageVisible;
}, 10000, 100);
yield hideContextUI();
gWindow = Browser.selectedTab.browser.contentWindow;
gFrame = gWindow.document.getElementById("frame1");
gInput = gFrame.contentDocument.getElementById("textinput");
ok(gWindow != null, "gWindow");
ok(gFrame != null, "gFrame");
ok(gInput != null, "gInput");
InputSourceHelper.isPrecise = false;
},
});
gTests.push({
desc: "basic selection",
setUp: setUpAndTearDown,
tearDown: setUpAndTearDown,
run: function test() {
gInput.focus();
gInput.selectionStart = gInput.selectionEnd = 0;
let promise = waitForEvent(document, "popupshown");
sendContextMenuClick(232, 583);
yield promise;
checkContextUIMenuItemVisibility(["context-select",
"context-select-all"]);
let menuItem = document.getElementById("context-select");
ok(menuItem, "menu item exists");
ok(!menuItem.hidden, "menu item visible");
let popupPromise = waitForEvent(document, "popuphidden");
EventUtils.synthesizeMouse(menuItem, 10, 10, {}, gWindow);
yield popupPromise;
yield waitForCondition(function () {
return SelectionHelperUI.isSelectionUIVisible;
}, kCommonWaitMs, kCommonPollMs);
is(getTrimmedSelection(gInput).toString(), "straight", "selection test");
checkMonoclePositionRange("start", 210, 220, 600, 605);
checkMonoclePositionRange("end", 250, 260, 600, 605);
},
});
gTests.push({
desc: "drag selection",
setUp: setUpAndTearDown,
tearDown: setUpAndTearDown,
run: function test() {
gInput.focus();
gInput.selectionStart = gInput.selectionEnd = 0;
let promise = waitForEvent(document, "popupshown");
sendContextMenuClick(232, 583);
yield promise;
checkContextUIMenuItemVisibility(["context-select",
"context-select-all"]);
let menuItem = document.getElementById("context-select");
ok(menuItem, "menu item exists");
ok(!menuItem.hidden, "menu item visible");
let popupPromise = waitForEvent(document, "popuphidden");
EventUtils.synthesizeMouse(menuItem, 10, 10, {}, gWindow);
yield popupPromise;
yield waitForCondition(function () {
return SelectionHelperUI.isSelectionUIVisible;
}, kCommonWaitMs, kCommonPollMs);
is(getTrimmedSelection(gInput).toString(), "straight", "selection test");
// end marker to the right
let xpos = SelectionHelperUI.endMark.xPos;
let ypos = SelectionHelperUI.endMark.yPos + 10;
var touchdrag = new TouchDragAndHold();
yield touchdrag.start(gWindow, xpos, ypos, xpos + 350, ypos);
yield waitForCondition(function () {
return getTrimmedSelection(gInput).toString() ==
"straight on like a tunnel for some way and then dipped suddenly down";
}, 6000, 2000);
touchdrag.end();
yield waitForCondition(function () {
return !SelectionHelperUI.hasActiveDrag;
}, kCommonWaitMs, kCommonPollMs);
yield SelectionHelperUI.pingSelectionHandler();
// start marker to the left
let xpos = SelectionHelperUI.startMark.xPos;
let ypos = SelectionHelperUI.startMark.yPos + 10;
var touchdrag = new TouchDragAndHold();
yield touchdrag.start(gWindow, xpos, ypos, 10, ypos);
yield waitForCondition(function () {
return getTrimmedSelection(gInput).toString() ==
"The rabbit-hole went straight on like a tunnel for some way and then dipped suddenly down";
}, 6000, 2000);
touchdrag.end();
yield waitForCondition(function () {
return !SelectionHelperUI.hasActiveDrag;
}, kCommonWaitMs, kCommonPollMs);
yield SelectionHelperUI.pingSelectionHandler();
},
});
function test() {
if (!isLandscapeMode()) {
todo(false, "browser_selection_tests need landscape mode to run.");
return;
}
requestLongerTimeout(3);
runTests();
}

View File

@ -0,0 +1,82 @@
<!DOCTYPE html>
<html>
<head>
<style>
</style>
</head>
<body style="margin: 5px 5px 5px 85px;">
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<div><p>
<iframe id="frame1" style="border: 0px;" height="200" src="res/textarea01.html" width="600"></iframe>
</p></div>
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
</body>
</html>

View File

@ -0,0 +1,257 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
let gWindow = null;
var gFrame = null;
var gTextArea = null;
const kMarkerOffsetY = 12;
const kCommonWaitMs = 5000;
const kCommonPollMs = 100;
///////////////////////////////////////////////////
// form input tests
///////////////////////////////////////////////////
function setUpAndTearDown() {
emptyClipboard();
if (gWindow)
clearSelection(gWindow);
if (gFrame)
clearSelection(gFrame);
if (gTextArea)
clearSelection(gTextArea);
yield waitForCondition(function () {
return !SelectionHelperUI.isSelectionUIVisible;
}, kCommonWaitMs, kCommonPollMs);
}
gTests.push({
desc: "normalize browser",
setUp: setUpAndTearDown,
tearDown: setUpAndTearDown,
run: function test() {
info(chromeRoot + "browser_selection_frame_textarea.html");
yield addTab(chromeRoot + "browser_selection_frame_textarea.html");
yield waitForCondition(function () {
return !StartUI.isStartPageVisible;
}, 10000, 100);
yield hideContextUI();
gWindow = Browser.selectedTab.browser.contentWindow;
gFrame = gWindow.document.getElementById("frame1");
gTextArea = gFrame.contentDocument.getElementById("textarea");
ok(gWindow != null, "gWindow");
ok(gFrame != null, "gFrame");
ok(gTextArea != null, "gTextArea");
InputSourceHelper.isPrecise = false;
},
});
gTests.push({
desc: "basic selection",
setUp: setUpAndTearDown,
tearDown: setUpAndTearDown,
run: function test() {
gTextArea.focus();
gTextArea.selectionStart = gTextArea.selectionEnd = 0;
let promise = waitForEvent(document, "popupshown");
sendContextMenuClick(275, 663);
yield promise;
checkContextUIMenuItemVisibility(["context-select",
"context-select-all"]);
let menuItem = document.getElementById("context-select");
ok(menuItem, "menu item exists");
ok(!menuItem.hidden, "menu item visible");
let popupPromise = waitForEvent(document, "popuphidden");
EventUtils.synthesizeMouse(menuItem, 10, 10, {}, gWindow);
yield popupPromise;
yield waitForCondition(function () {
return SelectionHelperUI.isSelectionUIVisible;
}, kCommonWaitMs, kCommonPollMs);
is(getTrimmedSelection(gTextArea).toString(), "wondered", "selection test");
checkMonoclePositionRange("start", 260, 275, 675, 685);
checkMonoclePositionRange("end", 320, 335, 675, 685);
},
});
gTests.push({
desc: "drag selection",
setUp: setUpAndTearDown,
tearDown: setUpAndTearDown,
run: function test() {
gTextArea.focus();
gTextArea.selectionStart = gTextArea.selectionEnd = 0;
let promise = waitForEvent(document, "popupshown");
sendContextMenuClick(275, 663);
yield promise;
checkContextUIMenuItemVisibility(["context-select",
"context-select-all"]);
let menuItem = document.getElementById("context-select");
ok(menuItem, "menu item exists");
ok(!menuItem.hidden, "menu item visible");
let popupPromise = waitForEvent(document, "popuphidden");
EventUtils.synthesizeMouse(menuItem, 10, 10, {}, gWindow);
yield popupPromise;
yield waitForCondition(function () {
return SelectionHelperUI.isSelectionUIVisible;
}, kCommonWaitMs, kCommonPollMs);
is(getTrimmedSelection(gTextArea).toString(), "wondered", "selection test");
// end marker to the right
let xpos = SelectionHelperUI.endMark.xPos;
let ypos = SelectionHelperUI.endMark.yPos + 10;
var touchdrag = new TouchDragAndHold();
yield touchdrag.start(gWindow, xpos, ypos, xpos + 150, ypos);
yield waitForCondition(function () {
return getTrimmedSelection(gTextArea).toString() ==
"wondered at this,";
}, 6000, 2000);
touchdrag.end();
yield waitForCondition(function () {
return !SelectionHelperUI.hasActiveDrag;
}, kCommonWaitMs, kCommonPollMs);
yield SelectionHelperUI.pingSelectionHandler();
// start marker up and to the left
let xpos = SelectionHelperUI.startMark.xPos;
let ypos = SelectionHelperUI.startMark.yPos + 10;
var touchdrag = new TouchDragAndHold();
yield touchdrag.start(gWindow, xpos, ypos, 40, 500);
yield waitForCondition(function () {
return getTrimmedSelection(gTextArea).toString().substring(0, 17) ==
"There was nothing";
}, 6000, 2000);
touchdrag.end();
let promise = waitForEvent(document, "popupshown");
sendContextMenuClick(250, 640);
yield promise;
checkContextUIMenuItemVisibility(["context-cut",
"context-copy"]);
let menuItem = document.getElementById("context-copy");
ok(menuItem, "menu item exists");
ok(!menuItem.hidden, "menu item visible");
let popupPromise = waitForEvent(document, "popuphidden");
EventUtils.synthesizeMouse(menuItem, 10, 10, {}, gWindow);
yield popupPromise;
let string = "";
yield waitForCondition(function () {
string = SpecialPowers.getClipboardData("text/unicode");
return string.substring(0, 17) === "There was nothing";
});
},
});
gTests.push({
desc: "drag selection",
setUp: setUpAndTearDown,
tearDown: setUpAndTearDown,
run: function test() {
gTextArea.focus();
gTextArea.selectionStart = gTextArea.selectionEnd = 0;
let scrollPromise = waitForEvent(gWindow, "scroll");
gWindow.scrollBy(0, 200);
yield scrollPromise;
let promise = waitForEvent(document, "popupshown");
sendContextMenuClick(275, 463);
yield promise;
checkContextUIMenuItemVisibility(["context-select",
"context-select-all"]);
let menuItem = document.getElementById("context-select");
ok(menuItem, "menu item exists");
ok(!menuItem.hidden, "menu item visible");
let popupPromise = waitForEvent(document, "popuphidden");
EventUtils.synthesizeMouse(menuItem, 10, 10, {}, gWindow);
yield popupPromise;
yield waitForCondition(function () {
return SelectionHelperUI.isSelectionUIVisible;
}, kCommonWaitMs, kCommonPollMs);
is(getTrimmedSelection(gTextArea).toString(), "wondered", "selection test");
// end marker to the right
let xpos = SelectionHelperUI.endMark.xPos;
let ypos = SelectionHelperUI.endMark.yPos + 10;
var touchdrag = new TouchDragAndHold();
yield touchdrag.start(gWindow, xpos, ypos, xpos + 150, ypos);
yield waitForCondition(function () {
return getTrimmedSelection(gTextArea).toString() ==
"wondered at this,";
}, 6000, 2000);
touchdrag.end();
yield waitForCondition(function () {
return !SelectionHelperUI.hasActiveDrag;
}, kCommonWaitMs, kCommonPollMs);
yield SelectionHelperUI.pingSelectionHandler();
// start marker up and to the left
let xpos = SelectionHelperUI.startMark.xPos;
let ypos = SelectionHelperUI.startMark.yPos + 10;
var touchdrag = new TouchDragAndHold();
yield touchdrag.start(gWindow, xpos, ypos, 40, 300);
yield waitForCondition(function () {
return getTrimmedSelection(gTextArea).toString().substring(0, 17) ==
"There was nothing";
}, 6000, 2000);
touchdrag.end();
let promise = waitForEvent(document, "popupshown");
sendContextMenuClick(250, 440);
yield promise;
checkContextUIMenuItemVisibility(["context-cut",
"context-copy"]);
let menuItem = document.getElementById("context-copy");
ok(menuItem, "menu item exists");
ok(!menuItem.hidden, "menu item visible");
let popupPromise = waitForEvent(document, "popuphidden");
EventUtils.synthesizeMouse(menuItem, 10, 10, {}, gWindow);
yield popupPromise;
let string = "";
yield waitForCondition(function () {
string = SpecialPowers.getClipboardData("text/unicode");
return string.substring(0, 17) === "There was nothing";
});
},
});
function test() {
if (!isLandscapeMode()) {
todo(false, "browser_selection_tests need landscape mode to run.");
return;
}
requestLongerTimeout(3);
runTests();
}

View File

@ -0,0 +1,8 @@
<!DOCTYPE html>
<html>
<head>
</head>
<body style="margin: 5px 5px 5px 85px;">
<input id="a" style="width:300px; height:25px;" value="The rabbit-hole went straight on like a tunnel for some way and then dipped suddenly down" type="text">
</body>
</html>

View File

@ -0,0 +1,205 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
let gWindow = null;
var gInput = null;
const kMarkerOffsetY = 12;
const kCommonWaitMs = 5000;
const kCommonPollMs = 100;
///////////////////////////////////////////////////
// form input tests
///////////////////////////////////////////////////
function setUpAndTearDown() {
emptyClipboard();
if (gWindow)
clearSelection(gWindow);
if (gInput)
clearSelection(gInput);
yield waitForCondition(function () {
return !SelectionHelperUI.isSelectionUIVisible;
}, kCommonWaitMs, kCommonPollMs);
}
/*
5px top margin
25px tall text input
300px wide
*/
gTests.push({
desc: "normalize browser",
setUp: setUpAndTearDown,
tearDown: setUpAndTearDown,
run: function test() {
info(chromeRoot + "browser_selection_inputs.html");
yield addTab(chromeRoot + "browser_selection_inputs.html");
yield waitForCondition(function () {
return !StartUI.isStartPageVisible;
}, 10000, 100);
yield hideContextUI();
gWindow = Browser.selectedTab.browser.contentWindow;
gInput = gWindow.document.getElementById("a");
InputSourceHelper.isPrecise = false;
},
});
gTests.push({
desc: "basic text input selection",
setUp: setUpAndTearDown,
tearDown: setUpAndTearDown,
run: function test() {
gInput.focus();
gInput.selectionStart = gInput.selectionEnd = 0;
let promise = waitForEvent(document, "popupshown");
sendContextMenuClick(200, 17);
yield promise;
checkContextUIMenuItemVisibility(["context-select",
"context-select-all"]);
let menuItem = document.getElementById("context-select");
ok(menuItem, "menu item exists");
ok(!menuItem.hidden, "menu item visible");
let popupPromise = waitForEvent(document, "popuphidden");
EventUtils.synthesizeMouse(menuItem, 10, 10, {}, gWindow);
yield popupPromise;
yield waitForCondition(function () {
return SelectionHelperUI.isSelectionUIVisible;
}, kCommonWaitMs, kCommonPollMs);
is(getTrimmedSelection(gInput).toString(), "went", "selection test");
},
});
gTests.push({
desc: "drag left to scroll",
setUp: setUpAndTearDown,
tearDown: setUpAndTearDown,
run: function test() {
gInput.selectionStart = gInput.selectionEnd = gInput.value.length;
let promise = waitForEvent(document, "popupshown");
sendContextMenuClick(190, 17);
yield promise;
checkContextUIMenuItemVisibility(["context-select",
"context-select-all"]);
let menuItem = document.getElementById("context-select");
ok(menuItem, "menu item exists");
ok(!menuItem.hidden, "menu item visible");
let popupPromise = waitForEvent(document, "popuphidden");
EventUtils.synthesizeMouse(menuItem, 10, 10, {}, gWindow);
yield popupPromise;
yield waitForCondition(function () {
return SelectionHelperUI.isSelectionUIVisible;
}, kCommonWaitMs, kCommonPollMs);
// check text selection
is(getTrimmedSelection(gInput).toString(), "way", "selection test");
// to the left
let xpos = SelectionHelperUI.startMark.xPos;
let ypos = SelectionHelperUI.startMark.yPos + 10;
var touchdrag = new TouchDragAndHold();
yield touchdrag.start(gWindow, xpos, ypos, 10, ypos);
yield waitForCondition(function () {
return getTrimmedSelection(gInput).toString() ==
"The rabbit-hole went straight on like a tunnel for some way";
}, 6000, 2000);
touchdrag.end();
yield waitForCondition(function () {
return !SelectionHelperUI.hasActiveDrag;
}, kCommonWaitMs, kCommonPollMs);
yield SelectionHelperUI.pingSelectionHandler();
},
});
gTests.push({
desc: "drag right to scroll and bug 862025",
setUp: setUpAndTearDown,
tearDown: setUpAndTearDown,
run: function test() {
gInput.selectionStart = gInput.selectionEnd = 0;
let promise = waitForEvent(document, "popupshown");
sendContextMenuClick(230, 17);
yield promise;
checkContextUIMenuItemVisibility(["context-select",
"context-select-all"]);
let menuItem = document.getElementById("context-select");
ok(menuItem, "menu item exists");
ok(!menuItem.hidden, "menu item visible");
let popupPromise = waitForEvent(document, "popuphidden");
EventUtils.synthesizeMouse(menuItem, 10, 10, {}, gWindow);
yield popupPromise;
yield waitForCondition(function () {
return SelectionHelperUI.isSelectionUIVisible;
}, kCommonWaitMs, kCommonPollMs);
// check text selection
is(getTrimmedSelection(gInput).toString(), "straight", "selection test");
// to the right
let xpos = SelectionHelperUI.endMark.xPos;
let ypos = SelectionHelperUI.endMark.yPos + 10;
var touchdrag = new TouchDragAndHold();
yield touchdrag.start(gWindow, xpos, ypos, 510, ypos);
yield waitForCondition(function () {
return getTrimmedSelection(gInput).toString() ==
"straight on like a tunnel for some way and then dipped suddenly down";
}, 6000, 2000);
touchdrag.end();
yield waitForCondition(function () {
return !SelectionHelperUI.hasActiveDrag;
}, kCommonWaitMs, kCommonPollMs);
yield SelectionHelperUI.pingSelectionHandler();
// down - selection shouldn't change
let xpos = SelectionHelperUI.endMark.xPos;
let ypos = SelectionHelperUI.endMark.yPos + 10;
yield touchdrag.start(gWindow, xpos, ypos, xpos, ypos + 150);
yield waitForMs(2000);
touchdrag.end();
is(getTrimmedSelection(gInput).toString(), "straight on like a tunnel for some way and then dipped suddenly down", "selection test");
// left and up - selection should shrink
let xpos = SelectionHelperUI.endMark.xPos;
let ypos = SelectionHelperUI.endMark.yPos + 10;
yield touchdrag.start(gWindow, xpos, ypos, 105, 25);
yield waitForCondition(function () {
return getTrimmedSelection(gInput).toString() ==
"straight on like a tunnel for";
}, 6000, 2000);
touchdrag.end();
},
});
function test() {
if (!isLandscapeMode()) {
todo(false, "browser_selection_tests need landscape mode to run.");
return;
}
requestLongerTimeout(3);
runTests();
}

View File

@ -25,7 +25,6 @@ function setUpAndTearDown() {
yield waitForCondition(function () {
return !SelectionHelperUI.isSelectionUIVisible;
}, kCommonWaitMs, kCommonPollMs);
yield hideContextUI();
}
gTests.push({
@ -40,6 +39,8 @@ gTests.push({
return !StartUI.isStartPageVisible;
}, 10000, 100);
yield hideContextUI();
gWindow = Browser.selectedTab.browser.contentWindow;
InputSourceHelper.isPrecise = false;
},
@ -143,11 +144,6 @@ gTests.push({
});
function test() {
if (isDebugBuild()) {
todo(false, "selection tests can't run in debug builds.");
return;
}
if (!isLandscapeMode()) {
todo(false, "browser_selection_tests need landscape mode to run.");
return;

View File

@ -55,6 +55,24 @@ function checkContextUIMenuItemVisibility(aVisibleList)
is(errors, 0, "context menu item list visibility");
}
function checkMonoclePositionRange(aMonocle, aMinX, aMaxX, aMinY, aMaxY)
{
let monocle = null;
if (aMonocle == "start")
monocle = SelectionHelperUI._startMark;
else if (aMonocle == "end")
monocle = SelectionHelperUI._endMark;
else if (aMonocle == "caret")
monocle = SelectionHelperUI._caretMark;
else
ok(false, "bad monocle id");
ok(monocle.xPos > aMinX && monocle.xPos < aMaxX,
"X position is " + monocle.xPos + ", expected between " + aMinX + " and " + aMaxX);
ok(monocle.yPos > aMinY && monocle.yPos < aMaxY,
"Y position is " + monocle.yPos + ", expected between " + aMinY + " and " + aMaxY);
}
/*
* showNotification - displays a test notification with the current
* browser and waits for the noticiation to be fully displayed.
@ -184,7 +202,7 @@ function addTab(aUrl) {
return Task.spawn(function() {
info("Opening "+aUrl+" in a new tab");
let tab = Browser.addTab(aUrl, true);
yield waitForEvent(tab.browser, "pageshow");
yield tab.pageShowPromise;
is(tab.browser.currentURI.spec, aUrl, aUrl + " is loaded");
registerCleanupFunction(function() Browser.closeTab(tab));
@ -213,7 +231,6 @@ function addTab(aUrl) {
* @returns a Promise that resolves to the received event, or to an Error
*/
function waitForEvent(aSubject, aEventName, aTimeoutMs) {
info("waitForEvent: on " + aSubject + " event: " + aEventName);
let eventDeferred = Promise.defer();
let timeoutMs = aTimeoutMs || kDefaultWait;
let timerID = setTimeout(function wfe_canceller() {
@ -548,8 +565,11 @@ TouchDragAndHold.prototype = {
_timeoutStep: 2,
_numSteps: 50,
_debug: false,
_win: null,
callback: function callback() {
if (this._win == null)
return;
if (++this._step.steps >= this._numSteps) {
EventUtils.synthesizeTouchAtPoint(this._endPoint.xPos, this._endPoint.yPos,
{ type: "touchmove" }, this._win);

View File

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html>
<head>
<style>
body {
padding: 0;
margin: 0;
}
</style>
</head>
<body>
<textarea id="textarea" style="overflow: hidden;" name="textarea" rows="10" cols="50">
There was nothing so VERY remarkable in that; nor did Alice think it so VERY much out of
the way to hear the Rabbit say to itself, `Oh dear! Oh dear! I shall be late!' (when she
thought it over afterwards, it occurred to her that she ought to have wondered at this,
but at the time it all seemed quite natural); but when the Rabbit actually TOOK A WATCH
OUT OF ITS WAISTCOAT-POCKET, and looked at it, and then hurried on, Alice started to her
feet, for it flashed across her mind that she had never before seen a rabbit with either a
waistcoat-pocket, or a watch to take out of it, and burning with curiosity, she ran across
the field after it, and fortunately was just in time to see it pop down a large rabbit-hole
under the hedge.
</textarea>
</body>
</html>

View File

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html>
<head>
<style>
body {
padding: 0;
margin: 0;
}
</style>
</head>
<body>
<input id="textinput" style="width:300px; height:25px;" value="The rabbit-hole went straight on like a tunnel for some way and then dipped suddenly down" type="text">
</body>
</html>

View File

@ -145,7 +145,7 @@ CrossSlideHandler.prototype = {
}
},
cancel: function(){
cancel: function(aEvent){
this._fireProgressEvent("cancelled", aEvent);
this.drag = null;
},
@ -183,7 +183,7 @@ CrossSlideHandler.prototype = {
if (aEvent.touches.length!==1) {
// cancel if another touch point gets involved
return this.cancel();
return this.cancel(aEvent);
}
let startPt = this.drag.origin;
@ -202,7 +202,7 @@ CrossSlideHandler.prototype = {
if (-1 == newState) {
// out of bounds, cancel the event always
return this.cancel();
return this.cancel(aEvent);
}
let isWithinCone = withinCone(crossAxisDistance, scrollAxisDistance);
@ -213,7 +213,7 @@ CrossSlideHandler.prototype = {
if (currState >= CrossSlidingState.SELECTING && !isWithinCone) {
// we're committed to a cross-slide gesture,
// so going out of bounds at this point means aborting
return this.cancel();
return this.cancel(aEvent);
}
if (currState > newState) {
@ -232,7 +232,7 @@ CrossSlideHandler.prototype = {
aEvent.stopPropagation();
if (this.drag.state < CrossSlidingState.SELECTING) {
return this.cancel();
return this.cancel(aEvent);
}
this._fireProgressEvent("completed", aEvent);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 8.7 KiB

View File

@ -476,10 +476,6 @@ menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) {
list-style-image: url("chrome://browser/skin/places/bookmarksToolbar.png");
}
#BMB_bookmarkThisPage {
list-style-image: url("chrome://browser/skin/places/starPage.png");
}
#BMB_unsortedBookmarks {
list-style-image: url("chrome://browser/skin/places/unsortedBookmarks.png");
}
@ -654,19 +650,10 @@ toolbar[mode="full"] .toolbarbutton-1 > .toolbarbutton-menubutton-button {
-moz-image-region: rect(0px 48px 24px 24px);
}
#bookmarks-button,
#bookmarks-menu-button {
#bookmarks-button {
-moz-image-region: rect(0px 72px 24px 48px);
}
#bookmarks-menu-button.bookmark-item {
list-style-image: url("chrome://browser/skin/Toolbar-small.png");
}
#bookmarks-menu-button.toolbarbutton-1 {
-moz-box-orient: horizontal;
}
#print-button {
list-style-image: url("moz-icon://stock/gtk-print?size=toolbar");
}
@ -727,8 +714,8 @@ toolbar[mode="full"] .toolbarbutton-1 > .toolbarbutton-menubutton-button {
-moz-image-region: rect(0px 168px 24px 144px);
}
#feed-button[disabled="true"] > .toolbarbutton-icon {
opacity: .3;
#feed-button[disabled] > .toolbarbutton-icon {
opacity: .4;
}
#webrtc-status-button {
@ -820,9 +807,7 @@ toolbar[iconsize="small"] #history-button {
-moz-image-region: rect(0px 32px 16px 16px);
}
toolbar[iconsize="small"] #bookmarks-button,
toolbar[iconsize="small"] #bookmarks-menu-button,
#bookmarks-menu-button.bookmark-item {
toolbar[iconsize="small"] #bookmarks-button {
-moz-image-region: rect(0px 48px 16px 32px);
}
@ -1351,7 +1336,8 @@ toolbar[iconsize="small"] #webrtc-status-button {
.ac-result-type-bookmark,
.autocomplete-treebody::-moz-tree-image(bookmark, treecolAutoCompleteImage) {
list-style-image: url("chrome://browser/skin/places/pageStarred.png");
list-style-image: url("chrome://browser/skin/places/star-icons.png");
-moz-image-region: rect(0px 32px 16px 16px);
width: 16px;
height: 16px;
}
@ -1493,13 +1479,34 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
margin-top: 1em;
}
/* Star button */
#star-button {
list-style-image: url("chrome://browser/skin/places/starPage.png");
/* bookmarks menu-button */
#bookmarks-menu-button {
list-style-image: url("chrome://browser/skin/Toolbar.png");
-moz-image-region: rect(0px 216px 24px 192px);
}
#star-button[starred="true"] {
list-style-image: url("chrome://browser/skin/places/pageStarred.png");
#bookmarks-menu-button[starred] {
-moz-image-region: rect(24px 216px 48px 192px);
}
toolbar[iconsize="small"] #bookmarks-menu-button,
#bookmarks-menu-button.bookmark-item {
list-style-image: url("chrome://browser/skin/Toolbar-small.png");
-moz-image-region: rect(0px 144px 16px 128px);
}
toolbar[iconsize="small"] #bookmarks-menu-button[starred],
#bookmarks-menu-button.bookmark-item[starred] {
-moz-image-region: rect(16px 144px 32px 128px);
}
#bookmarks-menu-button[disabled] > .toolbarbutton-icon,
#bookmarks-menu-button[disabled] > .toolbarbutton-menu-dropmarker,
#bookmarks-menu-button[disabled] > .toolbarbutton-menubutton-dropmarker,
#bookmarks-menu-button[disabled] > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
#bookmarks-menu-button > .toolbarbutton-menubutton-button[disabled] > .toolbarbutton-icon {
opacity: .4;
}
/* Bookmarking panel */

View File

@ -130,7 +130,7 @@
-moz-appearance: none !important;
list-style-image: url("chrome://browser/skin/devtools/dropmarker.png");
-moz-box-align: center;
margin: 0 3px;
padding: 0 3px;
}
/* Text input */

View File

@ -93,11 +93,13 @@
}
.requests-menu-file {
width: 14em;
width: 20vw;
min-width: 4em;
}
.requests-menu-domain {
width: 14em;
width: 14vw;
min-width: 10em;
}
.requests-menu-type {
@ -303,13 +305,44 @@
#details-pane {
max-width: none;
margin: 0 !important;
/* To prevent all the margin hacks to hide the sidebar */
/* To prevent all the margin hacks to hide the sidebar. */
}
.requests-menu-status-and-method {
width: 14vw;
}
.requests-menu-file,
.requests-menu-domain {
width: 30vw;
min-width: 10em;
}
.requests-menu-type {
width: 8vw;
}
.requests-menu-size {
border-width: 0px !important;
width: 16vw;
border-width: 0 !important;
box-shadow: none !important;
/* !important are required here because Timeline is not visible and thus
the right border and box-shadow of Size column should be hidden */
/* The "Timeline" header is not visible anymore, and thus the
right border and box-shadow of "Size" column should be hidden. */
}
}
@media (min-width: 701px) {
#network-table[type-overflows] .requests-menu-domain {
border-width: 0 !important;
box-shadow: none !important;
/* The "Type" header is not visible anymore, and thus the
right border and box-shadow of "Domain" column should be hidden. */
}
#network-table[domain-overflows] .requests-menu-file {
border-width: 0 !important;
box-shadow: none !important;
/* The "Domain" header is not visible anymore, and thus the
right border and box-shadow of "File" column should be hidden. */
}
}

View File

@ -155,7 +155,7 @@ richlistitem[type="download"]:last-child {
/*** Highlighted list items ***/
#downloadsPanel:not([keyfocus]) > #downloadsListBox > richlistitem[type="download"][state="1"]:hover {
#downloadsPanel:not([keyfocus]) > #downloadsListBox > richlistitem[type="download"][state="1"][exists]:hover {
border-radius: 3px;
border-top: 1px solid hsla(0,0%,100%,.3);
border-bottom: 1px solid hsla(0,0%,0%,.2);

View File

@ -83,14 +83,13 @@ browser.jar:
skin/classic/browser/places/calendar.png (places/calendar.png)
* skin/classic/browser/places/editBookmarkOverlay.css (places/editBookmarkOverlay.css)
skin/classic/browser/places/livemark-item.png (places/livemark-item.png)
skin/classic/browser/places/pageStarred.png (places/pageStarred.png)
skin/classic/browser/places/star-icons.png (places/star-icons.png)
skin/classic/browser/places/starred48.png (places/starred48.png)
skin/classic/browser/places/unstarred48.png (places/unstarred48.png)
skin/classic/browser/places/places.css (places/places.css)
skin/classic/browser/places/organizer.css (places/organizer.css)
skin/classic/browser/places/organizer.xml (places/organizer.xml)
skin/classic/browser/places/query.png (places/query.png)
skin/classic/browser/places/starPage.png (places/starPage.png)
skin/classic/browser/places/tag.png (places/tag.png)
skin/classic/browser/places/toolbarDropMarker.png (places/toolbarDropMarker.png)
skin/classic/browser/places/unsortedBookmarks.png (places/unsortedBookmarks.png)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 767 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 723 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 8.5 KiB

View File

@ -438,7 +438,8 @@ toolbarbutton.bookmark-item > menupopup {
list-style-image: url("chrome://browser/skin/Toolbar@2x.png");
}
:-moz-any(@primaryToolbarButtons@):not(#tabview-button) > .toolbarbutton-icon {
:-moz-any(@primaryToolbarButtons@):not(#tabview-button) > .toolbarbutton-icon,
:-moz-any(@primaryToolbarButtons@):not(#tabview-button) > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
width: 20px;
}
}
@ -474,7 +475,7 @@ toolbar:not([mode="icons"]) #restore-button {
.toolbarbutton-1[disabled="true"] > .toolbarbutton-icon,
.toolbarbutton-1[disabled="true"] > .toolbarbutton-badge-container > .toolbarbutton-icon,
.toolbarbutton-1[type="menu-button"] > .toolbarbutton-menubutton-button[disabled="true"] > .toolbarbutton-icon,
.toolbarbutton-1 > .toolbarbutton-menubutton-button[disabled="true"] > .toolbarbutton-icon,
#restore-button[disabled="true"] > .toolbarbutton-icon {
opacity: .4;
}
@ -482,7 +483,7 @@ toolbar:not([mode="icons"]) #restore-button {
@media (-moz-mac-lion-theme) {
.toolbarbutton-1[disabled="true"] > .toolbarbutton-icon,
.toolbarbutton-1[disabled="true"] > .toolbarbutton-badge-container > .toolbarbutton-icon,
.toolbarbutton-1[type="menu-button"] > .toolbarbutton-menubutton-button[disabled="true"] > .toolbarbutton-icon,
.toolbarbutton-1 > .toolbarbutton-menubutton-button[disabled="true"] > .toolbarbutton-icon,
#restore-button[disabled="true"] > .toolbarbutton-icon,
.toolbarbutton-1[disabled="true"] > .toolbarbutton-menu-dropmarker,
.toolbarbutton-1[disabled="true"] > .toolbarbutton-menubutton-dropmarker,
@ -490,13 +491,14 @@ toolbar:not([mode="icons"]) #restore-button {
.toolbarbutton-1:not(:hover):-moz-window-inactive > .toolbarbutton-badge-container > .toolbarbutton-icon,
#restore-button:not(:hover):-moz-window-inactive > .toolbarbutton-icon,
.toolbarbutton-1:not(:hover):-moz-window-inactive > .toolbarbutton-menu-dropmarker,
.toolbarbutton-1:not(:hover):-moz-window-inactive > .toolbarbutton-menubutton-dropmarker {
.toolbarbutton-1:not(:hover):-moz-window-inactive > .toolbarbutton-menubutton-dropmarker,
.toolbarbutton-1:not(:hover):-moz-window-inactive > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
opacity: .5;
}
.toolbarbutton-1:-moz-window-inactive[disabled="true"] > .toolbarbutton-icon,
.toolbarbutton-1:-moz-window-inactive[disabled="true"] > .toolbarbutton-badge-container > .toolbarbutton-icon,
.toolbarbutton-1:-moz-window-inactive[type="menu-button"] > .toolbarbutton-menubutton-button[disabled="true"] > .toolbarbutton-icon,
.toolbarbutton-1:-moz-window-inactive > .toolbarbutton-menubutton-button[disabled="true"] > .toolbarbutton-icon,
#restore-button:-moz-window-inactive[disabled="true"] > .toolbarbutton-icon {
opacity: .25;
}
@ -524,8 +526,7 @@ toolbar:not([mode="icons"]) #restore-button {
}
.toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
width: 14px;
padding-top: 2px;
padding: 2px 4px 0;
-moz-border-start: none !important;
}
@ -916,8 +917,7 @@ toolbar[mode="icons"] #forward-button:-moz-lwtheme {
/* bookmark sidebar & menu buttons */
#bookmarks-button,
#bookmarks-menu-button {
#bookmarks-button {
-moz-image-region: rect(0, 180px, 20px, 160px);
}
@ -925,33 +925,14 @@ toolbar[mode="icons"] #forward-button:-moz-lwtheme {
-moz-image-region: rect(20px, 180px, 40px, 160px);
}
#bookmarks-menu-button.bookmark-item {
-moz-image-region: rect(2px, 178px, 18px, 162px);
list-style-image: url("chrome://browser/skin/Toolbar.png");
}
@media (min-resolution: 2dppx) {
#bookmarks-button,
#bookmarks-menu-button {
#bookmarks-button {
-moz-image-region: rect(0, 360px, 40px, 320px);
}
#bookmarks-button[checked="true"] {
-moz-image-region: rect(40px, 360px, 80px, 320px);
}
#bookmarks-menu-button.bookmark-item {
-moz-image-region: rect(4px, 356px, 36px, 324px);
list-style-image: url("chrome://browser/skin/Toolbar@2x.png");
}
#bookmarks-menu-button.bookmark-item > .toolbarbutton-icon {
width: 16px;
}
}
#bookmarks-menu-button.toolbarbutton-1 {
-moz-box-orient: horizontal;
}
/* print button */
@ -1736,35 +1717,49 @@ window[tabsontop="false"] richlistitem[type~="action"][actiontype="switchtab"][s
margin-top: 1em;
}
/* STAR BUTTON */
#star-button {
/* bookmarks menu-button */
#bookmarks-menu-button {
-moz-image-region: rect(0px 500px 20px 480px);
}
#bookmarks-menu-button[starred] {
-moz-image-region: rect(20px 500px 40px 480px);
}
#bookmarks-menu-button.bookmark-item {
list-style-image: url("chrome://browser/skin/places/star-icons.png");
-moz-image-region: rect(0, 16px, 16px, 0);
-moz-image-region: rect(0px 16px 16px 0px);
}
#star-button:hover:active,
#star-button[starred="true"] {
-moz-image-region: rect(0, 32px, 16px, 16px);
#bookmarks-menu-button.bookmark-item[starred] {
-moz-image-region: rect(0px 32px 16px 16px);
}
#star-button:hover:active[starred="true"] {
-moz-image-region: rect(0, 48px, 16px, 32px);
#bookmarks-menu-button.bookmark-item > .toolbarbutton-menubutton-button {
padding: 0;
}
@media (min-resolution: 2dppx) {
#star-button {
#bookmarks-menu-button {
-moz-image-region: rect(0px, 1000px, 40px, 960px);
}
#bookmarks-menu-button[starred] {
-moz-image-region: rect(40px, 1000px, 80px, 960px);
}
#bookmarks-menu-button.bookmark-item {
list-style-image: url("chrome://browser/skin/places/star-icons@2x.png");
-moz-image-region: rect(0, 32px, 32px, 0);
width: 22px;
-moz-image-region: rect(0px 32px 32px 0px);
}
#star-button:hover:active,
#star-button[starred="true"] {
-moz-image-region: rect(0, 64px, 32px, 32px);
#bookmarks-menu-button.bookmark-item[starred] {
-moz-image-region: rect(0px 64px 32px 32px);
}
#star-button:hover:active[starred="true"] {
-moz-image-region: rect(0, 96px, 32px, 64px);
#bookmarks-menu-button.bookmark-item > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
width: 16px;
}
}
@ -2517,12 +2512,16 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
}
:-moz-any(#TabsToolbar, #addon-bar) .toolbarbutton-1:not([type="menu-button"]),
:-moz-any(#TabsToolbar, #addon-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-button,
:-moz-any(#TabsToolbar, #addon-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
:-moz-any(#TabsToolbar, #addon-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-button {
margin: 0;
padding: 0 1px;
}
:-moz-any(#TabsToolbar, #addon-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
padding-left: 4px;
padding-right: 4px;
}
.tabbrowser-arrowscrollbox > .scrollbutton-up:not([disabled]):hover,
.tabbrowser-arrowscrollbox > .scrollbutton-down:not([disabled]):hover,
:-moz-any(#TabsToolbar, #addon-bar) .toolbarbutton-1:not([type="menu-button"]):not([disabled]):not([open]):hover,

View File

@ -134,7 +134,6 @@
.devtools-toolbarbutton[type=menu-button] > .toolbarbutton-menubutton-dropmarker {
-moz-appearance: none !important;
list-style-image: url("chrome://browser/skin/devtools/dropmarker.png");
margin: 0 3px;
border: 0;
}

View File

@ -93,11 +93,13 @@
}
.requests-menu-file {
width: 16em;
width: 20vw;
min-width: 4em;
}
.requests-menu-domain {
width: 16em;
width: 14vw;
min-width: 10em;
}
.requests-menu-type {
@ -303,13 +305,44 @@
#details-pane {
max-width: none;
margin: 0 !important;
/* To prevent all the margin hacks to hide the sidebar */
/* To prevent all the margin hacks to hide the sidebar. */
}
.requests-menu-status-and-method {
width: 14vw;
}
.requests-menu-file,
.requests-menu-domain {
width: 30vw;
min-width: 10em;
}
.requests-menu-type {
width: 8vw;
}
.requests-menu-size {
border-width: 0px !important;
width: 16vw;
border-width: 0 !important;
box-shadow: none !important;
/* !important are required here because Timeline is not visible and thus
the right border and box-shadow of Size column should be hidden */
/* The "Timeline" header is not visible anymore, and thus the
right border and box-shadow of "Size" column should be hidden. */
}
}
@media (min-width: 701px) {
#network-table[type-overflows] .requests-menu-domain {
border-width: 0 !important;
box-shadow: none !important;
/* The "Type" header is not visible anymore, and thus the
right border and box-shadow of "Domain" column should be hidden. */
}
#network-table[domain-overflows] .requests-menu-file {
border-width: 0 !important;
box-shadow: none !important;
/* The "Domain" header is not visible anymore, and thus the
right border and box-shadow of "File" column should be hidden. */
}
}

View File

@ -177,7 +177,7 @@ richlistitem[type="download"]:last-child {
/*** Highlighted list items ***/
#downloadsPanel[keyfocus] > #downloadsListBox:focus > richlistitem[type="download"][selected],
#downloadsPanel:not([keyfocus]) > #downloadsListBox > richlistitem[type="download"][state="1"]:hover {
#downloadsPanel:not([keyfocus]) > #downloadsListBox > richlistitem[type="download"][state="1"][exists]:hover {
border-radius: 3px;
border-top: 1px solid hsla(0,0%,100%,.2);
border-bottom: 1px solid hsla(0,0%,0%,.4);
@ -185,7 +185,7 @@ richlistitem[type="download"]:last-child {
color: HighlightText;
}
#downloadsPanel:not([keyfocus]) > #downloadsListBox > richlistitem[type="download"][state="1"]:hover {
#downloadsPanel:not([keyfocus]) > #downloadsListBox > richlistitem[type="download"][state="1"][exists]:hover {
cursor: pointer;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 9.5 KiB

View File

@ -159,8 +159,8 @@
border-right-style: none !important;
}
#navigator-toolbox[tabsontop=false] > :-moz-any(#toolbar-menubar, #nav-bar) :-moz-any(@primaryToolbarButtons@):not(:-moz-any(#alltabs-button,#tabview-button,#sync-button[status])) > .toolbarbutton-icon:not(:-moz-lwtheme),
#nav-bar + #customToolbars + #PersonalToolbar[collapsed=true] + #TabsToolbar[tabsontop=false]:last-child :-moz-any(@primaryToolbarButtons@):not(:-moz-any(#alltabs-button,#tabview-button,#new-tab-button,#sync-button[status])) > .toolbarbutton-icon:not(:-moz-lwtheme) {
#navigator-toolbox[tabsontop=false] > :-moz-any(#toolbar-menubar, #nav-bar) :-moz-any(@primaryToolbarButtons@):not(:-moz-any(#alltabs-button,#tabview-button,#sync-button[status],#bookmarks-menu-button)) > .toolbarbutton-icon:not(:-moz-lwtheme),
#nav-bar + #customToolbars + #PersonalToolbar[collapsed=true] + #TabsToolbar[tabsontop=false]:last-child :-moz-any(@primaryToolbarButtons@):not(:-moz-any(#alltabs-button,#tabview-button,#new-tab-button,#sync-button[status],#bookmarks-menu-button)) > .toolbarbutton-icon:not(:-moz-lwtheme) {
list-style-image: url("chrome://browser/skin/Toolbar-inverted.png");
}

View File

@ -647,7 +647,7 @@ toolbarbutton.bookmark-item[open="true"] {
-moz-padding-end: 2px;
}
.bookmark-item:not(#bookmarks-menu-button) > .toolbarbutton-icon {
.bookmark-item > .toolbarbutton-icon {
width: 16px;
height: 16px;
}
@ -764,7 +764,8 @@ menuitem.bookmark-item {
.toolbarbutton-1[disabled=true] > .toolbarbutton-icon,
.toolbarbutton-1[disabled=true] > .toolbarbutton-menu-dropmarker,
.toolbarbutton-1[disabled=true] > .toolbarbutton-menubutton-dropmarker,
.toolbarbutton-1[disabled=true] > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
.toolbarbutton-1[disabled=true] > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
.toolbarbutton-1 > .toolbarbutton-menubutton-button[disabled] > .toolbarbutton-icon {
opacity: .4;
}
@ -866,7 +867,7 @@ toolbar[mode=full] .toolbarbutton-1 > .toolbarbutton-menubutton-button {
}
@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
padding: 8px 3px 7px;
padding: 8px 5px 7px;
}
@navbarLargeIcons@ .toolbarbutton-1:not(:hover):not(:active):not([open]) > .toolbarbutton-menubutton-dropmarker::before,
@ -1115,16 +1116,9 @@ toolbar[mode=full] .toolbarbutton-1 > .toolbarbutton-menubutton-button {
-moz-image-region: rect(0, 126px, 18px, 108px);
}
#bookmarks-button,
#bookmarks-menu-button {
#bookmarks-button {
-moz-image-region: rect(0, 144px, 18px, 126px);
}
#bookmarks-menu-button.bookmark-item {
list-style-image: url("chrome://browser/skin/Toolbar.png");
}
#bookmarks-menu-button.bookmark-item:-moz-lwtheme-brighttext {
list-style-image: url("chrome://browser/skin/Toolbar-inverted.png");
}
#print-button {
-moz-image-region: rect(0, 162px, 18px, 144px);
@ -1580,8 +1574,8 @@ html|*.urlbar-input:-moz-lwtheme::-moz-placeholder,
.ac-result-type-bookmark,
.autocomplete-treebody::-moz-tree-image(bookmark, treecolAutoCompleteImage) {
list-style-image: url("chrome://browser/skin/places/editBookmark.png");
-moz-image-region: rect(0px 16px 16px 0px);
list-style-image: url("chrome://browser/skin/places/bookmark.png");
-moz-image-region: rect(0px 48px 16px 32px);
width: 16px;
height: 16px;
}
@ -1792,28 +1786,31 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
margin-top: 1em;
}
/* star button */
/* bookmarks menu-button */
#star-button {
#bookmarks-menu-button {
-moz-image-region: rect(0px 378px 18px 360px);
}
#bookmarks-menu-button[starred] {
-moz-image-region: rect(18px 378px 36px 360px);
}
#bookmarks-menu-button.bookmark-item {
list-style-image: url("chrome://browser/skin/places/bookmark.png");
-moz-image-region: rect(0px 16px 16px 0px);
}
#star-button:hover {
background-image: radial-gradient(circle closest-side, hsla(45,100%,73%,.3), hsla(45,100%,73%,0));
-moz-image-region: rect(0px 32px 16px 16px);
}
#star-button:hover:active {
background-image: radial-gradient(circle closest-side, hsla(45,100%,73%,.1), hsla(45,100%,73%,0));
#bookmarks-menu-button.bookmark-item[starred] {
-moz-image-region: rect(0px 48px 16px 32px);
}
#star-button[starred="true"] {
list-style-image: url("chrome://browser/skin/places/editBookmark.png");
#bookmarks-menu-button.bookmark-item > .toolbarbutton-menubutton-button> .toolbarbutton-icon {
-moz-margin-start: 5px;
}
/* bookmarking panel */
#editBookmarkPanelStarIcon {
list-style-image: url("chrome://browser/skin/places/starred48.png");
width: 48px;

View File

@ -93,11 +93,13 @@
}
.requests-menu-file {
width: 16em;
width: 20vw;
min-width: 4em;
}
.requests-menu-domain {
width: 16em;
width: 14vw;
min-width: 10em;
}
.requests-menu-type {
@ -303,13 +305,44 @@
#details-pane {
max-width: none;
margin: 0 !important;
/* To prevent all the margin hacks to hide the sidebar */
/* To prevent all the margin hacks to hide the sidebar. */
}
.requests-menu-status-and-method {
width: 14vw;
}
.requests-menu-file,
.requests-menu-domain {
width: 30vw;
min-width: 10em;
}
.requests-menu-type {
width: 8vw;
}
.requests-menu-size {
border-width: 0px !important;
width: 16vw;
border-width: 0 !important;
box-shadow: none !important;
/* !important are required here because Timeline is not visible and thus
the right border and box-shadow of Size column should be hidden */
/* The "Timeline" header is not visible anymore, and thus the
right border and box-shadow of "Size" column should be hidden. */
}
}
@media (min-width: 701px) {
#network-table[type-overflows] .requests-menu-domain {
border-width: 0 !important;
box-shadow: none !important;
/* The "Type" header is not visible anymore, and thus the
right border and box-shadow of "Domain" column should be hidden. */
}
#network-table[domain-overflows] .requests-menu-file {
border-width: 0 !important;
box-shadow: none !important;
/* The "Domain" header is not visible anymore, and thus the
right border and box-shadow of "File" column should be hidden. */
}
}

View File

@ -12,7 +12,7 @@
border-bottom: 1px solid hsl(213,40%,90%);
}
#downloadsPanel:not([keyfocus]) > #downloadsListBox > richlistitem[type="download"][state="1"]:hover {
#downloadsPanel:not([keyfocus]) > #downloadsListBox > richlistitem[type="download"][state="1"][exists]:hover {
border: 1px solid hsl(213,45%,65%);
box-shadow: 0 0 0 1px hsla(0,0%,100%,.5) inset,
0 1px 0 hsla(0,0%,100%,.3) inset;

View File

@ -166,7 +166,7 @@ richlistitem[type="download"]:first-child {
/*** Highlighted list items ***/
#downloadsPanel:not([keyfocus]) > #downloadsListBox > richlistitem[type="download"][state="1"]:hover {
#downloadsPanel:not([keyfocus]) > #downloadsListBox > richlistitem[type="download"][state="1"][exists]:hover {
border-radius: 3px;
border-top: 1px solid hsla(0,0%,100%,.2);
border-bottom: 1px solid hsla(0,0%,0%,.2);

View File

@ -98,7 +98,6 @@ browser.jar:
skin/classic/browser/places/places.css (places/places.css)
* skin/classic/browser/places/organizer.css (places/organizer.css)
skin/classic/browser/places/bookmark.png (places/bookmark.png)
skin/classic/browser/places/editBookmark.png (places/editBookmark.png)
skin/classic/browser/places/query.png (places/query.png)
skin/classic/browser/places/bookmarksMenu.png (places/bookmarksMenu.png)
skin/classic/browser/places/bookmarksToolbar.png (places/bookmarksToolbar.png)
@ -357,7 +356,6 @@ browser.jar:
* skin/classic/aero/browser/places/places.css (places/places-aero.css)
* skin/classic/aero/browser/places/organizer.css (places/organizer-aero.css)
skin/classic/aero/browser/places/bookmark.png (places/bookmark.png)
skin/classic/aero/browser/places/editBookmark.png (places/editBookmark.png)
skin/classic/aero/browser/places/query.png (places/query-aero.png)
skin/classic/aero/browser/places/bookmarksMenu.png (places/bookmarksMenu-aero.png)
skin/classic/aero/browser/places/bookmarksToolbar.png (places/bookmarksToolbar-aero.png)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -1073,6 +1073,8 @@ conic/conicstatisticsevent.h
#endif
#if MOZ_NATIVE_LIBEVENT==1
event.h
#else
sys/event.h
#endif
#ifdef MOZ_ENABLE_LIBPROXY
proxy.h

View File

@ -425,7 +425,7 @@ public:
*
* @return The document or null if no JS Context.
*/
static nsIDOMDocument *GetDocumentFromCaller();
static nsIDocument* GetDocumentFromCaller();
/**
* Get the document through the JS context that's currently on the stack.
@ -434,7 +434,7 @@ public:
*
* @return The document or null if no JS context
*/
static nsIDOMDocument *GetDocumentFromContext();
static nsIDocument* GetDocumentFromContext();
// Check if a node is in the document prolog, i.e. before the document
// element.

View File

@ -1709,7 +1709,7 @@ nsContentUtils::GetWindowFromCaller()
return nullptr;
}
nsIDOMDocument *
nsIDocument*
nsContentUtils::GetDocumentFromCaller()
{
JSContext *cx = nullptr;
@ -1725,10 +1725,10 @@ nsContentUtils::GetDocumentFromCaller()
return nullptr;
}
return win->GetExtantDocument();
return win->GetExtantDoc();
}
nsIDOMDocument *
nsIDocument*
nsContentUtils::GetDocumentFromContext()
{
JSContext *cx = nullptr;
@ -1740,7 +1740,7 @@ nsContentUtils::GetDocumentFromContext()
if (sgo) {
nsCOMPtr<nsPIDOMWindow> pwin = do_QueryInterface(sgo);
if (pwin) {
return pwin->GetExtantDocument();
return pwin->GetExtantDoc();
}
}
}

View File

@ -260,8 +260,7 @@ nsDOMFileBase::MozSlice(int64_t aStart, int64_t aEnd,
if (sgo) {
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(sgo);
if (window) {
nsCOMPtr<nsIDocument> document =
do_QueryInterface(window->GetExtantDocument());
nsCOMPtr<nsIDocument> document = window->GetExtantDoc();
if (document) {
document->WarnOnceAbout(nsIDocument::eMozSlice);
}
@ -276,7 +275,7 @@ nsDOMFileBase::GetInternalStream(nsIInputStream **aStream)
{
// Must be overridden
NS_NOTREACHED("Must override GetInternalStream");
return NS_ERROR_NOT_IMPLEMENTED;
}

View File

@ -408,7 +408,7 @@ protected:
bool Suppressed()
{
if (mOwner) {
nsCOMPtr<nsIDocument> d = do_QueryInterface(mOwner->GetExtantDocument());
nsCOMPtr<nsIDocument> d = mOwner->GetExtantDoc();
return d && d->IsInSyncOperation();
}
return false;

View File

@ -2373,7 +2373,7 @@ CSPErrorQueue::Flush(nsIDocument* aDocument)
for (uint32_t i = 0; i < mErrors.Length(); i++) {
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
"CSP", aDocument,
nsContentUtils::eDOM_PROPERTIES,
nsContentUtils::eSECURITY_PROPERTIES,
mErrors[i]);
}
mErrors.Clear();
@ -2530,22 +2530,11 @@ nsDocument::InitCSP(nsIChannel* aChannel)
// If the old header is present, warn that it will be deprecated.
if (!cspOldHeaderValue.IsEmpty() || !cspOldROHeaderValue.IsEmpty()) {
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
"CSP", this,
nsContentUtils::eDOM_PROPERTIES,
"OldCSPHeaderDeprecated");
// Additionally log deprecated warning to Web Console.
mCSPWebConsoleErrorQueue.Add("OldCSPHeaderDeprecated");
// Also, if the new headers AND the old headers were present, warn
// that the old headers will be ignored.
if (cspSpecCompliant) {
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
"CSP", this,
nsContentUtils::eDOM_PROPERTIES,
"BothCSPHeadersPresent");
// Additionally log to Web Console.
mCSPWebConsoleErrorQueue.Add("BothCSPHeadersPresent");
}
}
@ -2582,11 +2571,6 @@ nsDocument::InitCSP(nsIChannel* aChannel)
// CSP policies are present since CSP only allows one policy and it can't
// be partially report-only.
if (applyAppDefaultCSP || applyCSPFromHeader) {
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
"CSP", this,
nsContentUtils::eDOM_PROPERTIES,
"ReportOnlyCSPIgnored");
// Additionally log to Web Console.
mCSPWebConsoleErrorQueue.Add("ReportOnlyCSPIgnored");
#ifdef PR_LOGGING
PR_LOG(gCspPRLog, PR_LOG_DEBUG,
@ -6239,8 +6223,6 @@ nsDocument::GetAnimationController()
return mAnimationController;
}
static const char* dirAttributes[] = { "ltr", "rtl", "auto", 0 };
/**
* Retrieve the "direction" property of the document.
*
@ -6259,14 +6241,7 @@ nsIDocument::GetDir(nsAString& aDirection) const
aDirection.Truncate();
Element* rootElement = GetHtmlElement();
if (rootElement) {
nsAutoString dir;
rootElement->GetAttr(kNameSpaceID_None, nsGkAtoms::dir, dir);
for (uint32_t i = 0; dirAttributes[i]; ++i) {
if (dir.LowerCaseEqualsASCII(dirAttributes[i])) {
aDirection.AssignASCII(dirAttributes[i]);
return;
}
}
static_cast<nsGenericHTMLElement*>(rootElement)->GetDir(aDirection);
}
}
@ -11261,7 +11236,7 @@ nsAutoSyncOperation::nsAutoSyncOperation(nsIDocument* aDoc)
win->GetTop(getter_AddRefs(topWindow));
nsCOMPtr<nsPIDOMWindow> top = do_QueryInterface(topWindow);
if (top) {
nsCOMPtr<nsIDocument> doc = do_QueryInterface(top->GetExtantDocument());
nsCOMPtr<nsIDocument> doc = top->GetExtantDoc();
MarkDocumentTreeToBeInSyncOperation(doc, &mDocuments);
}
}

View File

@ -1095,10 +1095,8 @@ nsFrameLoader::SwapWithOtherLoader(nsFrameLoader* aOther,
SameCOMIdentity(otherChromeEventHandler, otherContent),
"How did that happen, exactly?");
nsCOMPtr<nsIDocument> ourChildDocument =
do_QueryInterface(ourWindow->GetExtantDocument());
nsCOMPtr<nsIDocument> otherChildDocument =
do_QueryInterface(otherWindow->GetExtantDocument());
nsCOMPtr<nsIDocument> ourChildDocument = ourWindow->GetExtantDoc();
nsCOMPtr<nsIDocument> otherChildDocument = otherWindow ->GetExtantDoc();
if (!ourChildDocument || !otherChildDocument) {
// This shouldn't be happening
return NS_ERROR_NOT_IMPLEMENTED;

View File

@ -745,6 +745,8 @@ nsObjectLoadingContent::InstantiatePluginInstance(bool aIsLoading)
// Flush layout so that the frame is created if possible and the plugin is
// initialized with the latest information.
doc->FlushPendingNotifications(Flush_Layout);
// Flushing layout may have re-entered and loaded something underneath us
NS_ENSURE_TRUE(mInstantiating, NS_OK);
if (!thisContent->GetPrimaryFrame()) {
LOG(("OBJLC [%p]: Not instantiating plugin with no frame", this));
@ -767,16 +769,42 @@ nsObjectLoadingContent::InstantiatePluginInstance(bool aIsLoading)
appShell->SuspendNative();
}
nsRefPtr<nsPluginInstanceOwner> newOwner;
rv = pluginHost->InstantiatePluginInstance(mContentType.get(),
mURI.get(), this,
getter_AddRefs(mInstanceOwner));
getter_AddRefs(newOwner));
// XXX(johns): We don't suspend native inside stopping plugins...
if (appShell) {
appShell->ResumeNative();
}
if (NS_FAILED(rv)) {
return rv;
if (!mInstantiating || NS_FAILED(rv)) {
LOG(("OBJLC [%p]: Plugin instantiation failed or re-entered, "
"killing old instance", this));
// XXX(johns): This needs to be de-duplicated with DoStopPlugin, but we
// don't want to touch the protochain or delayed stop.
// (Bug 767635)
if (newOwner) {
nsRefPtr<nsNPAPIPluginInstance> inst;
newOwner->GetInstance(getter_AddRefs(inst));
newOwner->SetFrame(nullptr);
if (inst) {
pluginHost->StopPluginInstance(inst);
}
newOwner->Destroy();
}
return NS_OK;
}
mInstanceOwner = newOwner;
// Ensure the frame did not change during instantiation re-entry (common).
// HasNewFrame would not have mInstanceOwner yet, so the new frame would be
// dangling. (Bug 854082)
nsIFrame* frame = thisContent->GetPrimaryFrame();
if (frame && mInstanceOwner) {
mInstanceOwner->SetFrame(static_cast<nsObjectFrame*>(frame));
}
// Set up scripting interfaces.
@ -1011,16 +1039,10 @@ nsObjectLoadingContent::HasNewFrame(nsIObjectFrame* aFrame)
}
// Otherwise, we're just changing frames
mInstanceOwner->SetFrame(nullptr);
// Set up relationship between instance owner and frame.
nsObjectFrame *objFrame = static_cast<nsObjectFrame*>(aFrame);
mInstanceOwner->SetFrame(objFrame);
// Set up new frame to draw.
objFrame->FixupWindow(objFrame->GetContentRectRelativeToSelf().Size());
objFrame->InvalidateFrame();
return NS_OK;
}
@ -2156,6 +2178,10 @@ nsObjectLoadingContent::UnloadObject(bool aResetState)
mOriginalContentType.Truncate();
}
// InstantiatePluginInstance checks this after re-entrant calls and aborts if
// it was cleared from under it
mInstantiating = false;
mScriptRequested = false;
// This call should be last as it may re-enter
@ -2294,7 +2320,6 @@ nsObjectLoadingContent::PluginDestroyed()
// plugins in plugin host. Invalidate instance owner / prototype but otherwise
// don't take any action.
TeardownProtoChain();
mInstanceOwner->SetFrame(nullptr);
mInstanceOwner->Destroy();
mInstanceOwner = nullptr;
return NS_OK;
@ -2578,6 +2603,8 @@ nsObjectLoadingContent::StopPluginInstance()
CloseChannel();
}
// We detach the instance owner's frame before destruction, but don't destroy
// the instance owner until the plugin is stopped.
mInstanceOwner->SetFrame(nullptr);
bool delayedStop = false;

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