merge fx-team to mozilla-central

This commit is contained in:
Carsten "Tomcat" Book 2014-02-06 12:51:21 +01:00
commit 117533e244
53 changed files with 604 additions and 280 deletions

View File

@ -53,7 +53,14 @@ exports.env = require('./system/environment').env;
* 'success' code 0. To exit with failure use `1`.
* TODO: Improve platform to actually quit with an exit code.
*/
let forcedExit = false;
exports.exit = function exit(code) {
if (forcedExit) {
// a forced exit was already tried
// NOTE: exit(0) is called twice sometimes (ex when using cfx testaddons)
return;
}
// This is used by 'cfx' to find out exit code.
if ('resultFile' in options && options.resultFile) {
let mode = PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE;
@ -64,6 +71,9 @@ exports.exit = function exit(code) {
stream.close();
}
if (code == 0) {
forcedExit = true;
}
appStartup.quit(code ? E_ATTEMPT : E_FORCE);
};

View File

@ -0,0 +1,18 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// Test that we can link with libxul using js-ctypes
const {Cu} = require("chrome");
const {ctypes} = Cu.import("resource://gre/modules/ctypes.jsm", {});
const {OS} = Cu.import("resource://gre/modules/osfile.jsm", {});
exports.test = function(assert) {
let path = OS.Constants.Path.libxul;
assert.pass("libxul is at " + path);
let lib = ctypes.open(path);
assert.ok(lib != null, "linked to libxul successfully");
};
require('test').run(exports);

View File

@ -1446,12 +1446,12 @@ let BookmarkingUI = {
_starButtonLabel: null,
get _starButtonOverflowedLabel() {
delete this._starButtonOverflowedLabel;
this._starButtonOverflowedLabel =
return this._starButtonOverflowedLabel =
gNavigatorBundle.getString("starButtonOverflowed.label");
},
get _starButtonOverflowedStarredLabel() {
delete this._starButtonOverflowedStarredLabel;
this._starButtonOverflowedStarredLabel =
return this._starButtonOverflowedStarredLabel =
gNavigatorBundle.getString("starButtonOverflowedStarred.label");
},
onWidgetOverflow: function(aNode, aContainer) {

View File

@ -200,6 +200,18 @@
accesskey="&customizeMenu.addMoreItems.accesskey;"
label="&customizeMenu.addMoreItems.label;"/>
</menupopup>
<svg:svg height="0">
<svg:defs>
<svg:linearGradient gradientUnits="objectBoundingBox" id="menuPanelButtonTextFadeOut" x2="0" y2="1">
<svg:stop stop-color="white" offset=".66"/>
<svg:stop stop-color="rgb(128,128,128)" offset=".72"/>
<svg:stop stop-color="black" offset=".9"/>
</svg:linearGradient>
<svg:mask id="menuPanelButtonTextFadeOutMask" maskUnits="objectBoundingBox" maskContentUnits="objectBoundingBox" x="0" y="0" width="100%" height="100%">
<svg:rect width="1" height="1" fill="url(#menuPanelButtonTextFadeOut)"/>
</svg:mask>
</svg:defs>
</svg:svg>
</panel>
<panel id="widget-overflow"

View File

@ -224,47 +224,52 @@ Bookmarks.prototype = {
let entries = aSourceFolder.directoryEntries;
while (entries.hasMoreElements()) {
let entry = entries.getNext().QueryInterface(Ci.nsIFile);
// Make sure that entry.path == entry.target to not follow .lnk folder
// shortcuts which could lead to infinite cycles.
if (entry.isDirectory() && entry.path == entry.target) {
let destFolderId;
if (entry.leafName == this._toolbarFolderName &&
entry.parent.equals(this._favoritesFolder)) {
// Import to the bookmarks toolbar.
destFolderId = PlacesUtils.toolbarFolderId;
if (!MigrationUtils.isStartupMigration) {
try {
// Make sure that entry.path == entry.target to not follow .lnk folder
// shortcuts which could lead to infinite cycles.
// Don't use isSymlink(), since it would throw for invalid
// lnk files pointing to URLs or to unresolvable paths.
if (entry.path == entry.target && entry.isDirectory()) {
let destFolderId;
if (entry.leafName == this._toolbarFolderName &&
entry.parent.equals(this._favoritesFolder)) {
// Import to the bookmarks toolbar.
destFolderId = PlacesUtils.toolbarFolderId;
if (!MigrationUtils.isStartupMigration) {
destFolderId =
MigrationUtils.createImportedBookmarksFolder("IE", destFolderId);
}
}
else {
// Import to a new folder.
destFolderId =
MigrationUtils.createImportedBookmarksFolder("IE", destFolderId);
PlacesUtils.bookmarks.createFolder(aDestFolderId, entry.leafName,
PlacesUtils.bookmarks.DEFAULT_INDEX);
}
if (entry.isReadable()) {
// Recursively import the folder.
this._migrateFolder(entry, destFolderId);
}
}
else {
// Import to a new folder.
destFolderId =
PlacesUtils.bookmarks.createFolder(aDestFolderId, entry.leafName,
PlacesUtils.bookmarks.DEFAULT_INDEX);
}
// Strip the .url extension, to both check this is a valid link file,
// and get the associated title.
let matches = entry.leafName.match(/(.+)\.url$/i);
if (matches) {
let fileHandler = Cc["@mozilla.org/network/protocol;1?name=file"].
getService(Ci.nsIFileProtocolHandler);
let uri = fileHandler.readURLFile(entry);
let title = matches[1];
if (entry.isReadable()) {
// Recursively import the folder.
this._migrateFolder(entry, destFolderId);
}
}
else {
// Strip the .url extension, to both check this is a valid link file,
// and get the associated title.
let matches = entry.leafName.match(/(.+)\.url$/i);
if (matches) {
let fileHandler = Cc["@mozilla.org/network/protocol;1?name=file"].
getService(Ci.nsIFileProtocolHandler);
let uri = fileHandler.readURLFile(entry);
let title = matches[1];
PlacesUtils.bookmarks.insertBookmark(aDestFolderId,
uri,
PlacesUtils.bookmarks.DEFAULT_INDEX,
title);
PlacesUtils.bookmarks.insertBookmark(aDestFolderId,
uri,
PlacesUtils.bookmarks.DEFAULT_INDEX,
title);
}
}
} catch (ex) {
Components.utils.reportError("Unable to import IE favorite (" + entry.leafName + "): " + ex);
}
}
}

View File

@ -214,7 +214,7 @@
value="&manage.label;"/>
<spacer flex="1"/>
<vbox align="end">
<button onclick="gSyncPane.unlinkFirefoxAccount(true);"
<button oncommand="gSyncPane.unlinkFirefoxAccount(true);"
label="&disconnect.label;" />
</vbox>
</hbox>
@ -228,7 +228,7 @@
</description>
<spacer flex="1"/>
<vbox align="end">
<button onclick="gSyncPane.verifyFirefoxAccount();"
<button oncommand="gSyncPane.verifyFirefoxAccount();"
label="&verify.label;"/>
<label class="text-link"
onclick="/* no warning as account can't have previously synced */ gSyncPane.unlinkFirefoxAccount(false);"
@ -245,7 +245,7 @@
</description>
<spacer flex="1"/>
<vbox align="end">
<button onclick="gSyncPane.reSignIn();"
<button oncommand="gSyncPane.reSignIn();"
label="&signIn.label;"/>
<label class="text-link"
onclick="gSyncPane.unlinkFirefoxAccount(true);"

View File

@ -20,6 +20,7 @@ Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource:///modules/devtools/gDevTools.jsm");
Cu.import("resource:///modules/devtools/scratchpad-manager.jsm");
Cu.import("resource:///modules/devtools/DOMHelpers.jsm");
Cu.import("resource://gre/modules/Task.jsm");
loader.lazyGetter(this, "Hosts", () => require("devtools/framework/toolbox-hosts").Hosts);
@ -1057,40 +1058,33 @@ Toolbox.prototype = {
* Returns a promise that resolves when the fronts are destroyed
*/
destroyInspector: function() {
let deferred = promise.defer();
if (this._inspector) {
// Selection is not always available.
if (this._selection) {
this._selection.destroy();
this._selection = null;
}
let walker = this._walker ? this._walker.release() : promise.resolve(null);
walker.then(
() => {
this._inspector.destroy();
if (this._highlighter) {
this._highlighter.destroy();
}
},
(e) => {
console.error("Walker.release() failed: " + e);
this._inspector.destroy();
return this._highlighter ? this._highlighter.destroy() : promise.resolve(null);
}
).then(() => {
this._inspector = null;
this._highlighter = null;
this._walker = null;
deferred.resolve();
});
} else {
deferred.resolve();
if (!this._inspector) {
return promise.resolve();
}
return deferred.promise;
let outstanding = () => {
return Task.spawn(function*() {
yield this.highlighterUtils.stopPicker();
yield this._inspector.destroy();
if (this._highlighter) {
yield this._highlighter.destroy();
}
if (this._selection) {
this._selection.destroy();
}
this._inspector = null;
this._highlighter = null;
this._selection = null;
this._walker = null;
}.bind(this));
};
// Releasing the walker (if it has been created)
// This can fail, but in any case, we want to continue destroying the
// inspector/highlighter/selection
let walker = this._walker ? this._walker.release() : promise.resolve();
return walker.then(outstanding, outstanding);
},
/**
@ -1142,15 +1136,16 @@ Toolbox.prototype = {
// Destroying the walker and inspector fronts
outstanding.push(this.destroyInspector());
// Removing buttons
this._pickerButton.removeEventListener("command", this._togglePicker, false);
this._pickerButton = null;
let container = this.doc.getElementById("toolbox-buttons");
while (container.firstChild) {
container.removeChild(container.firstChild);
}
outstanding.push(() => {
this._pickerButton.removeEventListener("command", this._togglePicker, false);
this._pickerButton = null;
let container = this.doc.getElementById("toolbox-buttons");
while (container.firstChild) {
container.removeChild(container.firstChild);
}
});
// Remove the host UI
outstanding.push(this.destroyHost());
this._telemetry.destroy();
@ -1223,9 +1218,14 @@ ToolboxHighlighterUtils.prototype = {
* events on the target to highlight the hovered/picked element.
* Depending on the server-side capabilities, this may fire events when nodes
* are hovered.
* @return A promise that resolves when the picker has started
* @return A promise that resolves when the picker has started or immediately
* if it is already started
*/
startPicker: function() {
if (this._isPicking) {
return promise.resolve();
}
let deferred = promise.defer();
let done = () => {
@ -1260,9 +1260,14 @@ ToolboxHighlighterUtils.prototype = {
/**
* Stop the element picker
* @return A promise that resolves when the picker has stopped
* @return A promise that resolves when the picker has stopped or immediately
* if it is already stopped
*/
stopPicker: function() {
if (!this._isPicking) {
return promise.resolve();
}
let deferred = promise.defer();
let done = () => {

View File

@ -49,3 +49,4 @@ support-files =
[browser_inspector_bug_958456_highlight_comments.js]
[browser_inspector_bug_958169_switch_to_inspector_on_pick.js]
[browser_inspector_bug_961771_picker_stops_on_tool_select.js]
[browser_inspector_bug_962478_picker_stops_on_destroy.js]

View File

@ -2,47 +2,39 @@
* 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/. */
// Test that the highlighter's picker should be stopped when a different tool is selected
// Test that the highlighter's picker should be stopped when a different tool is
// selected
function test() {
let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
let {require} = devtools;
let promise = require("sdk/core/promise");
let {Task} = Cu.import("resource://gre/modules/Task.jsm", {});
waitForExplicitFinish();
let inspector, doc, toolbox;
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function onload() {
gBrowser.selectedBrowser.removeEventListener("load", onload, true);
doc = content.document;
waitForFocus(setupTest, content);
}, true);
content.location = "data:text/html,testing the highlighter goes away on tool selection";
function setupTest() {
openInspector((aInspector, aToolbox) => {
toolbox = aToolbox;
inspector = aInspector;
toolbox.once("picker-stopped", () => {
ok(true, "picker-stopped event fired after switch tools, so picker is closed");
finishUp();
});
openInspector((aInspector, toolbox) => {
let pickerStopped = toolbox.once("picker-stopped");
Task.spawn(function() {
info("Starting the inspector picker");
yield toolbox.highlighterUtils.startPicker();
info("Selecting another tool than the inspector in the toolbox");
yield toolbox.selectNextTool();
}).then(null, Cu.reportError);
info("Waiting for the picker-stopped event to be fired")
yield pickerStopped;
ok(true, "picker-stopped event fired after switch tools, so picker is closed");
}).then(null, ok.bind(null, false)).then(finishUp);
});
}
function finishUp() {
inspector = doc = toolbox = null;
gBrowser.removeCurrentTab();
finish();
}
}

View File

@ -0,0 +1,45 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// Test that the highlighter's picker should be stopped when the toolbox is
// closed
function test() {
let {Task} = Cu.import("resource://gre/modules/Task.jsm", {});
waitForExplicitFinish();
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function onload() {
gBrowser.selectedBrowser.removeEventListener("load", onload, true);
waitForFocus(runTest, content);
}, true);
content.location = "data:text/html,<p>testing the highlighter goes away on destroy</p>";
function runTest() {
openInspector((inspector, toolbox) => {
let pickerStopped = toolbox.once("picker-stopped");
Task.spawn(function() {
// Selecting a node and waiting for inspector-updated event gives the
// inspector a chance to fully update its side-panels and therefore
// avoids errors when removing the tab (due to ongoing requests)
yield inspector.selection.setNode(content.document.querySelector("p"));
yield inspector.once("inspector-updated");
info("inspector displayed and ready, starting the picker");
yield toolbox.highlighterUtils.startPicker();
info("destroying the toolbox");
yield toolbox.destroy();
info("waiting for the picker-stopped event that should be fired when the toolbox is destroyed");
yield pickerStopped;
ok(true, "picker-stopped event fired after switch tools, so picker is closed");
}).then(null, ok.bind(null, false)).then(finishUp);
});
}
function finishUp() {
gBrowser.removeCurrentTab();
finish();
}
}

View File

@ -178,16 +178,18 @@
}
function toggle(id) {
var el = document.getElementById(id);
if (el.getAttribute("collapsed"))
el.setAttribute("collapsed", false);
else
el.setAttribute("collapsed", true);
var element = document.getElementById(id);
if (element.hasAttribute("collapsed")) {
element.removeAttribute("collapsed");
} else {
element.setAttribute("collapsed", true);
}
}
]]></script>
</head>
<body id="errorPage" class="certerror" dir="&locale.dir;">
<div class="top-decoration"></div>
<!-- PAGE CONTAINER (for styling purposes only) -->
<div id="errorPageContainer" class="section">
@ -214,14 +216,14 @@
<!-- The following sections can be unhidden by default by setting the
"browser.xul.error_pages.expert_bad_cert" pref to true -->
<div id="technicalContent" collapsed="true">
<h2 onclick="toggle('technicalContent');" id="technicalContentHeading">&certerror.technical.heading;</h2>
<p id="technicalContentText"/>
<div id="technicalContent" class="expandable-section" collapsed="true">
<h2 onclick="toggle('technicalContent');" id="technicalContentHeading" class="expandable-heading">&certerror.technical.heading;</h2>
<p class="expandable-content" id="technicalContentText"/>
</div>
<div id="expertContent" collapsed="true">
<h2 onclick="toggle('expertContent');" id="expertContentHeading">&certerror.expert.heading;</h2>
<div>
<div id="expertContent" class="expandable-section" collapsed="true">
<h2 onclick="toggle('expertContent');" id="expertContentHeading" class="expandable-heading">&certerror.expert.heading;</h2>
<div class="expandable-content">
<p>&certerror.expert.content;</p>
<p>&certerror.expert.contentPara2;</p>
<xul:button xmlns:xul='http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul' id='temporaryExceptionButton' label='&certerror.addTemporaryException.label;'/>

View File

@ -151,7 +151,7 @@
</head>
<body id="errorPage" class="blockedsite" dir="&locale.dir;">
<div class="top-decoration"></div>
<div id="errorPageContainer" class="section">

View File

@ -121,7 +121,7 @@ HelperAppLauncherDialog.prototype = {
className: "download-filename-text"
},
{
text: aLauncher.downloadSize,
text: downloadSize,
className: "download-size-text"
},
{

View File

@ -115,4 +115,9 @@
% XXX currently, there's some weirdness with the dppx unit, as documented in
% bug 895277. Because of that, we have to use 1.39dppx instead of 1.4dppx.
%define min_res_140pc 1.39dppx
%define min_res_180pc 1.8dppx
%define min_res_180pc 1.8dppx
% error page style constants
%define error_page_background_color #eee
%define error_page_warning_color #efd400
%define error_page_error_color #bf0000

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 850 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 886 B

View File

@ -119,8 +119,12 @@ chrome.jar:
skin/images/errorpage-warning.png (images/errorpage-warning.png)
skin/images/errorpage-warning@1.4x.png (images/errorpage-warning@1.4x.png)
skin/images/errorpage-warning@1.8x.png (images/errorpage-warning@1.8x.png)
skin/images/errorpage-larry-white.png (images/errorpage-larry-white.png)
skin/images/errorpage-larry-black.png (images/errorpage-larry-black.png)
skin/images/errorpage-cert-untrusted.png (images/errorpage-cert-untrusted.png)
skin/images/errorpage-cert-untrusted@1.4x.png (images/errorpage-cert-untrusted@1.4x.png)
skin/images/errorpage-cert-untrusted@1.8x.png (images/errorpage-cert-untrusted@1.8x.png)
skin/images/errorpage-blocked-site.png (images/errorpage-blocked-site.png)
skin/images/errorpage-blocked-site@1.4x.png (images/errorpage-blocked-site@1.4x.png)
skin/images/errorpage-blocked-site@1.8x.png (images/errorpage-blocked-site@1.8x.png)
skin/images/alert-downloads-30.png (images/alert-downloads-30.png)
skin/images/search-glass-30.png (images/search-glass-30.png)
skin/images/play-hdpi.png (images/play-hdpi.png)

View File

@ -65,13 +65,48 @@ li {
padding: 8px 0px;
}
#errorPage.certerror {
background-color: #EFD400;
#errorPage.certerror, #errorPage.blockedsite {
background-color: @error_page_background_color@;
}
#errorPage.blockedsite {
background-color: #BF0000;
color: #fff;
#errorPage button {
margin: 5px 10px 5px 0;
}
#errorPage > .top-decoration {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 25px;
}
#errorPage.certerror > .top-decoration {
background: linear-gradient(-45deg,
@error_page_background_color@ 25%,
@error_page_warning_color@ 25%,
@error_page_warning_color@ 50%,
@error_page_background_color@ 50%,
@error_page_background_color@ 75%,
@error_page_warning_color@ 75%,
@error_page_warning_color@) repeat scroll 0% 0% /
80px 80px transparent;
}
#errorPage.blockedsite > .top-decoration {
background: linear-gradient(-45deg,
@error_page_background_color@ 25%,
@error_page_error_color@ 25%,
@error_page_error_color@ 50%,
@error_page_background_color@ 50%,
@error_page_background_color@ 75%,
@error_page_error_color@ 75%,
@error_page_error_color@) repeat scroll 0% 0% /
80px 80px transparent;
}
#errorPage #cert_domain_link {
color: #0095dd;
}
#errorPage.certerror #errorPageContainer > .section-header,
@ -88,9 +123,6 @@ li {
-moz-padding-end: 24px;
}
#errorTitle {
}
#errorTitleIcon {
background-image: url("chrome://browser/skin/images/errorpage-warning.png");
background-position: center center;
@ -105,11 +137,35 @@ li {
width: 40px;
}
#errorPage.certerror #errorTitleIcon, #errorPage.blockedsite #errorTitleIcon {
background-size: 60px 60px;
width: 60px;
height: 60px;
-moz-margin-start: -80px;
-moz-margin-end: 10px;
}
#errorPage.certerror #errorTitleIcon {
background-image: url("chrome://browser/skin/images/errorpage-cert-untrusted.png");
}
#errorPage.blockedsite #errorTitleIcon {
background-image: url("chrome://browser/skin/images/errorpage-blocked-site.png");
}
@media (min-resolution: @min_res_140pc@) {
/* Load 140% image when scaled by 140% */
#errorTitleIcon {
background-image: url("chrome://browser/skin/images/errorpage-warning@1.4x.png");
}
#errorPage.certerror #errorTitleIcon {
background-image: url("chrome://browser/skin/images/errorpage-cert-untrusted@1.4x.png");
}
#errorPage.blockedsite #errorTitleIcon {
background-image: url("chrome://browser/skin/images/errorpage-blocked-site@1.4x.png");
}
}
@media (min-resolution: @min_res_180pc@) {
@ -117,15 +173,22 @@ li {
#errorTitleIcon {
background-image: url("chrome://browser/skin/images/errorpage-warning@1.8x.png");
}
#errorPage.certerror #errorTitleIcon {
background-image: url("chrome://browser/skin/images/errorpage-cert-untrusted@1.8x.png");
}
#errorPage.blockedsite #errorTitleIcon {
background-image: url("chrome://browser/skin/images/errorpage-blocked-site@1.8x.png");
}
}
#errorPage.certerror #errorTitleIcon {
background-image: url("chrome://browser/skin/images/errorpage-larry-black.png");
}
#errorPage.blockedsite #errorTitleIcon {
background-image: url("chrome://browser/skin/images/errorpage-larry-white.png");
color: white;
@media (max-width: 760px) {
#errorPage.certerror #errorTitleIcon, #errorPage.blockedsite #errorTitleIcon {
display: block;
-moz-margin-start: 0;
-moz-margin-end: 0;
}
}
.errorTitleText {
@ -188,28 +251,25 @@ li {
padding-right: 8px;
}
#securityOverrideDiv {
padding-top: 10px;
}
div[collapsed] {
padding-left: 15px;
background-image: url("chrome://browser/skin/images/arrowright-16.png");
.expandable-section {
background: url("chrome://browser/skin/images/arrowdown-16.png") no-repeat left 0.6em;
background-size: 11px 11px;
background-repeat: no-repeat;
background-position: left 0.6em;
}
div[collapsed="true"] {
.expandable-section[collapsed] {
background-image: url("chrome://browser/skin/images/arrowright-16.png");
}
div[collapsed="false"] {
background-image: url("chrome://browser/skin/images/arrowdown-16.png");
}
div[collapsed="true"] > p,
div[collapsed="true"] > div {
.expandable-section[collapsed] > .expandable-content {
display: none;
}
.expandable-section > .expandable-heading {
cursor: pointer;
-moz-padding-start: 15px;
-moz-user-select: none;
}

View File

@ -2646,10 +2646,12 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
}
.tabbrowser-tab[selected=true]:not(:-moz-lwtheme) {
/* overriding tabbox.css */
color: inherit;
}
.tabbrowser-tab[selected=true]:-moz-lwtheme {
.tabbrowser-tab[selected=true] {
/* overriding tabbox.css */
text-shadow: inherit;
}

View File

@ -8,7 +8,7 @@
toolbarbutton.panel-multiview-anchor {
background-image: url(chrome://browser/skin/customizableui/subView-arrow-back-inverted@2x.png),
linear-gradient(rgba(255,255,255,0.3), rgba(255,255,255,0));
background-size: 16px;
background-size: 16px, auto;
}
#PanelUI-customize {

View File

@ -108,9 +108,18 @@
.panelUI-grid .toolbarbutton-menubutton-button > .toolbarbutton-multiline-text,
.panelUI-grid .toolbarbutton-1 > .toolbarbutton-multiline-text {
margin: 2px 0 0;
text-align: center;
-moz-hyphens: auto;
mask: url(chrome://browser/content/browser.xul#menuPanelButtonTextFadeOutMask);
min-height: 3.5em;
}
.panelUI-grid .toolbarbutton-1 > .toolbarbutton-multiline-text {
margin: 2px 0 0;
}
.panelUI-grid .toolbarbutton-menubutton-button > .toolbarbutton-multiline-text {
margin: -1px 0 0;
}
#wrapper-edit-controls:-moz-any([place="palette"],[place="panel"]) > #edit-controls,
@ -165,14 +174,33 @@ panelview:not([mainview]) .toolbarbutton-text,
toolbaritem[cui-areatype="menu-panel"][sdkstylewidget="true"]:not(.panel-wide-item),
.panelUI-grid .toolbarbutton-1,
.customization-palette .toolbarbutton-1,
.panel-customization-placeholder-child {
-moz-appearance: none;
-moz-box-orient: vertical;
min-width: calc(@menuPanelWidth@ / 3);
max-width: calc(@menuPanelWidth@ / 3);
height: calc(40px + 2.4em);
max-height: calc(40px + 2.4em);
width: calc(@menuPanelWidth@ / 3);
height: calc(40px + 4em);
}
.customization-palette .toolbarbutton-1 {
-moz-appearance: none;
-moz-box-orient: vertical;
}
.panelUI-grid .toolbarbutton-1 > .toolbarbutton-menubutton-button {
-moz-appearance: none;
-moz-box-orient: vertical;
width: calc(@menuPanelWidth@ / 3 - 2px);
height: calc(38px + 4em);
margin-top: 3px; /* Hack needed to get type=menu-button to properly align vertically. */
border: 0;
}
toolbaritem[cui-areatype="menu-panel"][sdkstylewidget="true"]:not(.panel-wide-item),
.panelUI-grid .toolbarbutton-1:not([type="menu-button"]),
.panelUI-grid .toolbarbutton-1 > .toolbarbutton-menubutton-button,
.customization-palette .toolbarbutton-1,
.panel-customization-placeholder-child {
overflow: hidden;
}
.panel-customization-placeholder-child {
@ -186,7 +214,7 @@ toolbaritem[cui-areatype="menu-panel"][sdkstylewidget="true"]:not(.panel-wide-it
width: 16px;
-moz-margin-start: -16px;
height: 40px;
max-height: 40px;
margin-bottom: 4em;
padding: 0;
}
@ -230,7 +258,18 @@ toolbaritem[cui-areatype="menu-panel"][sdkstylewidget="true"]:not(.panel-wide-it
.panel-customization-placeholder-child > .toolbarbutton-icon {
min-width: 32px;
min-height: 32px;
margin: 4px;
/* Explanation for calc((A / B - C) / D), simplified to calc(X / Y - Z):
A / B (@menuPanelWidth@ / 3)
Each button is @menuPanelWidth@ / 3 wide.
C (46px)
The button icon is 32 pixels wide.
The button has 12px of horizontal padding (6 on each side).
The button has 2px of horizontal border (1 on each side).
Total width of button should therefore be 46px.
D (2)
Divide by 2 since each button has two horizontal margins.
*/
margin: 4px calc(@menuPanelWidth@ / 6 - 23px);
}
toolbarpaletteitem[place="palette"] > toolbaritem > toolbarbutton {
@ -421,12 +460,20 @@ panelview .toolbarbutton-1,
padding: 2px 6px;
background-color: hsla(210,4%,10%,0);
border-radius: 2px;
border: 1px solid;
border-style: solid;
border-color: hsla(210,4%,10%,0);
transition-property: background-color, border-color;
transition-duration: 150ms;
}
panelview .toolbarbutton-1,
.subviewbutton,
.widget-overflow-list .toolbarbutton-1,
#edit-controls@inAnyPanel@ > toolbarbutton,
#zoom-controls@inAnyPanel@ > toolbarbutton {
border-width: 1px;
}
.subviewbutton.panel-subview-footer {
border-radius: 0;
border: none;
@ -465,10 +512,6 @@ panelview .toolbarbutton-1,
margin-top: 6px;
}
.panelUI-grid .toolbarbutton-1 > .toolbarbutton-menubutton-button {
border: 0;
}
panelview .toolbarbutton-1@buttonStateHover@,
.subviewbutton@buttonStateHover@,
.widget-overflow-list .toolbarbutton-1@buttonStateHover@,
@ -558,7 +601,7 @@ toolbarbutton.panel-multiview-anchor > .toolbarbutton-menubutton-button {
color: HighlightText;
}
toolbarpaletteitem[place="palette"] > #bookmarks-menu-button > .toolbarbutton-menubutton-dropmarker,
toolbarpaletteitem[place="palette"] > .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker,
#bookmarks-menu-button[cui-areatype="menu-panel"] > .toolbarbutton-menubutton-dropmarker {
display: none;
}

View File

@ -837,11 +837,14 @@ bool DefineOSFileConstants(JSContext *cx, JS::Handle<JSObject*> global)
// library, which is sufficient to link to the library using js-ctypes.
#if defined(XP_MACOSX)
// Under MacOS X, for some reason, libxul is called simply "XUL"
nsAutoString libxul(NS_LITERAL_STRING("XUL"));
// Under MacOS X, for some reason, libxul is called simply "XUL",
// and we need to provide the full path.
nsAutoString libxul;
libxul.Append(gPaths->libDir);
libxul.Append(NS_LITERAL_STRING("/XUL"));
#else
// On other platforms, libxul is a library "xul" with regular
// library prefix/suffix
// library prefix/suffix.
nsAutoString libxul;
libxul.Append(NS_LITERAL_STRING(DLL_PREFIX));
libxul.Append(NS_LITERAL_STRING("xul"));

View File

@ -267,6 +267,7 @@ bool DidProcessCrash(bool* child_exited, ProcessHandle handle) {
if (WIFSIGNALED(status)) {
switch(WTERMSIG(status)) {
case SIGSYS:
case SIGSEGV:
case SIGILL:
case SIGABRT:

View File

@ -543,6 +543,9 @@ abstract public class BrowserApp extends GeckoApp
registerEventListener("Telemetry:Gather");
registerEventListener("Settings:Show");
registerEventListener("Updater:Launch");
registerEventListener("Menu:Add");
registerEventListener("Menu:Remove");
registerEventListener("Menu:Update");
Distribution.init(this);
JavaAddonManager.getInstance().init(getApplicationContext());
@ -857,6 +860,9 @@ abstract public class BrowserApp extends GeckoApp
unregisterEventListener("Telemetry:Gather");
unregisterEventListener("Settings:Show");
unregisterEventListener("Updater:Launch");
unregisterEventListener("Menu:Add");
unregisterEventListener("Menu:Remove");
unregisterEventListener("Menu:Update");
if (AppConstants.MOZ_ANDROID_BEAM && Build.VERSION.SDK_INT >= 14) {
NfcAdapter nfc = NfcAdapter.getDefaultAdapter(this);

View File

@ -360,6 +360,10 @@ public abstract class GeckoApp
}
public MenuPanel getMenuPanel() {
if (mMenuPanel == null) {
onCreatePanelMenu(Window.FEATURE_OPTIONS_PANEL, null);
invalidateOptionsMenu();
}
return mMenuPanel;
}
@ -442,8 +446,9 @@ public abstract class GeckoApp
if (Build.VERSION.SDK_INT >= 11 && featureId == Window.FEATURE_OPTIONS_PANEL) {
if (mMenu == null) {
onCreatePanelMenu(featureId, menu);
onPreparePanel(featureId, mMenuPanel, mMenu);
// getMenuPanel() will force the creation of the menu as well
MenuPanel panel = getMenuPanel();
onPreparePanel(featureId, panel, mMenu);
}
// Scroll custom menu to the top
@ -1409,12 +1414,6 @@ public abstract class GeckoApp
private void initialize() {
mInitialized = true;
if (Build.VERSION.SDK_INT >= 11) {
// Create the panel and inflate the custom menu.
onCreatePanelMenu(Window.FEATURE_OPTIONS_PANEL, null);
}
invalidateOptionsMenu();
Intent intent = getIntent();
String action = intent.getAction();
@ -1528,9 +1527,6 @@ public abstract class GeckoApp
registerEventListener("Reader:Share");
registerEventListener("Reader:FaviconRequest");
registerEventListener("onCameraCapture");
registerEventListener("Menu:Add");
registerEventListener("Menu:Remove");
registerEventListener("Menu:Update");
registerEventListener("Gecko:Ready");
registerEventListener("Gecko:DelayedStartup");
registerEventListener("Toast:Show");
@ -2058,9 +2054,6 @@ public abstract class GeckoApp
unregisterEventListener("Reader:Share");
unregisterEventListener("Reader:FaviconRequest");
unregisterEventListener("onCameraCapture");
unregisterEventListener("Menu:Add");
unregisterEventListener("Menu:Remove");
unregisterEventListener("Menu:Update");
unregisterEventListener("Gecko:Ready");
unregisterEventListener("Gecko:DelayedStartup");
unregisterEventListener("Toast:Show");

View File

@ -11,6 +11,7 @@ import org.mozilla.gecko.Tabs;
import org.mozilla.gecko.animation.PropertyAnimator;
import org.mozilla.gecko.animation.PropertyAnimator.Property;
import org.mozilla.gecko.animation.ViewHelper;
import org.mozilla.gecko.db.BrowserContract.Combined;
import org.mozilla.gecko.db.BrowserContract.Thumbnails;
import org.mozilla.gecko.db.BrowserDB;
import org.mozilla.gecko.db.BrowserDB.URLColumns;
@ -81,7 +82,7 @@ public class TopSitesPanel extends HomeFragment {
private TopSitesGridAdapter mGridAdapter;
// List of top sites
private ListView mList;
private HomeListView mList;
// Grid of top sites
private TopSitesGridView mGrid;
@ -201,6 +202,25 @@ public class TopSitesPanel extends HomeFragment {
}
});
mList.setContextMenuInfoFactory(new HomeListView.ContextMenuInfoFactory() {
@Override
public HomeContextMenuInfo makeInfoForCursor(View view, int position, long id, Cursor cursor) {
final HomeContextMenuInfo info = new HomeContextMenuInfo(view, position, id);
info.url = cursor.getString(cursor.getColumnIndexOrThrow(Combined.URL));
info.title = cursor.getString(cursor.getColumnIndexOrThrow(Combined.TITLE));
info.historyId = cursor.getInt(cursor.getColumnIndexOrThrow(Combined.HISTORY_ID));
final int bookmarkIdCol = cursor.getColumnIndexOrThrow(Combined.BOOKMARK_ID);
if (cursor.isNull(bookmarkIdCol)) {
// If this is a combined cursor, we may get a history item without a
// bookmark, in which case the bookmarks ID column value will be null.
info.bookmarkId = -1;
} else {
info.bookmarkId = cursor.getInt(bookmarkIdCol);
}
return info;
}
});
mGrid.setOnUrlOpenListener(mUrlOpenListener);
mGrid.setOnEditPinnedSiteListener(mEditPinnedSiteListener);
@ -722,7 +742,7 @@ public class TopSitesPanel extends HomeFragment {
if (!c.moveToFirst()) {
return;
}
final ArrayList<String> urls = new ArrayList<String>();
int i = 1;
do {

View File

@ -378,6 +378,10 @@ public abstract class SessionTest extends BaseTest {
}
private String readFile(File target) throws IOException {
if (!target.exists()) {
return null;
}
FileReader fr = new FileReader(target);
try {
StringBuffer sb = new StringBuffer();

View File

@ -132,13 +132,7 @@ public class ToolbarComponent extends BaseComponent {
WaitHelper.waitForPageLoad(new Runnable() {
@Override
public void run() {
if (InputMethods.shouldDisableUrlBarUpdate(mActivity)) {
// Bug 945521 workaround: Some IMEs do not allow the go button
// to be displayed in the toolbar so we hit enter instead.
mSolo.sendKey(Solo.ENTER);
} else {
mSolo.clickOnView(getGoButton());
}
mSolo.clickOnView(getGoButton());
}
});
waitForNotEditing();

View File

@ -27,13 +27,25 @@ public final class GeckoHelper {
}
public static void blockForReady() {
final EventExpecter geckoReady = sActions.expectGeckoEvent("Gecko:Ready");
blockForEvent("Gecko:Ready");
}
final boolean isReady = GeckoThread.checkLaunchState(LaunchState.GeckoRunning);
if (!isReady) {
geckoReady.blockForEvent();
/**
* Blocks for the "Gecko:DelayedStartup" event, which occurs after "Gecko:Ready" and the
* first page load.
*/
public static void blockForDelayedStartup() {
blockForEvent("Gecko:DelayedStartup");
}
private static void blockForEvent(final String eventName) {
final EventExpecter eventExpecter = sActions.expectGeckoEvent(eventName);
final boolean isRunning = GeckoThread.checkLaunchState(LaunchState.GeckoRunning);
if (!isRunning) {
eventExpecter.blockForEvent();
}
geckoReady.unregisterListener();
eventExpecter.unregisterListener();
}
}

View File

@ -13,7 +13,7 @@ public class testAboutHomePageNavigation extends UITest {
// enum for both phone and tablet, then swiping through the panels. This will also
// benefit having a HomePager with custom panels.
public void testAboutHomePageNavigation() {
GeckoHelper.blockForReady();
GeckoHelper.blockForDelayedStartup();
mAboutHome.assertVisible()
.assertCurrentPanel(PanelType.TOP_SITES);

View File

@ -20,8 +20,10 @@ public class testAdobeFlash extends PixelTest {
public void testLoad() {
// This test only works on ICS and higher
if (Build.VERSION.SDK_INT < 15)
if (Build.VERSION.SDK_INT < 15) {
blockForGeckoReady();
return;
}
// Enable plugins
JSONObject jsonPref = new JSONObject();

View File

@ -63,6 +63,11 @@ public class testSessionOOMSave extends SessionTest {
public boolean isSatisfied() {
try {
String sessionString = readProfileFile("sessionstore.js");
if (sessionString == null) {
mLastException = new AssertException("Could not read sessionstore.js");
return false;
}
verifySessionJSON(mSession, sessionString, mAsserter);
} catch (AssertException e) {
mLastException = e;

View File

@ -133,7 +133,7 @@ PaymentUI.prototype = {
let tab = content.BrowserApp.addTab(aPaymentFlowInfo.uri + aPaymentFlowInfo.jwt);
// Inject paymentSuccess and paymentFailed methods into the document after its loaded.
tab.browser.addEventListener("DOMContentLoaded", function loadPaymentShim() {
tab.browser.addEventListener("DOMWindowCreated", function loadPaymentShim() {
let frame = tab.browser.contentDocument.defaultView;
try {
frame.wrappedJSObject.mozPaymentProvider = {
@ -172,7 +172,7 @@ PaymentUI.prototype = {
} catch (e) {
_error(aRequestId, "ERROR_ADDING_METHODS");
} finally {
tab.browser.removeEventListener("DOMContentLoaded", loadPaymentShim);
tab.browser.removeEventListener("DOMWindowCreated", loadPaymentShim);
}
}, true);

View File

@ -43,6 +43,7 @@ SessionStore.prototype = {
_lastSaveTime: 0,
_interval: 10000,
_maxTabsUndo: 1,
_pendingWrite: 0,
init: function ss_init() {
// Get file references
@ -77,6 +78,7 @@ SessionStore.prototype = {
observerService.addObserver(this, "domwindowclosed", true);
observerService.addObserver(this, "browser:purge-session-history", true);
observerService.addObserver(this, "Session:Restore", true);
observerService.addObserver(this, "application-background", true);
break;
case "final-ui-startup":
observerService.removeObserver(this, "final-ui-startup");
@ -102,7 +104,7 @@ SessionStore.prototype = {
if (this._loadState == STATE_RUNNING) {
// Save the purged state immediately
this.saveStateNow();
this.saveState();
}
Services.obs.notifyObservers(null, "sessionstore-state-purge-complete", "");
@ -110,9 +112,12 @@ SessionStore.prototype = {
case "timer-callback":
// Timer call back for delayed saving
this._saveTimer = null;
this.saveState();
if (this._pendingWrite) {
this.saveState();
}
break;
case "Session:Restore": {
Services.obs.removeObserver(this, "Session:Restore");
if (aData) {
// Be ready to handle any restore failures by making sure we have a valid tab opened
let window = Services.wm.getMostRecentWindow("navigator:browser");
@ -143,6 +148,13 @@ SessionStore.prototype = {
}
break;
}
case "application-background":
// We receive this notification when Android's onPause callback is
// executed. After onPause, the application may be terminated at any
// point without notice; therefore, we must synchronously write out any
// pending save state to ensure that this data does not get lost.
this.flushPendingState();
break;
}
},
@ -165,11 +177,15 @@ SessionStore.prototype = {
this.onTabSelect(window, browser);
break;
}
case "pageshow": {
let browser = aEvent.currentTarget;
// Top-level changes only
if (aEvent.originalTarget == browser.contentDocument)
this.onTabLoad(window, browser, aEvent.persisted);
case "DOMTitleChanged": {
let browser = Services.wm.getMostRecentWindow("navigator:browser")
.BrowserApp
.getBrowserForDocument(aEvent.target);
// Use DOMTitleChanged to detect page loads over alternatives.
// onLocationChange happens too early, so we don't have the page title
// yet; pageshow happens too late, so we could lose session data if the
// browser were killed.
this.onTabLoad(window, browser);
break;
}
}
@ -204,6 +220,7 @@ SessionStore.prototype = {
browsers.addEventListener("TabOpen", this, true);
browsers.addEventListener("TabClose", this, true);
browsers.addEventListener("TabSelect", this, true);
browsers.addEventListener("DOMTitleChanged", this, true);
},
onWindowClose: function ss_onWindowClose(aWindow) {
@ -215,6 +232,7 @@ SessionStore.prototype = {
browsers.removeEventListener("TabOpen", this, true);
browsers.removeEventListener("TabClose", this, true);
browsers.removeEventListener("TabSelect", this, true);
browsers.removeEventListener("DOMTitleChanged", this, true);
if (this._loadState == STATE_RUNNING) {
// Update all window data for a last time
@ -235,15 +253,12 @@ SessionStore.prototype = {
},
onTabAdd: function ss_onTabAdd(aWindow, aBrowser, aNoNotification) {
aBrowser.addEventListener("pageshow", this, true);
if (!aNoNotification)
this.saveStateDelayed();
this._updateCrashReportURL(aWindow);
},
onTabRemove: function ss_onTabRemove(aWindow, aBrowser, aNoNotification) {
aBrowser.removeEventListener("pageshow", this, true);
// If this browser is being restored, skip any session save activity
if (aBrowser.__SS_restore)
return;
@ -271,7 +286,7 @@ SessionStore.prototype = {
}
},
onTabLoad: function ss_onTabLoad(aWindow, aBrowser, aPersisted) {
onTabLoad: function ss_onTabLoad(aWindow, aBrowser) {
// If this browser is being restored, skip any session save activity
if (aBrowser.__SS_restore)
return;
@ -282,32 +297,26 @@ SessionStore.prototype = {
let history = aBrowser.sessionHistory;
if (aPersisted && aBrowser.__SS_data) {
// Loading from the cache; just update the index
aBrowser.__SS_data.index = history.index + 1;
this.saveStateDelayed();
} else {
// Serialize the tab data
let entries = [];
let index = history.index + 1;
for (let i = 0; i < history.count; i++) {
let historyEntry = history.getEntryAtIndex(i, false);
// Don't try to restore wyciwyg URLs
if (historyEntry.URI.schemeIs("wyciwyg")) {
// Adjust the index to account for skipped history entries
if (i <= history.index)
index--;
continue;
}
let entry = this._serializeHistoryEntry(historyEntry);
entries.push(entry);
// Serialize the tab data
let entries = [];
let index = history.index + 1;
for (let i = 0; i < history.count; i++) {
let historyEntry = history.getEntryAtIndex(i, false);
// Don't try to restore wyciwyg URLs
if (historyEntry.URI.schemeIs("wyciwyg")) {
// Adjust the index to account for skipped history entries
if (i <= history.index)
index--;
continue;
}
let data = { entries: entries, index: index };
delete aBrowser.__SS_data;
this._collectTabData(aWindow, aBrowser, data);
this.saveStateNow();
let entry = this._serializeHistoryEntry(historyEntry);
entries.push(entry);
}
let data = { entries: entries, index: index };
delete aBrowser.__SS_data;
this._collectTabData(aWindow, aBrowser, data);
this.saveStateDelayed();
this._updateCrashReportURL(aWindow);
},
@ -342,6 +351,7 @@ SessionStore.prototype = {
// If we have to wait, set a timer, otherwise saveState directly
let delay = Math.max(minimalDelay, 2000);
if (delay > 0) {
this._pendingWrite++;
this._saveTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
this._saveTimer.init(this, delay, Ci.nsITimer.TYPE_ONE_SHOT);
} else {
@ -350,16 +360,25 @@ SessionStore.prototype = {
}
},
saveStateNow: function ss_saveStateNow() {
saveState: function ss_saveState() {
this._pendingWrite++;
this._saveState(true);
},
// Immediately and synchronously writes any pending state to disk.
flushPendingState: function ss_flushPendingState() {
if (this._pendingWrite) {
this._saveState(false);
}
},
_saveState: function ss_saveState(aAsync) {
// Kill any queued timer and save immediately
if (this._saveTimer) {
this._saveTimer.cancel();
this._saveTimer = null;
}
this.saveState();
},
saveState: function ss_saveState() {
let data = this._getCurrentState();
let normalData = { windows: [] };
let privateData = { windows: [] };
@ -388,7 +407,7 @@ SessionStore.prototype = {
}
// Write only non-private data to disk
this._writeFile(this._sessionFile, JSON.stringify(normalData));
this._writeFile(this._sessionFile, JSON.stringify(normalData), aAsync);
// If we have private data, send it to Java; otherwise, send null to
// indicate that there is no private data
@ -464,7 +483,7 @@ SessionStore.prototype = {
}
},
_writeFile: function ss_writeFile(aFile, aData) {
_writeFile: function ss_writeFile(aFile, aData, aAsync) {
let stateString = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
stateString.data = aData;
Services.obs.notifyObservers(stateString, "sessionstore-state-write", "");
@ -473,11 +492,28 @@ SessionStore.prototype = {
if (!stateString.data)
return;
// Asynchronously copy the data to the file.
let array = new TextEncoder().encode(aData);
OS.File.writeAtomic(aFile.path, array, { tmpPath: aFile.path + ".tmp" }).then(function onSuccess() {
Services.obs.notifyObservers(null, "sessionstore-state-write-complete", "");
});
if (aAsync) {
let array = new TextEncoder().encode(aData);
let pendingWrite = this._pendingWrite;
OS.File.writeAtomic(aFile.path, array, { tmpPath: aFile.path + ".tmp" }).then(function onSuccess() {
// Make sure this._pendingWrite is the same value it was before we
// fired off the async write. If the count is different, another write
// is pending, so we shouldn't reset this._pendingWrite yet.
if (pendingWrite === this._pendingWrite)
this._pendingWrite = 0;
Services.obs.notifyObservers(null, "sessionstore-state-write-complete", "");
}.bind(this));
} else {
this._pendingWrite = 0;
let foStream = Cc["@mozilla.org/network/file-output-stream;1"].
createInstance(Ci.nsIFileOutputStream);
foStream.init(aFile, 0x02 | 0x08 | 0x20, 0666, 0);
let converter = Cc["@mozilla.org/intl/converter-output-stream;1"].
createInstance(Ci.nsIConverterOutputStream);
converter.init(foStream, "UTF-8", 0, 0);
converter.writeString(aData);
converter.close();
}
},
_updateCrashReportURL: function ss_updateCrashReportURL(aWindow) {

View File

@ -13,13 +13,6 @@
#include "ElfLoader.h"
#ifdef MOZ_MEMORY
// libc's free().
extern "C" void __real_free(void *);
#else
#define __real_free(a) free(a)
#endif
#ifdef DEBUG
#define LOG(x...) __android_log_print(ANDROID_LOG_INFO, "GeckoJNI", x)
#else
@ -91,8 +84,7 @@ throwError(JNIEnv* jenv, const char * funcString) {
LOG("Throwing error: %s\n", msg);
JNI_Throw(jenv, "java/lang/Exception", msg);
// msg is allocated by asprintf, it needs to be freed by libc.
__real_free(msg);
free(msg);
LOG("Error thrown\n");
}

View File

@ -11,13 +11,6 @@
#include "ElfLoader.h"
#include "SQLiteBridge.h"
#ifdef MOZ_MEMORY
// libc's free().
extern "C" void __real_free(void *);
#else
#define __real_free(a) free(a)
#endif
#ifdef DEBUG
#define LOG(x...) __android_log_print(ANDROID_LOG_INFO, "GeckoJNI", x)
#else
@ -85,8 +78,7 @@ static void throwSqliteException(JNIEnv* jenv, const char* aFormat, ...)
vasprintf(&msg, aFormat, ap);
LOG("Error in SQLiteBridge: %s\n", msg);
JNI_Throw(jenv, "org/mozilla/gecko/sqlite/SQLiteBridgeException", msg);
// msg is allocated by vasprintf, it needs to be freed by libc.
__real_free(msg);
free(msg);
va_end(ap);
}

View File

@ -79,6 +79,7 @@
#define AUDIO_MP3 "audio/mpeg"
#define AUDIO_MP4 "audio/mp4"
#define AUDIO_AMR "audio/amr"
#define AUDIO_MIDI "audio/x-midi"
#define BINARY_OCTET_STREAM "binary/octet-stream"

View File

@ -8,11 +8,13 @@
#include <stdio.h>
#include <sys/ptrace.h>
#include <sys/prctl.h>
#include <sys/syscall.h>
#include <signal.h>
#include <string.h>
#include "mozilla/ArrayUtils.h"
#include "mozilla/NullPtr.h"
#include "nsExceptionHandler.h"
#if defined(ANDROID)
#include "android_ucontext.h"
#include <android/log.h>
@ -65,7 +67,8 @@ static void
Reporter(int nr, siginfo_t *info, void *void_context)
{
ucontext_t *ctx = static_cast<ucontext_t*>(void_context);
unsigned long syscall, args[6];
unsigned long syscall_nr, args[6];
pid_t pid = getpid(), tid = syscall(__NR_gettid);
if (nr != SIGSYS) {
return;
@ -77,7 +80,7 @@ Reporter(int nr, siginfo_t *info, void *void_context)
return;
}
syscall = SECCOMP_SYSCALL(ctx);
syscall_nr = SECCOMP_SYSCALL(ctx);
args[0] = SECCOMP_PARM1(ctx);
args[1] = SECCOMP_PARM2(ctx);
args[2] = SECCOMP_PARM3(ctx);
@ -85,10 +88,20 @@ Reporter(int nr, siginfo_t *info, void *void_context)
args[4] = SECCOMP_PARM5(ctx);
args[5] = SECCOMP_PARM6(ctx);
LOG_ERROR("seccomp sandbox violation: pid %u, syscall %lu, args %lu %lu %lu"
" %lu %lu %lu. Killing process.", getpid(), syscall,
LOG_ERROR("seccomp sandbox violation: pid %d, syscall %lu, args %lu %lu %lu"
" %lu %lu %lu. Killing process.", pid, syscall_nr,
args[0], args[1], args[2], args[3], args[4], args[5]);
bool dumped = CrashReporter::WriteMinidumpForSigInfo(nr, info, void_context);
if (!dumped) {
LOG_ERROR("Failed to write minidump");
}
// Try to reraise, so the parent sees that this process crashed.
// (If tgkill is forbidden, then seccomp will raise SIGSYS, which
// also accomplishes that goal.)
signal(SIGSYS, SIG_DFL);
syscall(__NR_tgkill, pid, tid, nr);
_exit(127);
}

View File

@ -329,7 +329,7 @@ AbstractFile.read = function read(path, bytes, options = {}) {
let file = exports.OS.File.open(path);
try {
let buffer = file.read(bytes, options);
if (options.compression == "lz4") {
if ("compression" in options && options.compression == "lz4") {
return Lz4.decompressFileContent(buffer, options);
} else {
return buffer;
@ -399,7 +399,7 @@ AbstractFile.writeAtomic =
buffer = new TextEncoder(encoding).encode(buffer);
}
if (options.compression == "lz4") {
if ("compression" in options && options.compression == "lz4") {
buffer = Lz4.compressFileContent(buffer, options);
options = Object.create(options);
options.bytes = buffer.byteLength;

View File

@ -19,6 +19,7 @@ Cu.import("resource://gre/modules/LightweightThemeManager.jsm", this);
Cu.import("resource://gre/modules/ThirdPartyCookieProbe.jsm", this);
Cu.import("resource://gre/modules/Promise.jsm", this);
Cu.import("resource://gre/modules/Task.jsm", this);
Cu.import("resource://gre/modules/AsyncShutdown.jsm", this);
// When modifying the payload in incompatible ways, please bump this version number
const PAYLOAD_VERSION = 1;
@ -901,7 +902,16 @@ let Impl = {
Telemetry.canRecord = false;
return;
}
Services.obs.addObserver(this, "profile-before-change2", false);
AsyncShutdown.sendTelemetry.addBlocker(
"Telemetry: shutting down",
function condition(){
this.uninstall();
if (Telemetry.canSend) {
return this.savePendingPings();
}
}.bind(this));
Services.obs.addObserver(this, "sessionstore-windows-restored", false);
Services.obs.addObserver(this, "quit-application-granted", false);
#ifdef MOZ_WIDGET_ANDROID
@ -985,7 +995,6 @@ let Impl = {
Services.obs.removeObserver(this, "xul-window-visible");
this._hasXulWindowVisibleObserver = false;
}
Services.obs.removeObserver(this, "profile-before-change2");
Services.obs.removeObserver(this, "quit-application-granted");
#ifdef MOZ_WIDGET_ANDROID
Services.obs.removeObserver(this, "application-background", false);
@ -1079,13 +1088,6 @@ let Impl = {
case "idle":
this.sendIdlePing(false, this._server);
break;
case "profile-before-change2":
this.uninstall();
if (Telemetry.canSend) {
return this.savePendingPings();
} else {
return Promise.resolve();
}
#ifdef MOZ_WIDGET_ANDROID
// On Android, we can get killed without warning once we are in the background,

View File

@ -0,0 +1,28 @@
commit 443e11243cf3c88087b70602822d9e228f60d40a
Author: Jed Davis <jld@mozilla.com>
Date: Wed Jan 29 12:06:33 2014 -0800
Bug 945498: Use breakpad to report seccomp violations as crashes.
diff --git a/toolkit/crashreporter/google-breakpad/src/client/linux/handler/exception_handler.h b/toolkit/crashreporter/google-breakpad/src/client/linux/handler/exception_handler.h
index 7155419..c0039bc 100644
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/handler/exception_handler.h
+++ b/toolkit/crashreporter/google-breakpad/src/client/linux/handler/exception_handler.h
@@ -219,6 +219,9 @@ class ExceptionHandler {
// Force signal handling for the specified signal.
bool SimulateSignalDelivery(int sig);
+
+ // Report a crash signal from an SA_SIGINFO signal handler.
+ bool HandleSignal(int sig, siginfo_t* info, void* uc);
private:
// Save the old signal handlers and install new ones.
static bool InstallHandlersLocked();
@@ -231,7 +234,6 @@ class ExceptionHandler {
void WaitForContinueSignal();
static void SignalHandler(int sig, siginfo_t* info, void* uc);
- bool HandleSignal(int sig, siginfo_t* info, void* uc);
static int ThreadEntry(void* arg);
bool DoDump(pid_t crashing_process, const void* context,
size_t context_size);

View File

@ -219,6 +219,9 @@ class ExceptionHandler {
// Force signal handling for the specified signal.
bool SimulateSignalDelivery(int sig);
// Report a crash signal from an SA_SIGINFO signal handler.
bool HandleSignal(int sig, siginfo_t* info, void* uc);
private:
// Save the old signal handlers and install new ones.
static bool InstallHandlersLocked();
@ -231,7 +234,6 @@ class ExceptionHandler {
void WaitForContinueSignal();
static void SignalHandler(int sig, siginfo_t* info, void* uc);
bool HandleSignal(int sig, siginfo_t* info, void* uc);
static int ThreadEntry(void* arg);
bool DoDump(pid_t crashing_process, const void* context,
size_t context_size);

View File

@ -1739,6 +1739,13 @@ nsresult WriteMinidumpForException(EXCEPTION_POINTERS* aExceptionInfo)
}
#endif
#ifdef XP_LINUX
bool WriteMinidumpForSigInfo(int signo, siginfo_t* info, void* uc)
{
return gExceptionHandler->HandleSignal(signo, info, uc);
}
#endif
#ifdef XP_MACOSX
nsresult AppendObjCExceptionInfoToAppNotes(void *inException)
{

View File

@ -22,6 +22,10 @@
#include <mach/mach.h>
#endif
#if defined(XP_LINUX)
#include <signal.h>
#endif
class nsIFile;
template<class KeyClass, class DataType> class nsDataHashtable;
class nsCStringHashKey;
@ -69,6 +73,9 @@ void RenameAdditionalHangMinidump(nsIFile* minidump, nsIFile* childMinidump,
#ifdef XP_WIN32
nsresult WriteMinidumpForException(EXCEPTION_POINTERS* aExceptionInfo);
#endif
#ifdef XP_LINUX
bool WriteMinidumpForSigInfo(int signo, siginfo_t* info, void* uc);
#endif
#ifdef XP_MACOSX
nsresult AppendObjCExceptionInfoToAppNotes(void *inException);
#endif

View File

@ -565,12 +565,10 @@ WebappsActor.prototype = {
}
if (this._isAppAllowedForManifest(app.manifestURL)) {
let deferred = promise.defer();
reg.getManifestFor(manifestURL, function (manifest) {
return reg.getManifestFor(manifestURL).then(function (manifest) {
app.manifest = manifest;
deferred.resolve({app: app});
return {app: app};
});
return deferred.promise;
}
return { error: "forbidden" };
},

View File

@ -414,5 +414,6 @@ Spinner.prototype = {
// mechanisms, we register a few runstates here.
this.AsyncShutdown.profileBeforeChange = getPhase("profile-before-change");
this.AsyncShutdown.sendTelemetry = getPhase("profile-before-change2");
this.AsyncShutdown.webWorkersShutdown = getPhase("web-workers-shutdown");
Object.freeze(this.AsyncShutdown);

View File

@ -534,7 +534,8 @@ static nsExtraMimeTypeEntry extraMimeEntries [] =
{ AUDIO_MP4, "m4a", "MPEG-4 Audio" },
{ VIDEO_RAW, "yuv", "Raw YUV Video" },
{ AUDIO_WAV, "wav", "Waveform Audio" },
{ VIDEO_3GPP, "3gpp,3gp", "3GPP Video" }
{ VIDEO_3GPP, "3gpp,3gp", "3GPP Video" },
{ AUDIO_MIDI, "mid", "Standard MIDI Audio" }
};
#undef MAC_TYPE