Merge mozilla-central to inbound. a=merge CLOSED TREE

This commit is contained in:
Brindusan Cristian 2018-12-11 00:11:47 +02:00
commit cab76a96b5
89 changed files with 1079 additions and 1982 deletions

View File

@ -155,3 +155,4 @@ ad179a6fc14cbd41d10a018ac4a3822db119de3b FIREFOX_BETA_64_BASE
c44fbdd5173548c9035256dda8fd3512f67118a8 FIREFOX_NIGHTLY_64_END
58a0412e15574f063cd380517a0369bfb48b22e0 PRE_TREEWIDE_CLANG_FORMAT
9ad82455dcee2bc1d438e46016b8db00e88758a8 FIREFOX_BETA_65_BASE
3386ff76878d83496bb822d09115c77472808b53 FIREFOX_NIGHTLY_65_END

View File

@ -22,4 +22,4 @@
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
# don't change CLOBBER for WebIDL changes any more.
Bug 1499026 - Update to ICU 63 requires clobber
Merge day clobber

View File

@ -748,7 +748,7 @@ var BookmarksEventHandler = {
// is middle-clicked or when a non-bookmark item (except for Open in Tabs)
// in a bookmarks menupopup is middle-clicked.
if (target.localName == "menu" || target.localName == "toolbarbutton")
PlacesUIUtils.openContainerNodeInTabs(target._placesNode, aEvent, aView);
PlacesUIUtils.openMultipleLinksInTabs(target._placesNode, aEvent, aView);
} else if (aEvent.button == 1) {
// left-clicks with modifier are already served by onCommand
this.onCommand(aEvent);

View File

@ -626,26 +626,36 @@ var PlacesUIUtils = {
});
},
openContainerNodeInTabs:
function PUIU_openContainerInTabs(aNode, aEvent, aView) {
let window = aView.ownerWindow;
let urlsToOpen = PlacesUtils.getURLsForContainerNode(aNode);
if (OpenInTabsUtils.confirmOpenInTabs(urlsToOpen.length, window)) {
this._openTabset(urlsToOpen, aEvent, window);
}
},
openURINodesInTabs: function PUIU_openURINodesInTabs(aNodes, aEvent, aView) {
let window = aView.ownerWindow;
/**
* Loads a selected node's or nodes' URLs in tabs,
* warning the user when lots of URLs are being opened
*
* @param {object|array} nodeOrNodes
* Contains the node or nodes that we're opening in tabs
* @param {event} event
* The DOM mouse/key event with modifier keys set that track the
* user's preferred destination window or tab.
* @param {object} view
* The current view that contains the node or nodes selected for
* opening
*/
openMultipleLinksInTabs(nodeOrNodes, event, view) {
let window = view.ownerWindow;
let urlsToOpen = [];
for (var i = 0; i < aNodes.length; i++) {
// Skip over separators and folders.
if (PlacesUtils.nodeIsURI(aNodes[i]))
urlsToOpen.push({uri: aNodes[i].uri, isBookmark: PlacesUtils.nodeIsBookmark(aNodes[i])});
if (PlacesUtils.nodeIsContainer(nodeOrNodes)) {
urlsToOpen = PlacesUtils.getURLsForContainerNode(nodeOrNodes);
} else {
for (var i = 0; i < nodeOrNodes.length; i++) {
// Skip over separators and folders.
if (PlacesUtils.nodeIsURI(nodeOrNodes[i])) {
urlsToOpen.push({uri: nodeOrNodes[i].uri, isBookmark: PlacesUtils.nodeIsBookmark(nodeOrNodes[i])});
}
}
}
if (OpenInTabsUtils.confirmOpenInTabs(urlsToOpen.length, window)) {
this._openTabset(urlsToOpen, event, window);
}
this._openTabset(urlsToOpen, aEvent, window);
},
/**
@ -956,7 +966,7 @@ var PlacesUIUtils = {
} else if (!mouseInGutter && openInTabs &&
event.originalTarget.localName == "treechildren") {
tbo.view.selection.select(cell.row);
this.openContainerNodeInTabs(tree.selectedNode, event, tree);
this.openMultipleLinksInTabs(tree.selectedNode, event, tree);
} else if (!mouseInGutter && !isContainer &&
event.originalTarget.localName == "treechildren") {
// Clear all other selection since we're loading a link now. We must

View File

@ -658,7 +658,7 @@ PlacesViewBase.prototype = {
aPopup._endOptOpenAllInTabs.classList.add(this.options.extraClasses.footer);
aPopup._endOptOpenAllInTabs.setAttribute("oncommand",
"PlacesUIUtils.openContainerNodeInTabs(this.parentNode._placesNode, event, " +
"PlacesUIUtils.openMultipleLinksInTabs(this.parentNode._placesNode, event, " +
"PlacesUIUtils.getViewForNode(this));");
aPopup._endOptOpenAllInTabs.setAttribute("onclick",
"checkForMiddleClick(this, event); event.stopPropagation();");

View File

@ -646,10 +646,7 @@ PlacesController.prototype = {
if (!node && !nodes.length) {
node = this._view.result.root;
}
if (node && PlacesUtils.nodeIsContainer(node))
PlacesUIUtils.openContainerNodeInTabs(node, aEvent, this._view);
else
PlacesUIUtils.openURINodesInTabs(nodes, aEvent, this._view);
PlacesUIUtils.openMultipleLinksInTabs(node ? node : nodes, aEvent, this._view);
},
/**

View File

@ -353,7 +353,7 @@ var PlacesOrganizer = {
// The command execution function will take care of seeing if the
// selection is a folder or a different container type, and will
// load its contents in tabs.
PlacesUIUtils.openContainerNodeInTabs(node, aEvent, this._places);
PlacesUIUtils.openMultipleLinksInTabs(node, aEvent, this._places);
}
}
},
@ -1295,7 +1295,7 @@ var ContentTree = {
// The command execution function will take care of seeing if the
// selection is a folder or a different container type, and will
// load its contents in tabs.
PlacesUIUtils.openContainerNodeInTabs(node, aEvent, this.view);
PlacesUIUtils.openMultipleLinksInTabs(node, aEvent, this.view);
}
}
},

View File

@ -73,6 +73,7 @@ skip-if = (verify && debug && (os == 'mac' || os == 'linux'))
[browser_library_panel_leak.js]
[browser_library_search.js]
[browser_library_views_liveupdate.js]
[browser_library_warnOnOpen.js]
[browser_markPageAsFollowedLink.js]
[browser_panelview_bookmarks_delete.js]
[browser_paste_bookmarks.js]

View File

@ -0,0 +1,140 @@
/* 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/. */
/*
* Bug 1435562 - Test that browser.tabs.warnOnOpen is respected when
* opening multiple items from the Library. */
"use strict";
var gLibrary = null;
add_task(async function setup() {
// Temporarily disable history, so we won't record pages navigation.
await SpecialPowers.pushPrefEnv({set: [
["places.history.enabled", false],
]});
// Open Library window.
gLibrary = await promiseLibrary();
registerCleanupFunction(async () => {
// We must close "Other Bookmarks" ready for other tests.
gLibrary.PlacesOrganizer.selectLeftPaneBuiltIn("UnfiledBookmarks");
gLibrary.PlacesOrganizer._places.selectedNode.containerOpen = false;
await PlacesUtils.bookmarks.eraseEverything();
// Close Library window.
await promiseLibraryClosed(gLibrary);
});
});
add_task(async function test_warnOnOpenFolder() {
// Generate a list of links larger than browser.tabs.maxOpenBeforeWarn
const MAX_LINKS = 16;
let children = [];
for (let i = 0; i < MAX_LINKS; i++) {
children.push({
title: `Folder Target ${i}`,
url: `http://example${i}.com`,
});
}
// Create a new folder containing our links.
await PlacesUtils.bookmarks.insertTree({
guid: PlacesUtils.bookmarks.unfiledGuid,
children: [{
title: "bigFolder",
type: PlacesUtils.bookmarks.TYPE_FOLDER,
children,
}],
});
info("Pushed test folder into the bookmarks tree");
// Select unsorted bookmarks root in the left pane.
gLibrary.PlacesOrganizer.selectLeftPaneBuiltIn("UnfiledBookmarks");
info("Got selection in the Library left pane");
// Get our bookmark in the right pane.
gLibrary.ContentTree.view.view.nodeForTreeIndex(0);
info("Got bigFolder in the right pane");
gLibrary.PlacesOrganizer._places.selectedNode.containerOpen = true;
// Middle-click on folder (opens all links in folder) and then cancel opening in the dialog
let promiseLoaded = BrowserTestUtils.promiseAlertDialog("cancel");
let bookmarkedNode = gLibrary.PlacesOrganizer._places.selectedNode.getChild(0);
mouseEventOnCell(gLibrary.PlacesOrganizer._places,
gLibrary.PlacesOrganizer._places.view.treeIndexForNode(bookmarkedNode),
0,
{ button: 1 });
await promiseLoaded;
Assert.ok(true, "Expected dialog was shown when attempting to open folder with lots of links");
await PlacesUtils.bookmarks.eraseEverything();
});
add_task(async function test_warnOnOpenLinks() {
// Generate a list of links larger than browser.tabs.maxOpenBeforeWarn
const MAX_LINKS = 16;
let children = [];
for (let i = 0; i < MAX_LINKS; i++) {
children.push({
title: `Highlighted Target ${i}`,
url: `http://example${i}.com`,
});
}
// Insert the links into the tree
await PlacesUtils.bookmarks.insertTree({
guid: PlacesUtils.bookmarks.toolbarGuid,
children,
});
info("Pushed test folder into the bookmarks tree");
gLibrary.PlacesOrganizer.selectLeftPaneBuiltIn("BookmarksToolbar");
info("Got selection in the Library left pane");
// Select all the links
gLibrary.ContentTree.view.selectAll();
let placesContext = gLibrary.document.getElementById("placesContext");
let promiseContextMenu = BrowserTestUtils.waitForEvent(placesContext, "popupshown");
// Open up the context menu and select "Open All In Tabs" (the first item in the list)
synthesizeClickOnSelectedTreeCell(gLibrary.ContentTree.view, {
button: 2,
type: "contextmenu",
});
await promiseContextMenu;
info("Context menu opened as expected");
let openTabs = gLibrary.document.getElementById("placesContext_openLinks:tabs");
let promiseLoaded = BrowserTestUtils.promiseAlertDialog("cancel");
EventUtils.synthesizeMouseAtCenter(openTabs, {}, gLibrary);
await promiseLoaded;
Assert.ok(true, "Expected dialog was shown when attempting to open lots of selected links");
await PlacesUtils.bookmarks.eraseEverything();
});
function mouseEventOnCell(aTree, aRowIndex, aColumnIndex, aEventDetails) {
var selection = aTree.view.selection;
selection.select(aRowIndex);
aTree.treeBoxObject.ensureRowIsVisible(aRowIndex);
var column = aTree.columns[aColumnIndex];
// get cell coordinates
var rect = aTree.treeBoxObject.getCoordsForCellItem(aRowIndex, column, "text");
EventUtils.synthesizeMouse(aTree.body, rect.x, rect.y,
aEventDetails, gLibrary);
}

View File

@ -67,7 +67,7 @@ function promiseClipboard(aPopulateClipboardFn, aFlavor) {
function synthesizeClickOnSelectedTreeCell(aTree, aOptions) {
let tbo = aTree.treeBoxObject;
if (tbo.view.selection.count != 1)
if (tbo.view.selection.count < 1)
throw new Error("The test node should be successfully selected");
// Get selection rowID.
let min = {}, max = {};

View File

@ -1 +1 @@
65.0a1
66.0a1

View File

@ -1 +1 @@
65.0a1
66.0a1

View File

@ -1,5 +1,5 @@
This is the PDF.js project output, https://github.com/mozilla/pdf.js
Current extension version is: 2.1.86
Current extension version is: 2.1.97
Taken from upstream commit: 1cb7cc9b
Taken from upstream commit: 45c01974

View File

@ -123,8 +123,8 @@ return /******/ (function(modules) { // webpackBootstrap
"use strict";
var pdfjsVersion = '2.1.86';
var pdfjsBuild = '1cb7cc9b';
var pdfjsVersion = '2.1.97';
var pdfjsBuild = '45c01974';
var pdfjsSharedUtil = __w_pdfjs_require__(1);
@ -5141,7 +5141,7 @@ function _fetchDocument(worker, source, pdfDataRangeTransport, docId) {
return worker.messageHandler.sendWithPromise('GetDocRequest', {
docId,
apiVersion: '2.1.86',
apiVersion: '2.1.97',
source: {
data: source.data,
url: source.url,
@ -6860,9 +6860,9 @@ const InternalRenderTask = function InternalRenderTaskClosure() {
return InternalRenderTask;
}();
const version = '2.1.86';
const version = '2.1.97';
exports.version = version;
const build = '1cb7cc9b';
const build = '45c01974';
exports.build = build;
/***/ }),

View File

@ -123,8 +123,8 @@ return /******/ (function(modules) { // webpackBootstrap
"use strict";
var pdfjsVersion = '2.1.86';
var pdfjsBuild = '1cb7cc9b';
var pdfjsVersion = '2.1.97';
var pdfjsBuild = '45c01974';
var pdfjsCoreWorker = __w_pdfjs_require__(1);
@ -375,7 +375,7 @@ var WorkerMessageHandler = {
var cancelXHRs = null;
var WorkerTasks = [];
let apiVersion = docParams.apiVersion;
let workerVersion = '2.1.86';
let workerVersion = '2.1.97';
if (apiVersion !== workerVersion) {
throw new Error(`The API version "${apiVersion}" does not match ` + `the Worker version "${workerVersion}".`);

View File

@ -416,21 +416,14 @@ let PDFViewerApplication = {
},
async _readPreferences() {
const OVERRIDES = {
disableFontFace: true,
disableRange: true,
disableStream: true,
textLayerMode: _ui_utils.TextLayerMode.DISABLE
};
if (_app_options.AppOptions.get('disablePreferences') === true) {
return;
}
try {
const prefs = await this.preferences.getAll();
for (let name in prefs) {
if (name in OVERRIDES && _app_options.AppOptions.get(name) === OVERRIDES[name]) {
continue;
}
for (const name in prefs) {
_app_options.AppOptions.set(name, prefs[name]);
}
} catch (reason) {}
@ -5980,7 +5973,7 @@ class PDFHistory {
let forceReplace = false;
if (this._destination.page === position.first || this._destination.page === position.page) {
if (this._destination.page >= position.first && this._destination.page <= position.page) {
if (this._destination.dest || !this._destination.first) {
return;
}

View File

@ -20,7 +20,7 @@ origin:
# Human-readable identifier for this version/release
# Generally "version NNN", "tag SSS", "bookmark SSS"
release: version 2.1.86
release: version 2.1.97
# The package's license, where possible using the mnemonic from
# https://spdx.org/licenses/

View File

@ -128,10 +128,6 @@ locales = [
reference = "browser/extensions/formautofill/locales/en-US/**"
l10n = "{l}browser/extensions/formautofill/**"
[[paths]]
reference = "browser/extensions/onboarding/locales/en-US/**"
l10n = "{l}browser/extensions/onboarding/**"
[[paths]]
reference = "browser/extensions/webcompat-reporter/locales/en-US/**"
l10n = "{l}browser/extensions/webcompat-reporter/**"

View File

@ -273,10 +273,11 @@ var ContentSearch = {
let ok = SearchSuggestionController.engineOffersSuggestions(engine);
controller.maxLocalResults = ok ? MAX_LOCAL_SUGGESTIONS : MAX_SUGGESTIONS;
controller.maxRemoteResults = ok ? MAX_SUGGESTIONS : 0;
let priv = PrivateBrowsingUtils.isBrowserPrivate(browser);
// fetch() rejects its promise if there's a pending request, but since we
// process our event queue serially, there's never a pending request.
this._currentSuggestion = { controller, target: browser };
let suggestions = await controller.fetch(searchString, engine);
let suggestions = await controller.fetch(searchString, priv, engine);
this._currentSuggestion = null;
// suggestions will be null if the request was cancelled

View File

@ -10,4 +10,4 @@
# hardcoded milestones in the tree from these two files.
#--------------------------------------------------------
65.0a1
66.0a1

View File

@ -22,6 +22,7 @@
@import "resource://devtools/client/aboutdebugging-new/src/components/debugtarget/DebugTargetPane.css";
@import "resource://devtools/client/aboutdebugging-new/src/components/debugtarget/ExtensionDetail.css";
@import "resource://devtools/client/aboutdebugging-new/src/components/debugtarget/WorkerDetail.css";
@import "resource://devtools/client/aboutdebugging-new/src/components/shared/ErrorMessage.css";
@import "resource://devtools/client/aboutdebugging-new/src/components/sidebar/Sidebar.css";
@import "resource://devtools/client/aboutdebugging-new/src/components/sidebar/SidebarFixedItem.css";
@import "resource://devtools/client/aboutdebugging-new/src/components/sidebar/SidebarItem.css";

View File

@ -34,6 +34,9 @@ const {
REQUEST_WORKERS_FAILURE,
REQUEST_WORKERS_START,
REQUEST_WORKERS_SUCCESS,
TEMPORARY_EXTENSION_INSTALL_FAILURE,
TEMPORARY_EXTENSION_INSTALL_START,
TEMPORARY_EXTENSION_INSTALL_SUCCESS,
RUNTIMES,
} = require("../constants");
@ -83,11 +86,13 @@ function inspectDebugTarget(type, id) {
function installTemporaryExtension() {
const message = l10n.getString("about-debugging-tmp-extension-install-message");
return async (dispatch, getState) => {
dispatch({ type: TEMPORARY_EXTENSION_INSTALL_START });
const file = await openTemporaryExtension(window, message);
try {
await AddonManager.installTemporaryAddon(file);
dispatch({ type: TEMPORARY_EXTENSION_INSTALL_SUCCESS });
} catch (e) {
console.error(e);
dispatch({ type: TEMPORARY_EXTENSION_INSTALL_FAILURE, error: e });
}
};
}

View File

@ -44,6 +44,8 @@
--base-line-height: 1.8;
--micro-font-size: 11px;
--monospace-font-family: monospace;
/*
* Variables particular to about:debugging
*/
@ -105,6 +107,11 @@ a:active {
white-space: nowrap;
}
/* Technical text that should use a monospace font, such as code, error messages. */
.technical-text {
font-family: var(--monospace-font-family);
}
/*
* Typography
*/
@ -188,7 +195,6 @@ a:active {
-moz-context-properties: fill;
}
/*
* Layout elements
*/

View File

@ -47,6 +47,7 @@ class RuntimePage extends PureComponent {
sharedWorkers: PropTypes.arrayOf(PropTypes.object).isRequired,
tabs: PropTypes.arrayOf(PropTypes.object).isRequired,
temporaryExtensions: PropTypes.arrayOf(PropTypes.object).isRequired,
temporaryInstallError: PropTypes.string,
};
}
@ -104,6 +105,7 @@ class RuntimePage extends PureComponent {
sharedWorkers,
tabs,
temporaryExtensions,
temporaryInstallError,
} = this.props;
if (!runtimeInfo) {
@ -124,8 +126,10 @@ class RuntimePage extends PureComponent {
? this.renderConnectionPromptSetting()
: null,
isSupportedDebugTargetPane(runtimeInfo.type, DEBUG_TARGET_PANE.TEMPORARY_EXTENSION)
? TemporaryExtensionInstaller({ dispatch })
: null,
? TemporaryExtensionInstaller({
dispatch,
temporaryInstallError,
}) : null,
this.renderDebugTargetPane("Temporary Extensions",
temporaryExtensions,
TemporaryExtensionAction,
@ -177,6 +181,7 @@ const mapStateToProps = state => {
sharedWorkers: state.debugTargets.sharedWorkers,
tabs: state.debugTargets.tabs,
temporaryExtensions: state.debugTargets.temporaryExtensions,
temporaryInstallError: state.ui.temporaryInstallError,
};
};

View File

@ -11,6 +11,8 @@ const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const FluentReact = require("devtools/client/shared/vendor/fluent-react");
const Localized = createFactory(FluentReact.Localized);
const ErrorMessage = createFactory(require("../shared/ErrorMessage"));
const Actions = require("../../actions/index");
/**
@ -20,6 +22,7 @@ class TemporaryExtensionInstaller extends PureComponent {
static get propTypes() {
return {
dispatch: PropTypes.func.isRequired,
temporaryInstallError: PropTypes.string,
};
}
@ -28,17 +31,32 @@ class TemporaryExtensionInstaller extends PureComponent {
}
render() {
return Localized(
{
id: "about-debugging-tmp-extension-install-button",
},
dom.button(
const { temporaryInstallError } = this.props;
return dom.div(
{},
Localized(
{
className: "default-button js-temporary-extension-install-button",
onClick: e => this.install(),
id: "about-debugging-tmp-extension-install-button",
},
"Load Temporary Add-on…"
)
dom.button(
{
className: "default-button js-temporary-extension-install-button",
onClick: e => this.install(),
},
"Load Temporary Add-on…"
)
),
temporaryInstallError ? ErrorMessage(
{
errorDescriptionKey: "about-debugging-tmp-extension-install-error",
},
dom.div(
{
className: "technical-text",
},
temporaryInstallError
)
) : null
);
}
}

View File

@ -5,6 +5,7 @@
DIRS += [
'connect',
'debugtarget',
'shared',
'sidebar',
]

View File

@ -0,0 +1,30 @@
/* 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/. */
.error-message {
/* Temporary color chosen to match error background used in about:addons
* Pending UX in Bug 1509091 */
background-color: #FFE8E9;
/* Temporary color chosen to match chrome://mozapps/skin/extensions/alerticon-error.svg
* Pending UX in Bug 1509091 */
color: #E62117;
margin: calc(var(--base-distance) * 2) 0;
padding: var(--base-distance) calc(var(--base-distance) * 3);
}
/*
* Layout of the error message header
*
* +--------+----------------+
* | Icon | Header message |
* +--------+----------------+
*/
.error-message__header {
align-items: center;
display: grid;
grid-template-columns: calc(var(--base-distance) * 6) 1fr;
font-weight: bold;
}

View File

@ -0,0 +1,56 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const { createFactory, PureComponent } = require("devtools/client/shared/vendor/react");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const FluentReact = require("devtools/client/shared/vendor/fluent-react");
const Localized = createFactory(FluentReact.Localized);
/**
* This component is designed to display an error message. It is composed of a header
* displaying an error icon followed by a provided localized error description.
* Children passed to this component will be displayed beflow the message header.
*/
class ErrorMessage extends PureComponent {
static get propTypes() {
return {
children: PropTypes.node.isRequired,
// Should match a valid localized string key.
errorDescriptionKey: PropTypes.string.isRequired,
};
}
render() {
return dom.div(
{
className: "error-message js-error-message",
},
dom.div(
{
className: "error-message__header",
},
dom.img(
{
// Temporary image chosen to match error container in about:addons.
// Pending UX in Bug 1509091
src: "chrome://mozapps/skin/extensions/alerticon-error.svg",
}
),
Localized(
{
id: this.props.errorDescriptionKey,
},
dom.span({}, this.props.errorDescriptionKey)
)
),
this.props.children
);
}
}
module.exports = ErrorMessage;

View File

@ -0,0 +1,8 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DevToolsModules(
'ErrorMessage.css',
'ErrorMessage.js',
)

View File

@ -30,6 +30,9 @@ const actionTypes = {
REQUEST_WORKERS_FAILURE: "REQUEST_WORKERS_FAILURE",
REQUEST_WORKERS_START: "REQUEST_WORKERS_START",
REQUEST_WORKERS_SUCCESS: "REQUEST_WORKERS_SUCCESS",
TEMPORARY_EXTENSION_INSTALL_FAILURE: "TEMPORARY_EXTENSION_INSTALL_FAILURE",
TEMPORARY_EXTENSION_INSTALL_START: "TEMPORARY_EXTENSION_INSTALL_START",
TEMPORARY_EXTENSION_INSTALL_SUCCESS: "TEMPORARY_EXTENSION_INSTALL_SUCCESS",
UNWATCH_RUNTIME_FAILURE: "UNWATCH_RUNTIME_FAILURE",
UNWATCH_RUNTIME_START: "UNWATCH_RUNTIME_START",
UNWATCH_RUNTIME_SUCCESS: "UNWATCH_RUNTIME_SUCCESS",

View File

@ -9,6 +9,8 @@ const {
DEBUG_TARGET_COLLAPSIBILITY_UPDATED,
NETWORK_LOCATIONS_UPDATED,
PAGE_SELECTED,
TEMPORARY_EXTENSION_INSTALL_FAILURE,
TEMPORARY_EXTENSION_INSTALL_SUCCESS,
USB_RUNTIMES_SCAN_START,
USB_RUNTIMES_SCAN_SUCCESS,
} = require("../constants");
@ -24,6 +26,7 @@ function UiState(locations = [], debugTargetCollapsibilities = {},
selectedPage: null,
selectedRuntime: null,
showSystemAddons,
temporaryInstallError: null,
wifiEnabled,
};
}
@ -61,6 +64,15 @@ function uiReducer(state = UiState(), action) {
return Object.assign({}, state, { isScanningUsb: false });
}
case TEMPORARY_EXTENSION_INSTALL_SUCCESS: {
return Object.assign({}, state, { temporaryInstallError: null });
}
case TEMPORARY_EXTENSION_INSTALL_FAILURE: {
const { error } = action;
return Object.assign({}, state, { temporaryInstallError: error.message });
}
default:
return state;
}

View File

@ -11,6 +11,7 @@ support-files =
head-mocks.js
head.js
mocks/*
resources/bad-extension/*
resources/test-adb-extension/*
resources/test-temporary-extension/*
test-tab-favicons.html
@ -43,6 +44,7 @@ skip-if = (os == 'linux' && bits == 32) # ADB start() fails on linux 32, see Bug
skip-if = (os == 'linux' && bits == 32) # ADB start() fails on linux 32, see Bug 1499638
[browser_aboutdebugging_system_addons.js]
[browser_aboutdebugging_tab_favicons.js]
[browser_aboutdebugging_temporary_addon_install_error.js]
[browser_aboutdebugging_thisfirefox.js]
[browser_aboutdebugging_thisfirefox_runtime_info.js]
[browser_aboutdebugging_thisfirefox_worker_inspection.js]

View File

@ -0,0 +1,46 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/* import-globals-from head-addons-script.js */
"use strict";
// Load addons helpers
Services.scriptloader.loadSubScript(CHROME_URL_ROOT + "head-addons-script.js", this);
/**
* Test that the installation error messages are displayed when installing temporary
* extensions.
*/
const BAD_EXTENSION_PATH = "resources/bad-extension/manifest.json";
const EXTENSION_PATH = "resources/test-temporary-extension/manifest.json";
const EXTENSION_NAME = "test-temporary-extension";
add_task(async function() {
const { document, tab } = await openAboutDebugging();
info("Install a bad extension");
// Do not use installTemporaryAddon here since the install will fail.
prepareMockFilePicker(BAD_EXTENSION_PATH);
document.querySelector(".js-temporary-extension-install-button").click();
info("Wait until the install error message appears");
await waitUntil(() => document.querySelector(".js-error-message"));
const installError = document.querySelector(".js-error-message");
ok(installError.textContent.includes("JSON.parse: unexpected keyword"),
"The expected installation error is displayed: " + installError.textContent);
info("Install a valid extension to make the message disappear");
await installTemporaryExtension(EXTENSION_PATH, EXTENSION_NAME, document);
info("Wait until the error message disappears");
await waitUntil(() => !document.querySelector(".js-error-message"));
info("Wait for the temporary addon to be displayed as a debug target");
await waitUntil(() => findDebugTargetByText(EXTENSION_NAME, document));
await removeTemporaryExtension(EXTENSION_NAME, document);
await removeTab(tab);
});

View File

@ -1,6 +1,7 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/* import-globals-from ../../../shared/test/shared-head.js */
/* import-globals-from head.js */
"use strict";
@ -21,10 +22,7 @@ function getSupportsFile(path) {
// eslint-disable-next-line no-unused-vars
async function installTemporaryExtension(path, name, document) {
// Mock the file picker to select a test addon
const MockFilePicker = SpecialPowers.MockFilePicker;
MockFilePicker.init(window);
const file = getSupportsFile(path);
MockFilePicker.setFiles([file.file]);
prepareMockFilePicker(path);
const onAddonInstalled = new Promise(done => {
Management.on("startup", function listener(event, extension) {
@ -43,3 +41,19 @@ async function installTemporaryExtension(path, name, document) {
info("Wait for addon to be installed");
await onAddonInstalled;
}
async function removeTemporaryExtension(name, document) {
info(`Remove the temporary extension with name: '${name}'`);
const temporaryExtensionItem = findDebugTargetByText(name, document);
temporaryExtensionItem.querySelector(".js-temporary-extension-remove-button").click();
info("Wait until the debug target item disappears");
await waitUntil(() => !findDebugTargetByText(name, document));
}
function prepareMockFilePicker(path) {
// Mock the file picker to select a test addon
const MockFilePicker = SpecialPowers.MockFilePicker;
MockFilePicker.init(window);
MockFilePicker.setFiles([getSupportsFile(path).file]);
}

View File

@ -0,0 +1 @@
this is not valid json

View File

@ -119,6 +119,9 @@ about-debugging-debug-target-inspect-button = Inspect
# section. Clicking on the button will open a file picker to load a temporary extension
about-debugging-tmp-extension-install-button = Load Temporary Add-on…
# Text displayed when trying to install a temporary extension in the "This Firefox" page.
about-debugging-tmp-extension-install-error = There was an error during the temporary add-on installation.
# Text of a button displayed for a temporary extension loaded in the "This Firefox" page.
# Clicking on the button will reload the extension.
about-debugging-tmp-extension-reload-button = Reload

View File

@ -230,13 +230,21 @@ function tunnelToInnerBrowser(outer, inner) {
// Add mozbrowser event handlers
inner.addEventListener("mozbrowseropenwindow", this);
inner.addEventListener("mozbrowsershowmodalprompt", this);
},
handleEvent(event) {
if (event.type != "mozbrowseropenwindow") {
return;
switch (event.type) {
case "mozbrowseropenwindow":
this.handleOpenWindowEvent(event);
break;
case "mozbrowsershowmodalprompt":
this.handleModalPromptEvent(event);
break;
}
},
handleOpenWindowEvent(event) {
// Minimal support for <a target/> and window.open() which just ensures we at
// least open them somewhere (in a new tab). The following things are ignored:
// * Specific target names (everything treated as _blank)
@ -257,6 +265,29 @@ function tunnelToInnerBrowser(outer, inner) {
outer.contentPrincipal);
},
handleModalPromptEvent({ detail }) {
// Relay window.alert(), window.prompt() and window.confirm() dialogs through the
// outer window and make sure the return value is passed back to the inner window.
// When this event handler is called, the inner iframe is spinning in a nested event
// loop waiting to be unblocked.
// If we were calling preventDefault() here, then we would have to call
// detail.unblock() to unblock the inner iframe.
// But since we aren't the inner iframe will be unblocked automatically as soon as
// the mozbrowsershowmodalprompt event is done dispatching (i.e. as soon as this
// handler completes).
// See _handleShowModelPrompt in /dom/browser-element/BrowserElementParent.js
if (!["alert", "prompt", "confirm"].includes(detail.promptType)) {
return;
}
const promptFunction = outer.contentWindow[detail.promptType];
// Passing the initial value is useful for window.prompt() and doesn't hurt
// window.alert() and window.confirm(). See the Window webidl:
// https://searchfox.org/mozilla-central/source/dom/webidl/Window.webidl#77-80
detail.returnValue = promptFunction(detail.message, detail.initialValue);
},
stop() {
const tab = gBrowser.getTabForBrowser(outer);
const filteredProgressListener = gBrowser._tabFilters.get(tab);
@ -289,6 +320,7 @@ function tunnelToInnerBrowser(outer, inner) {
// Remove mozbrowser event handlers
inner.removeEventListener("mozbrowseropenwindow", this);
inner.removeEventListener("mozbrowsershowmodalprompt", this);
mmTunnel.destroy();
mmTunnel = null;

View File

@ -51,6 +51,7 @@ skip-if = true # Bug 1413765
tags = devtools geolocation
skip-if = true # Bug 1413765
[browser_preloaded_newtab.js]
[browser_prompts.js]
[browser_screenshot_button.js]
[browser_state_restore.js]
[browser_tab_close.js]

View File

@ -0,0 +1,76 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that alert, confirm and prompt are supported in RDM.
const TEST_URL = `data:text/html;charset=utf-8,
<CENTER>
<font face='comic sans ms' size='7'>ALERTS!</font>
</CENTER>`;
addRDMTask(TEST_URL, async function({ ui }) {
const { toolWindow } = ui;
const { store } = toolWindow;
await waitUntilState(store, state => state.viewports.length == 1);
// Alerts coming from inside the viewport are relayed by RDM to the outer browser.
// So, in order to test that those relayed prompts occur, let's override the usual
// alert, prompt and confirm methods there to test that they get called.
const { alert: oldAlert, prompt: oldPrompt, confirm: oldConfirm } = toolWindow;
info("Listen for calls on alert, prompt and confirm");
const prompts = [];
toolWindow.alert = message => {
prompts.push({
promptType: "alert",
message,
});
};
toolWindow.prompt = (message, initialValue) => {
prompts.push({
promptType: "prompt",
message,
initialValue,
});
};
toolWindow.confirm = message => {
prompts.push({
promptType: "confirm",
message,
});
};
info("Trigger a few prompts from inside the viewport");
await spawnViewportTask(ui, {}, function() {
content.alert("Some simple alert");
content.prompt("Some simple prompt");
content.prompt("Some simple prompt with initial value", "initial value");
content.confirm("Some simple confirm");
});
is(prompts.length, 4, "The right number of prompts was detected");
is(prompts[0].promptType, "alert", "Prompt 1 has the right type");
is(prompts[0].message, "Some simple alert", "Prompt 1 has the right message");
ok(!prompts[0].initialValue, "Prompt 1 has the right initialValue");
is(prompts[1].promptType, "prompt", "Prompt 2 has the right type");
is(prompts[1].message, "Some simple prompt", "Prompt 2 has the right message");
ok(!prompts[1].initialValue, "Prompt 2 has the right initialValue");
is(prompts[2].promptType, "prompt", "Prompt 3 has the right type");
is(prompts[2].message, "Some simple prompt with initial value",
"Prompt 3 has the right message");
is(prompts[2].initialValue, "initial value", "Prompt 3 has the right initialValue");
is(prompts[3].promptType, "confirm", "Prompt 4 has the right type");
is(prompts[3].message, "Some simple confirm", "Prompt 4 has the right message");
ok(!prompts[3].initialValue, "Prompt 4 has the right initialValue");
// Revert the old versions of alert, prompt and confirm.
toolWindow.alert = oldAlert;
toolWindow.prompt = oldPrompt;
toolWindow.confirm = oldConfirm;
});

View File

@ -1,8 +1,8 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<svg xmlns="http://www.w3.org/2000/svg" width="16px" height="16px" fill="none" stroke="context-fill #0b0b0b" stroke-width="0.8">
<path d="M8,2.7c0.7,0,1.3,0.6,1.3,1.3S8.7,5.3,8,5.3S6.7,4.7,6.7,4S7.3,2.7,8,2.7z"/>
<path d="M12,6.9H9.7v3v2.7c0,0.4-0.3,0.7-0.7,0.7S8.3,13,8.3,12.6V9.9H7.7v2.7c0,0.4-0.3,0.7-0.7,0.7S6.3,13,6.3,12.6
V7.4V7H4C3.6,7,3.3,6.7,3.3,6.3c0-0.4,0.3-0.7,0.7-0.7h2.3h3.3H12c0.3,0,0.6,0.2,0.6,0.5C12.7,6.6,12.4,6.9,12,6.9z"/>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="context-fill #0b0b0b">
<path d="M10 14V6h3.75M7 14V6H3.5" fill="none" stroke="context-fill" stroke-width="2" stroke-linecap="round"/>
<path d="M7 5h3v6H7z"/>
<circle cx="8.5" cy="2.6" r="1.8"/>
</svg>

Before

Width:  |  Height:  |  Size: 669 B

After

Width:  |  Height:  |  Size: 485 B

View File

@ -385,10 +385,10 @@ const AccessibleActor = ActorClassWithSpec(accessibleSpec, {
return null;
}
return getContrastRatioFor(this.rawAccessible.DOMNode.parentNode, {
const { DOMNode: rawNode } = this.rawAccessible;
return getContrastRatioFor(rawNode.parentNode, {
bounds: this.bounds,
contexts: this.walker.contexts,
win: this.walker.rootWin,
win: rawNode.ownerGlobal,
});
},

View File

@ -500,12 +500,14 @@ const AccessibleWalkerActor = ActorClassWithSpec(accessibleWalkerSpec, {
// highlighter temporarily modifies text color related CSS properties. In case where
// there are transitions that affect them, there might be unexpected side effects when
// taking a snapshot for contrast measurement)
loadSheet(this.rootWin, HIGHLIGHTER_STYLES_SHEET);
const { DOMNode: rawNode } = accessible.rawAccessible;
const win = rawNode.ownerGlobal;
loadSheet(win, HIGHLIGHTER_STYLES_SHEET);
const { audit, name, role } = accessible;
const shown = this.highlighter.show({ rawNode: accessible.rawAccessible.DOMNode },
{ ...options, ...bounds, name, role, audit });
const shown = this.highlighter.show({ rawNode },
{ ...options, ...bounds, name, role, audit });
// Re-enable transitions.
removeSheet(this.rootWin, HIGHLIGHTER_STYLES_SHEET);
removeSheet(win, HIGHLIGHTER_STYLES_SHEET);
return shown;
},

View File

@ -162,9 +162,6 @@ function getBgRGBA(dataText, dataBackground) {
* @param {Object} options
* - bounds {Object}
* Bounds for the accessible object.
* - contexts {null|Object}
* Canvas rendering contexts that have a window drawn as is and also
* with the all text made transparent for contrast comparison.
* - win {Object}
* Target window.
*

View File

@ -450,7 +450,6 @@ nsresult nsTextControlFrame::CreateRootNode() {
disp->mOverflowX != NS_STYLE_OVERFLOW_CLIP) {
classValue.AppendLiteral(" inherit-overflow");
}
classValue.AppendLiteral(" inherit-scroll-behavior");
}
nsresult rv = mRootNode->SetAttr(kNameSpaceID_None, nsGkAtoms::_class,
classValue, false);

View File

@ -172,14 +172,15 @@ input > .preview-div {
white-space: pre;
}
textarea > .anonymous-div.inherit-overflow {
overflow: inherit;
}
textarea > .anonymous-div.inherit-scroll-behavior {
textarea > .anonymous-div {
scroll-behavior: inherit;
overscroll-behavior: inherit;
}
textarea > .anonymous-div.inherit-overflow {
overflow: inherit;
}
input::placeholder,
textarea::placeholder,
input > .preview-div,

View File

@ -1,205 +0,0 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_AUDIO_DEVICE_AUDIO_DEVICE_SNDIO_H
#define WEBRTC_AUDIO_DEVICE_AUDIO_DEVICE_SNDIO_H
#include <memory>
#include <sndio.h>
#include "webrtc/modules/audio_device/audio_device_generic.h"
#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
#include "webrtc/base/platform_thread.h"
namespace webrtc
{
class AudioDeviceSndio : public AudioDeviceGeneric
{
public:
AudioDeviceSndio(const int32_t id);
virtual ~AudioDeviceSndio();
// Retrieve the currently utilized audio layer
virtual int32_t ActiveAudioLayer(
AudioDeviceModule::AudioLayer& audioLayer) const override;
// Main initializaton and termination
virtual InitStatus Init() override;
virtual int32_t Terminate() override;
virtual bool Initialized() const override;
// Device enumeration
virtual int16_t PlayoutDevices() override;
virtual int16_t RecordingDevices() override;
virtual int32_t PlayoutDeviceName(
uint16_t index,
char name[kAdmMaxDeviceNameSize],
char guid[kAdmMaxGuidSize]) override;
virtual int32_t RecordingDeviceName(
uint16_t index,
char name[kAdmMaxDeviceNameSize],
char guid[kAdmMaxGuidSize]) override;
// Device selection
virtual int32_t SetPlayoutDevice(uint16_t index) override;
virtual int32_t SetPlayoutDevice(
AudioDeviceModule::WindowsDeviceType device) override;
virtual int32_t SetRecordingDevice(uint16_t index) override;
virtual int32_t SetRecordingDevice(
AudioDeviceModule::WindowsDeviceType device) override;
// Audio transport initialization
virtual int32_t PlayoutIsAvailable(bool& available) override;
virtual int32_t InitPlayout() override;
virtual bool PlayoutIsInitialized() const override;
virtual int32_t RecordingIsAvailable(bool& available) override;
virtual int32_t InitRecording() override;
virtual bool RecordingIsInitialized() const override;
// Audio transport control
virtual int32_t StartPlayout() override;
virtual int32_t StopPlayout() override;
virtual bool Playing() const override;
virtual int32_t StartRecording() override;
virtual int32_t StopRecording() override;
virtual bool Recording() const override;
// Microphone Automatic Gain Control (AGC)
virtual int32_t SetAGC(bool enable) override;
virtual bool AGC() const override;
// Volume control based on the Windows Wave API (Windows only)
virtual int32_t SetWaveOutVolume(uint16_t volumeLeft,
uint16_t volumeRight) override;
virtual int32_t WaveOutVolume(uint16_t& volumeLeft,
uint16_t& volumeRight) const override;
// Audio mixer initialization
virtual int32_t InitSpeaker() override;
virtual bool SpeakerIsInitialized() const override;
virtual int32_t InitMicrophone() override;
virtual bool MicrophoneIsInitialized() const override;
// Speaker volume controls
virtual int32_t SpeakerVolumeIsAvailable(bool& available) override;
virtual int32_t SetSpeakerVolume(uint32_t volume) override;
virtual int32_t SpeakerVolume(uint32_t& volume) const override;
virtual int32_t MaxSpeakerVolume(uint32_t& maxVolume) const override;
virtual int32_t MinSpeakerVolume(uint32_t& minVolume) const override;
virtual int32_t SpeakerVolumeStepSize(uint16_t& stepSize) const override;
// Microphone volume controls
virtual int32_t MicrophoneVolumeIsAvailable(bool& available) override;
virtual int32_t SetMicrophoneVolume(uint32_t volume) override;
virtual int32_t MicrophoneVolume(uint32_t& volume) const override;
virtual int32_t MaxMicrophoneVolume(uint32_t& maxVolume) const override;
virtual int32_t MinMicrophoneVolume(uint32_t& minVolume) const override;
virtual int32_t MicrophoneVolumeStepSize(
uint16_t& stepSize) const override;
// Speaker mute control
virtual int32_t SpeakerMuteIsAvailable(bool& available) override;
virtual int32_t SetSpeakerMute(bool enable) override;
virtual int32_t SpeakerMute(bool& enabled) const override;
// Microphone mute control
virtual int32_t MicrophoneMuteIsAvailable(bool& available) override;
virtual int32_t SetMicrophoneMute(bool enable) override;
virtual int32_t MicrophoneMute(bool& enabled) const override;
// Microphone boost control
virtual int32_t MicrophoneBoostIsAvailable(bool& available) override;
virtual int32_t SetMicrophoneBoost(bool enable) override;
virtual int32_t MicrophoneBoost(bool& enabled) const override;
// Stereo support
virtual int32_t StereoPlayoutIsAvailable(bool& available) override;
virtual int32_t SetStereoPlayout(bool enable) override;
virtual int32_t StereoPlayout(bool& enabled) const override;
virtual int32_t StereoRecordingIsAvailable(bool& available) override;
virtual int32_t SetStereoRecording(bool enable) override;
virtual int32_t StereoRecording(bool& enabled) const override;
// Delay information and control
virtual int32_t SetPlayoutBuffer(
const AudioDeviceModule::BufferType type,
uint16_t sizeMS) override;
virtual int32_t PlayoutBuffer(
AudioDeviceModule::BufferType& type,
uint16_t& sizeMS) const override;
virtual int32_t PlayoutDelay(uint16_t& delayMS) const override;
virtual int32_t RecordingDelay(uint16_t& delayMS) const override;
virtual int32_t CPULoad(uint16_t& load) const override;
public:
virtual bool PlayoutWarning() const override;
virtual bool PlayoutError() const override;
virtual bool RecordingWarning() const override;
virtual bool RecordingError() const override;
virtual void ClearPlayoutWarning() override;
virtual void ClearPlayoutError() override;
virtual void ClearRecordingWarning() override;
virtual void ClearRecordingError() override;
virtual void AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) override;
// needs to be public because playOnmove/recOnmove are extern "C" ?
int _recDelay, _playDelay;
private:
static bool RecThreadFunc(void *);
static bool PlayThreadFunc(void *);
bool RecThreadProcess();
bool PlayThreadProcess();
private:
AudioDeviceBuffer* _ptrAudioBuffer;
struct sio_hdl* _playHandle;
struct sio_hdl* _recHandle;
struct sio_par _playParams, _recParams;
CriticalSectionWrapper& _critSect;
std::unique_ptr<rtc::PlatformThread> _ptrThreadRec;
std::unique_ptr<rtc::PlatformThread> _ptrThreadPlay;
int32_t _id;
int8_t* _recordingBuffer;
int8_t* _playoutBuffer;
uint8_t _recChannels;
uint8_t _playChannels;
unsigned int _recFrames;
unsigned int _playFrames;
AudioDeviceModule::BufferType _playBufType;
bool _initialized;
bool _recording;
bool _playing;
bool _AGC;
uint16_t _playWarning;
uint16_t _playError;
uint16_t _recWarning;
uint16_t _recError;
uint16_t _playBufDelay; // playback delay
uint16_t _playBufDelayFixed; // fixed playback delay
};
}
#endif

View File

@ -436,9 +436,8 @@ int VP8EncoderImpl::InitEncode(const VideoCodec* inst,
if (encoded_images_[i]._buffer != NULL) {
delete[] encoded_images_[i]._buffer;
}
// Reserve 100 extra bytes for overhead at small resolutions.
encoded_images_[i]._size =
CalcBufferSize(VideoType::kI420, codec_.width, codec_.height) + 100;
CalcBufferSize(VideoType::kI420, codec_.width, codec_.height);
encoded_images_[i]._buffer = new uint8_t[encoded_images_[i]._size];
encoded_images_[i]._completeFrame = true;
}

View File

@ -149,6 +149,7 @@ import org.mozilla.gecko.util.ActivityUtils;
import org.mozilla.gecko.util.ContextUtils;
import org.mozilla.gecko.util.DrawableUtil;
import org.mozilla.gecko.util.EventCallback;
import org.mozilla.gecko.util.FileUtils;
import org.mozilla.gecko.util.GamepadUtils;
import org.mozilla.gecko.util.GeckoBundle;
import org.mozilla.gecko.util.HardwareUtils;
@ -785,6 +786,7 @@ public class BrowserApp extends GeckoApp
"Feedback:MaybeLater",
"Sanitize:ClearHistory",
"Sanitize:ClearSyncedTabs",
"Sanitize:Cache",
"Telemetry:Gather",
"Download:AndroidDownloadManager",
"Website:AppInstalled",
@ -1520,6 +1522,7 @@ public class BrowserApp extends GeckoApp
"Feedback:MaybeLater",
"Sanitize:ClearHistory",
"Sanitize:ClearSyncedTabs",
"Sanitize:Cache",
"Telemetry:Gather",
"Download:AndroidDownloadManager",
"Website:AppInstalled",
@ -1890,6 +1893,18 @@ public class BrowserApp extends GeckoApp
callback.sendSuccess(null);
break;
case "Sanitize:Cache":
final File cacheFolder = new File(getCacheDir(), FileUtils.CONTENT_TEMP_DIRECTORY);
// file.delete() throws an exception if the path does not exists
// e.g you can get in this scenario after two cache clearing in a row
if (cacheFolder.exists()) {
FileUtils.delTree(cacheFolder, null, true);
// now we can delete the folder
cacheFolder.delete();
}
callback.sendSuccess(null);
break;
case "Sanitize:ClearSyncedTabs":
FennecTabsRepository.deleteNonLocalClientsAndTabs(this);
callback.sendSuccess(null);

View File

@ -81,26 +81,31 @@ Sanitizer.prototype = {
// Any further specific differences caused by architectural differences between
// Fennec and desktop Firefox are documented below for each item.
items: {
// Same as desktop Firefox.
// The difference is specifically the Sanitize:Cache message,
// so that the Android front-end can clear its caches as well,
// while everything else is unchanged.
cache: {
clear: function() {
return new Promise(function(resolve, reject) {
let refObj = {};
TelemetryStopwatch.start("FX_SANITIZE_CACHE", refObj);
let refObj = {};
TelemetryStopwatch.start("FX_SANITIZE_CACHE", refObj);
try {
Services.cache2.clear();
} catch (er) {}
try {
Services.cache2.clear();
} catch (er) {}
let imageCache = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools)
let imageCache = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools)
.getImgCacheForDocument(null);
try {
imageCache.clearCache(false); // true=chrome, false=content
} catch (er) {}
try {
imageCache.clearCache(false); // true=chrome, false=content
} catch (er) {}
TelemetryStopwatch.finish("FX_SANITIZE_CACHE", refObj);
resolve();
});
return EventDispatcher.instance.sendRequestForResult({ type: "Sanitize:Cache" })
.catch((err) => {
Cu.reportError(`Java-side cache clearing failed with error: ${err}`);
})
.then(() => {
TelemetryStopwatch.finish("FX_SANITIZE_CACHE", refObj);
});
},
get canClear() {

View File

@ -4,6 +4,7 @@
package org.mozilla.mozstumbler.service.stumblerthread.scanners;
import android.annotation.SuppressLint;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@ -211,6 +212,7 @@ public class WifiScanner extends BroadcastReceiver {
return true;
}
@SuppressLint("WifiManagerPotentialLeak")
private WifiManager getWifiManager() {
return (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
}

View File

@ -1171,4 +1171,4 @@ static const TransportSecurityPreload kPublicKeyPinningPreloadList[] = {
static const int32_t kUnknownId = -1;
static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1552565349122000);
static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1552911097642000);

File diff suppressed because it is too large Load Diff

View File

@ -8,7 +8,7 @@ for (let [key, val] of Object.entries({
// Don't manually modify this line, as it is automatically replaced on merge day
// by the gecko_migration.py script.
WEAVE_VERSION: "1.67.0",
WEAVE_VERSION: "1.68.0",
// Sync Server API version that the client supports.
SYNC_API_VERSION: "1.5",

View File

@ -1,5 +1,6 @@
import httplib
import json
import select
import urlparse
import error
@ -83,9 +84,35 @@ class HTTPWireProtocol(object):
self.port = port
self.url_prefix = url_prefix
self._conn = None
self._timeout = timeout
def __del__(self):
self.close()
def close(self):
"""Closes the current HTTP connection, if there is one."""
if self._conn:
self._conn.close()
@property
def connection(self):
"""Gets the current HTTP connection, or lazily creates one."""
if not self._conn:
conn_kwargs = {}
if self._timeout is not None:
conn_kwargs["timeout"] = timeout
self._conn = httplib.HTTPConnection(
self.host, self.port, strict=True, **conn_kwargs)
return self._conn
def url(self, suffix):
"""
From the relative path to a command end-point,
craft a full URL suitable to be used in a request to the HTTPD.
"""
return urlparse.urljoin(self.url_prefix, suffix)
def send(self,
@ -111,6 +138,8 @@ class HTTPWireProtocol(object):
element references to ``webdriver.Element`` is provided.
Use ``webdriver.protocol.Decoder`` to achieve this behaviour.
The client will attempt to use persistent HTTP connections.
:param method: `GET`, `POST`, or `DELETE`.
:param uri: Relative endpoint of the requests URL path.
:param body: Body of the request. Defaults to an empty
@ -141,26 +170,23 @@ class HTTPWireProtocol(object):
raise ValueError("Failed to encode request body as JSON:\n"
"%s" % json.dumps(body, indent=2))
if isinstance(payload, text_type):
payload = body.encode("utf-8")
response = self._request(method, uri, payload, headers)
return Response.from_http(response, decoder=decoder, **codec_kwargs)
def _request(self, method, uri, payload, headers=None):
if isinstance(payload, text_type):
payload = body.encode("utf-8")
if headers is None:
headers = {}
headers.update({'Connection': 'keep-alive'})
headers.update({"Connection": "keep-alive"})
url = self.url(uri)
conn_kwargs = {}
if self._timeout is not None:
conn_kwargs["timeout"] = self._timeout
if self._has_unread_data():
self.close()
self.connection.request(method, url, payload, headers)
return self.connection.getresponse()
conn = httplib.HTTPConnection(
self.host, self.port, strict=True, **conn_kwargs)
conn.request(method, url, payload, headers)
try:
response = conn.getresponse()
return Response.from_http(
response, decoder=decoder, **codec_kwargs)
finally:
conn.close()
def _has_unread_data(self):
return self._conn and select.select([self._conn.sock], [], [], 0)[0]

View File

@ -98,6 +98,10 @@ class MarionetteBaseProtocolPart(BaseProtocolPart):
except errors.ScriptTimeoutException:
self.logger.debug("Script timed out")
pass
except errors.JavascriptException as e:
# This can happen if we navigate, but just keep going
self.logger.debug(e.message)
pass
except IOError:
self.logger.debug("Socket closed")
break

View File

@ -18,7 +18,7 @@
#include "updatehelper.h"
#include "shellapi.h"
#include "readstrings.h"
#include "errors.h"
#include "updatererrors.h"
#include "commonupdatedir.h"
#pragma comment(lib, "version.lib")

View File

@ -31,7 +31,7 @@ using mozilla::UniquePtr;
#include "uachelper.h"
#include "updatehelper.h"
#include "pathhash.h"
#include "errors.h"
#include "updatererrors.h"
#include "commonupdatedir.h"
#define PATCH_DIR_PATH L"\\updates\\0"

View File

@ -137,7 +137,7 @@ class SuggestionsFetch {
this._engine = engine;
this._suggestions = [];
this._success = false;
this._promise = this._controller.fetch(searchString, engine, userContextId).then(results => {
this._promise = this._controller.fetch(searchString, inPrivateContext, engine, userContextId).then(results => {
this._success = true;
if (results) {
this._suggestions.push(

View File

@ -19,6 +19,10 @@ const BROWSER_SUGGEST_PREF = "browser.search.suggest.enabled";
const REMOTE_TIMEOUT_PREF = "browser.search.suggest.timeout";
const REMOTE_TIMEOUT_DEFAULT = 500; // maximum time (ms) to wait before giving up on a remote suggestions
XPCOMUtils.defineLazyServiceGetter(this, "UUIDGenerator",
"@mozilla.org/uuid-generator;1",
"nsIUUIDGenerator");
/**
* Remote search suggestions will be shown if gRemoteSuggestionsEnabled
* is true. Global because only one pref observer is needed for all instances.
@ -28,6 +32,20 @@ Services.prefs.addObserver(BROWSER_SUGGEST_PREF, function(aSubject, aTopic, aDat
gRemoteSuggestionsEnabled = Services.prefs.getBoolPref(BROWSER_SUGGEST_PREF);
});
/**
* Generates an UUID.
* @returns an UUID string, without leading or trailing braces.
*/
function uuid() {
let uuid = UUIDGenerator.generateUUID().toString();
return uuid.slice(1, uuid.length - 1);
}
// Maps each engine name to a unique firstPartyDomain, so that requests to
// different engines are isolated from each other and from normal browsing.
// This is the same for all the controllers.
var gFirstPartyDomains = new Map();
/**
* SearchSuggestionController.jsm exists as a helper module to allow multiple consumers to request and display
* search suggestions from a given engine, regardless of the base implementation. Much of this
@ -46,8 +64,6 @@ function SearchSuggestionController(callback = null) {
}
this.SearchSuggestionController.prototype = {
FIRST_PARTY_DOMAIN: "search.suggestions.8c845959-a33d-4787-953c-5d55a0afd56e.mozilla",
/**
* The maximum number of local form history results to return. This limit is
* only enforced if remote results are also returned.
@ -96,20 +112,26 @@ this.SearchSuggestionController.prototype = {
// Public methods
/**
* Gets the firstPartyDomains Map, useful for tests.
* @returns {Map} firstPartyDomains mapped by engine names.
*/
get firstPartyDomains() {
return gFirstPartyDomains;
},
/**
* Fetch search suggestions from all of the providers. Fetches in progress will be stopped and
* results from them will not be provided.
*
* @param {string} searchTerm - the term to provide suggestions for
* @param {bool} privateMode - whether the request is being made in the context of private browsing
* @param {nsISearchEngine} engine - search engine for the suggestions.
* @param {int} userContextId - the userContextId of the selected tab.
* @param {bool} privateMode - whether the request should be made private.
* Note that usually we want a private context, even in a non-private
* window, because we don't want to store cookies and offline data.
*
* @return {Promise} resolving to an object containing results or null.
*/
fetch(searchTerm, engine, userContextId = 0, privateMode = true) {
fetch(searchTerm, privateMode, engine, userContextId = 0) {
// There is no smart filtering from previous results here (as there is when looking through
// history/form data) because the result set returned by the server is different for every typed
// value - e.g. "ocean breathes" does not return a subset of the results returned for "ocean".
@ -119,6 +141,9 @@ this.SearchSuggestionController.prototype = {
if (!Services.search.isInitialized) {
throw new Error("Search not initialized yet (how did you get here?)");
}
if (typeof privateMode === "undefined") {
throw new Error("The privateMode argument is required to avoid unintentional privacy leaks");
}
if (!(engine instanceof Ci.nsISearchEngine)) {
throw new Error("Invalid search engine");
}
@ -231,12 +256,26 @@ this.SearchSuggestionController.prototype = {
SEARCH_RESPONSE_SUGGESTION_JSON);
let method = (submission.postData ? "POST" : "GET");
this._request.open(method, submission.uri.spec, true);
// Don't set or store cookies or on-disk cache.
this._request.channel.loadFlags = Ci.nsIChannel.LOAD_ANONYMOUS |
Ci.nsIChannel.INHIBIT_PERSISTENT_CACHING;
// Use a unique first-party domain for each engine, to isolate the
// suggestions requests.
if (!gFirstPartyDomains.has(engine.name)) {
// Use the engine identifier, or an uuid when not available, because the
// domain cannot contain invalid chars and the engine name may not be
// suitable. When using an uuid the firstPartyDomain of the same engine
// will differ across restarts, but that's acceptable for now.
// TODO (Bug 1511339): use a persistent unique identifier per engine.
gFirstPartyDomains.set(engine.name,
`${engine.identifier || uuid()}.search.suggestions.mozilla`);
}
let firstPartyDomain = gFirstPartyDomains.get(engine.name);
this._request.setOriginAttributes({
userContextId,
privateBrowsingId: privateMode ? 1 : 0,
// Use a unique first-party domain to isolate the suggestions cookies.
firstPartyDomain: this.FIRST_PARTY_DOMAIN,
firstPartyDomain,
});
this._request.mozBackgroundRequest = true; // suppress dialogs and fail silently

View File

@ -119,10 +119,19 @@ SuggestAutoComplete.prototype = {
var formHistorySearchParam = searchParam.split("|")[0];
// Receive the information about the privacy mode of the window to which
// this search box belongs. The front-end's search.xml bindings passes this
// information in the searchParam parameter. The alternative would have
// been to modify nsIAutoCompleteSearch to add an argument to startSearch
// and patch all of autocomplete to be aware of this, but the searchParam
// argument is already an opaque argument, so this solution is hopefully
// less hackish (although still gross.)
var privacyMode = (searchParam.split("|")[1] == "private");
// Start search immediately if possible, otherwise once the search
// service is initialized
if (Services.search.isInitialized) {
this._triggerSearch(searchString, formHistorySearchParam, listener);
this._triggerSearch(searchString, formHistorySearchParam, listener, privacyMode);
return;
}
@ -131,16 +140,17 @@ SuggestAutoComplete.prototype = {
Cu.reportError("Could not initialize search service, bailing out: " + aResult);
return;
}
this._triggerSearch(searchString, formHistorySearchParam, listener);
this._triggerSearch(searchString, formHistorySearchParam, listener, privacyMode);
});
},
/**
* Actual implementation of search.
*/
_triggerSearch(searchString, searchParam, listener) {
_triggerSearch(searchString, searchParam, listener, privacyMode) {
this._listener = listener;
this._suggestionController.fetch(searchString,
privacyMode,
Services.search.defaultEngine);
},

View File

@ -96,7 +96,7 @@ add_task(async function simple_no_result_callback() {
resolve();
});
controller.fetch("no remote", getEngine);
controller.fetch("no remote", false, getEngine);
});
});
@ -110,7 +110,7 @@ add_task(async function simple_no_result_callback_and_promise() {
deferred.resolve();
});
let result = await controller.fetch("no results", getEngine);
let result = await controller.fetch("no results", false, getEngine);
Assert.equal(result.term, "no results");
Assert.equal(result.local.length, 0);
Assert.equal(result.remote.length, 0);
@ -120,7 +120,7 @@ add_task(async function simple_no_result_callback_and_promise() {
add_task(async function simple_no_result_promise() {
let controller = new SearchSuggestionController();
let result = await controller.fetch("no remote", getEngine);
let result = await controller.fetch("no remote", false, getEngine);
Assert.equal(result.term, "no remote");
Assert.equal(result.local.length, 0);
Assert.equal(result.remote.length, 0);
@ -128,7 +128,7 @@ add_task(async function simple_no_result_promise() {
add_task(async function simple_remote_no_local_result() {
let controller = new SearchSuggestionController();
let result = await controller.fetch("mo", getEngine);
let result = await controller.fetch("mo", false, getEngine);
Assert.equal(result.term, "mo");
Assert.equal(result.local.length, 0);
Assert.equal(result.remote.length, 3);
@ -139,7 +139,7 @@ add_task(async function simple_remote_no_local_result() {
add_task(async function simple_remote_no_local_result_alternative_type() {
let controller = new SearchSuggestionController();
let result = await controller.fetch("mo", alternateJSONEngine);
let result = await controller.fetch("mo", false, alternateJSONEngine);
Assert.equal(result.term, "mo");
Assert.equal(result.local.length, 0);
Assert.equal(result.remote.length, 3);
@ -150,7 +150,7 @@ add_task(async function simple_remote_no_local_result_alternative_type() {
add_task(async function remote_term_case_mismatch() {
let controller = new SearchSuggestionController();
let result = await controller.fetch("Query Case Mismatch", getEngine);
let result = await controller.fetch("Query Case Mismatch", false, getEngine);
Assert.equal(result.term, "Query Case Mismatch");
Assert.equal(result.remote.length, 1);
Assert.equal(result.remote[0], "Query Case Mismatch");
@ -160,7 +160,7 @@ add_task(async function simple_local_no_remote_result() {
await updateSearchHistory("bump", "no remote entries");
let controller = new SearchSuggestionController();
let result = await controller.fetch("no remote", getEngine);
let result = await controller.fetch("no remote", false, getEngine);
Assert.equal(result.term, "no remote");
Assert.equal(result.local.length, 1);
Assert.equal(result.local[0], "no remote entries");
@ -173,7 +173,7 @@ add_task(async function simple_non_ascii() {
await updateSearchHistory("bump", "I ❤️ XUL");
let controller = new SearchSuggestionController();
let result = await controller.fetch("I ❤️", getEngine);
let result = await controller.fetch("I ❤️", false, getEngine);
Assert.equal(result.term, "I ❤️");
Assert.equal(result.local.length, 1);
Assert.equal(result.local[0], "I ❤️ XUL");
@ -185,7 +185,7 @@ add_task(async function both_local_remote_result_dedupe() {
await updateSearchHistory("bump", "Mozilla");
let controller = new SearchSuggestionController();
let result = await controller.fetch("mo", getEngine);
let result = await controller.fetch("mo", false, getEngine);
Assert.equal(result.term, "mo");
Assert.equal(result.local.length, 1);
Assert.equal(result.local[0], "Mozilla");
@ -196,7 +196,7 @@ add_task(async function both_local_remote_result_dedupe() {
add_task(async function POST_both_local_remote_result_dedupe() {
let controller = new SearchSuggestionController();
let result = await controller.fetch("mo", postEngine);
let result = await controller.fetch("mo", false, postEngine);
Assert.equal(result.term, "mo");
Assert.equal(result.local.length, 1);
Assert.equal(result.local[0], "Mozilla");
@ -209,7 +209,7 @@ add_task(async function both_local_remote_result_dedupe2() {
await updateSearchHistory("bump", "mom");
let controller = new SearchSuggestionController();
let result = await controller.fetch("mo", getEngine);
let result = await controller.fetch("mo", false, getEngine);
Assert.equal(result.term, "mo");
Assert.equal(result.local.length, 2);
Assert.equal(result.local[0], "mom");
@ -223,7 +223,7 @@ add_task(async function both_local_remote_result_dedupe3() {
await updateSearchHistory("bump", "modern");
let controller = new SearchSuggestionController();
let result = await controller.fetch("mo", getEngine);
let result = await controller.fetch("mo", false, getEngine);
Assert.equal(result.term, "mo");
Assert.equal(result.local.length, 3);
Assert.equal(result.local[0], "modern");
@ -238,10 +238,10 @@ add_task(async function fetch_twice_in_a_row() {
await updateSearchHistory("bump", "delayed local");
let controller = new SearchSuggestionController();
let resultPromise1 = controller.fetch("delay", getEngine);
let resultPromise1 = controller.fetch("delay", false, getEngine);
// A second fetch while the server is still waiting to return results leads to an abort.
let resultPromise2 = controller.fetch("delayed ", getEngine);
let resultPromise2 = controller.fetch("delayed ", false, getEngine);
await resultPromise1.then((results) => Assert.equal(null, results));
let result = await resultPromise2;
@ -259,7 +259,7 @@ add_task(async function fetch_twice_subset_reuse_formHistoryResult() {
await updateSearchHistory("bump", "delayed local");
let controller = new SearchSuggestionController();
let result = await controller.fetch("delay", getEngine);
let result = await controller.fetch("delay", false, getEngine);
Assert.equal(result.term, "delay");
Assert.equal(result.local.length, 2);
Assert.equal(result.local[0], "delay local");
@ -270,7 +270,7 @@ add_task(async function fetch_twice_subset_reuse_formHistoryResult() {
// Remove the entry from the DB but it should remain in the cached formHistoryResult.
await updateSearchHistory("remove", "delayed local");
let result2 = await controller.fetch("delayed ", getEngine);
let result2 = await controller.fetch("delayed ", false, getEngine);
Assert.equal(result2.term, "delayed ");
Assert.equal(result2.local.length, 1);
Assert.equal(result2.local[0], "delayed local");
@ -287,7 +287,7 @@ add_task(async function both_identical_with_more_than_max_results() {
let controller = new SearchSuggestionController();
controller.maxLocalResults = 7;
controller.maxRemoteResults = 10;
let result = await controller.fetch("letter ", getEngine);
let result = await controller.fetch("letter ", false, getEngine);
Assert.equal(result.term, "letter ");
Assert.equal(result.local.length, 7);
for (let i = 0; i < controller.maxLocalResults; i++) {
@ -304,7 +304,7 @@ add_task(async function noremote_maxLocal() {
let controller = new SearchSuggestionController();
controller.maxLocalResults = 2; // (should be ignored because no remote results)
controller.maxRemoteResults = 0;
let result = await controller.fetch("letter ", getEngine);
let result = await controller.fetch("letter ", false, getEngine);
Assert.equal(result.term, "letter ");
Assert.equal(result.local.length, 26);
for (let i = 0; i < result.local.length; i++) {
@ -317,7 +317,7 @@ add_task(async function someremote_maxLocal() {
let controller = new SearchSuggestionController();
controller.maxLocalResults = 2;
controller.maxRemoteResults = 4;
let result = await controller.fetch("letter ", getEngine);
let result = await controller.fetch("letter ", false, getEngine);
Assert.equal(result.term, "letter ");
Assert.equal(result.local.length, 2);
for (let i = 0; i < result.local.length; i++) {
@ -334,7 +334,7 @@ add_task(async function one_of_each() {
let controller = new SearchSuggestionController();
controller.maxLocalResults = 1;
controller.maxRemoteResults = 2;
let result = await controller.fetch("letter ", getEngine);
let result = await controller.fetch("letter ", false, getEngine);
Assert.equal(result.term, "letter ");
Assert.equal(result.local.length, 1);
Assert.equal(result.local[0], "letter A");
@ -347,7 +347,7 @@ add_task(async function local_result_returned_remote_result_disabled() {
let controller = new SearchSuggestionController();
controller.maxLocalResults = 1;
controller.maxRemoteResults = 1;
let result = await controller.fetch("letter ", getEngine);
let result = await controller.fetch("letter ", false, getEngine);
Assert.equal(result.term, "letter ");
Assert.equal(result.local.length, 26);
for (let i = 0; i < 26; i++) {
@ -362,7 +362,7 @@ add_task(async function local_result_returned_remote_result_disabled_after_creat
controller.maxLocalResults = 1;
controller.maxRemoteResults = 1;
Services.prefs.setBoolPref("browser.search.suggest.enabled", false);
let result = await controller.fetch("letter ", getEngine);
let result = await controller.fetch("letter ", false, getEngine);
Assert.equal(result.term, "letter ");
Assert.equal(result.local.length, 26);
for (let i = 0; i < 26; i++) {
@ -378,7 +378,7 @@ add_task(async function one_of_each_disabled_before_creation_enabled_after_creat
controller.maxLocalResults = 1;
controller.maxRemoteResults = 2;
Services.prefs.setBoolPref("browser.search.suggest.enabled", true);
let result = await controller.fetch("letter ", getEngine);
let result = await controller.fetch("letter ", false, getEngine);
Assert.equal(result.term, "letter ");
Assert.equal(result.local.length, 1);
Assert.equal(result.local[0], "letter A");
@ -394,7 +394,7 @@ add_task(async function one_local_zero_remote() {
let controller = new SearchSuggestionController();
controller.maxLocalResults = 1;
controller.maxRemoteResults = 0;
let result = await controller.fetch("letter ", getEngine);
let result = await controller.fetch("letter ", false, getEngine);
Assert.equal(result.term, "letter ");
Assert.equal(result.local.length, 26);
for (let i = 0; i < 26; i++) {
@ -407,7 +407,7 @@ add_task(async function zero_local_one_remote() {
let controller = new SearchSuggestionController();
controller.maxLocalResults = 0;
controller.maxRemoteResults = 1;
let result = await controller.fetch("letter ", getEngine);
let result = await controller.fetch("letter ", false, getEngine);
Assert.equal(result.term, "letter ");
Assert.equal(result.local.length, 0);
Assert.equal(result.remote.length, 1);
@ -418,7 +418,7 @@ add_task(async function stop_search() {
let controller = new SearchSuggestionController((result) => {
do_throw("The callback shouldn't be called after stop()");
});
let resultPromise = controller.fetch("mo", getEngine);
let resultPromise = controller.fetch("mo", false, getEngine);
controller.stop();
await resultPromise.then((result) => {
Assert.equal(null, result);
@ -428,7 +428,7 @@ add_task(async function stop_search() {
add_task(async function empty_searchTerm() {
// Empty searches don't go to the server but still get form history.
let controller = new SearchSuggestionController();
let result = await controller.fetch("", getEngine);
let result = await controller.fetch("", false, getEngine);
Assert.equal(result.term, "");
Assert.ok(result.local.length > 0);
Assert.equal(result.remote.length, 0);
@ -450,7 +450,7 @@ add_task(async function slow_timeout() {
check_result(result);
d.resolve();
}, 2000);
let result = await controller.fetch("slow ", getEngine);
let result = await controller.fetch("slow ", false, getEngine);
check_result(result);
await d.promise;
});
@ -458,7 +458,7 @@ add_task(async function slow_timeout() {
add_task(async function slow_stop() {
let d = PromiseUtils.defer();
let controller = new SearchSuggestionController();
let resultPromise = controller.fetch("slow ", getEngine);
let resultPromise = controller.fetch("slow ", false, getEngine);
setTimeout(function check_timeout() {
// The HTTP response takes 10 seconds but we timeout in less than a second so just use 0.
controller.stop();
@ -478,7 +478,7 @@ add_task(async function remote_term_mismatch() {
await updateSearchHistory("bump", "Query Mismatch Entry");
let controller = new SearchSuggestionController();
let result = await controller.fetch("Query Mismatch", getEngine);
let result = await controller.fetch("Query Mismatch", false, getEngine);
Assert.equal(result.term, "Query Mismatch");
Assert.equal(result.local.length, 1);
Assert.equal(result.local[0], "Query Mismatch Entry");
@ -489,7 +489,7 @@ add_task(async function http_404() {
await updateSearchHistory("bump", "HTTP 404 Entry");
let controller = new SearchSuggestionController();
let result = await controller.fetch("HTTP 404", getEngine);
let result = await controller.fetch("HTTP 404", false, getEngine);
Assert.equal(result.term, "HTTP 404");
Assert.equal(result.local.length, 1);
Assert.equal(result.local[0], "HTTP 404 Entry");
@ -500,7 +500,7 @@ add_task(async function http_500() {
await updateSearchHistory("bump", "HTTP 500 Entry");
let controller = new SearchSuggestionController();
let result = await controller.fetch("HTTP 500", getEngine);
let result = await controller.fetch("HTTP 500", false, getEngine);
Assert.equal(result.term, "HTTP 500");
Assert.equal(result.local.length, 1);
Assert.equal(result.local[0], "HTTP 500 Entry");
@ -511,7 +511,7 @@ add_task(async function unresolvable_server() {
await updateSearchHistory("bump", "Unresolvable Server Entry");
let controller = new SearchSuggestionController();
let result = await controller.fetch("Unresolvable Server", unresolvableEngine);
let result = await controller.fetch("Unresolvable Server", false, unresolvableEngine);
Assert.equal(result.term, "Unresolvable Server");
Assert.equal(result.local.length, 1);
Assert.equal(result.local[0], "Unresolvable Server Entry");
@ -521,17 +521,24 @@ add_task(async function unresolvable_server() {
// Exception handling
add_task(async function missing_pb() {
Assert.throws(() => {
let controller = new SearchSuggestionController();
controller.fetch("No privacy");
}, /priva/i);
});
add_task(async function missing_engine() {
Assert.throws(() => {
let controller = new SearchSuggestionController();
controller.fetch("No engine");
controller.fetch("No engine", false);
}, /engine/i);
});
add_task(async function invalid_engine() {
Assert.throws(() => {
let controller = new SearchSuggestionController();
controller.fetch("invalid engine", {});
controller.fetch("invalid engine", false, {});
}, /engine/i);
});
@ -540,7 +547,7 @@ add_task(async function no_results_requested() {
let controller = new SearchSuggestionController();
controller.maxLocalResults = 0;
controller.maxRemoteResults = 0;
controller.fetch("No results requested", getEngine);
controller.fetch("No results requested", false, getEngine);
}, /result/i);
});
@ -548,18 +555,18 @@ add_task(async function minus_one_results_requested() {
Assert.throws(() => {
let controller = new SearchSuggestionController();
controller.maxLocalResults = -1;
controller.fetch("-1 results requested", getEngine);
controller.fetch("-1 results requested", false, getEngine);
}, /result/i);
});
add_task(async function test_userContextId() {
let controller = new SearchSuggestionController();
controller._fetchRemote = function(searchTerm, engine, userContextId, privateMode) {
controller._fetchRemote = function(searchTerm, engine, privateMode, userContextId) {
Assert.equal(userContextId, 1);
return PromiseUtils.defer();
};
controller.fetch("test", getEngine, 1);
controller.fetch("test", false, getEngine, 1);
});
// Helpers

View File

@ -1,17 +1,14 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/* eslint-disable mozilla/no-arbitrary-setTimeout */
/**
* Testing search suggestions from SearchSuggestionController.jsm.
* Test that search suggestions from SearchSuggestionController.jsm don't store
* cookies.
*/
"use strict";
ChromeUtils.import("resource://gre/modules/FormHistory.jsm");
ChromeUtils.import("resource://gre/modules/SearchSuggestionController.jsm");
ChromeUtils.import("resource://gre/modules/Timer.jsm");
ChromeUtils.import("resource://gre/modules/PromiseUtils.jsm");
// We must make sure the FormHistoryStartup component is
// initialized in order for it to respond to FormHistory
@ -21,71 +18,104 @@ var formHistoryStartup = Cc["@mozilla.org/satchel/form-history-startup;1"].
formHistoryStartup.observe(null, "profile-after-change", null);
var httpServer = new HttpServer();
var getEngine;
function countCacheEntries() {
info("Enumerating cache entries");
return new Promise(resolve => {
let storage = Services.cache2.diskCacheStorage(Services.loadContextInfo.default, false);
storage.asyncVisitStorage({
onCacheStorageInfo(num, consumption) {
this._num = num;
},
onCacheEntryInfo(uri) {
info("Found cache entry: " + uri.asciiSpec);
},
onCacheEntryVisitCompleted() {
resolve(this._num || 0);
},
}, true /* Do walk entries */);
});
}
function countCookieEntries() {
info("Enumerating cookies");
let enumerator = Services.cookies.enumerator;
let cookieCount = 0;
for (let cookie of enumerator) {
info("Cookie:" + cookie.rawHost + " " + JSON.stringify(cookie.originAttributes));
cookieCount++;
break;
}
return cookieCount;
}
add_task(async function setup() {
Services.prefs.setBoolPref("browser.search.suggest.enabled", true);
let server = useHttpServer();
server.registerContentType("sjs", "sjs");
registerCleanupFunction(async function cleanup() {
// Clean up all the data.
await new Promise(resolve =>
Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, resolve));
Services.prefs.clearUserPref("browser.search.suggest.enabled");
});
[getEngine] = await addTestEngines([
let server = useHttpServer();
server.registerContentType("sjs", "sjs");
let unicodeName = ["\u30a8", "\u30c9"].join("");
let engines = await addTestEngines([
{
name: "GET suggestion engine",
name: unicodeName,
xmlFileName: "engineMaker.sjs?" + JSON.stringify({
baseURL: gDataUrl,
name: "GET suggestion engine",
name: unicodeName,
method: "GET",
}),
},
{
name: "engine two",
xmlFileName: "engineMaker.sjs?" + JSON.stringify({
baseURL: gDataUrl,
name: "engine two",
method: "GET",
}),
},
]);
// Clean up all the data.
await new Promise(resolve =>
Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, resolve));
Assert.equal(await countCacheEntries(), 0, "The cache should be empty");
Assert.equal(await countCookieEntries(), 0, "Should not find any cookie");
await test_engine(engines, true);
await test_engine(engines, false);
});
add_task(async function test_private() {
await new Promise(resolve => {
let controller = new SearchSuggestionController((result) => {
Assert.equal(result.term, "cookie");
Assert.equal(result.local.length, 0);
Assert.equal(result.remote.length, 0);
resolve();
});
controller.fetch("cookie", getEngine);
});
info("Enumerating cookies");
let enumerator = Services.cookies.enumerator;
let cookies = [];
for (let cookie of enumerator) {
info("Cookie:" + cookie.rawHost + " " + JSON.stringify(cookie.originAttributes));
cookies.push(cookie);
break;
}
Assert.equal(cookies.length, 0, "Should not find any cookie");
});
add_task(async function test_nonprivate() {
async function test_engine(engines, privateMode) {
let controller;
await new Promise(resolve => {
controller = new SearchSuggestionController((result) => {
Assert.equal(result.term, "cookie");
controller = new SearchSuggestionController((result) => {
Assert.equal(result.local.length, 0);
Assert.equal(result.remote.length, 0);
resolve();
if (result.term == "cookie") {
resolve();
}
});
controller.fetch("cookie", getEngine, 0, false);
controller.fetch("test", privateMode, engines[0]);
controller.fetch("cookie", privateMode, engines[1]);
});
info("Enumerating cookies");
let enumerator = Services.cookies.enumerator;
let cookies = [];
for (let cookie of enumerator) {
info("Cookie:" + cookie.rawHost + " " + JSON.stringify(cookie.originAttributes));
cookies.push(cookie);
break;
}
Assert.equal(cookies.length, 1, "Should find one cookie");
Assert.equal(cookies[0].originAttributes.firstPartyDomain,
controller.FIRST_PARTY_DOMAIN, "Check firstPartyDomain");
});
Assert.equal(await countCacheEntries(), 0, "The cache should be empty");
Assert.equal(await countCookieEntries(), 0, "Should not find any cookie");
let firstPartyDomain1 = controller.firstPartyDomains.get(engines[0].name);
Assert.ok(/^[\.a-z0-9-]+\.search\.suggestions\.mozilla/.test(firstPartyDomain1),
"Check firstPartyDomain1");
let firstPartyDomain2 = controller.firstPartyDomains.get(engines[1].name);
Assert.ok(/^[\.a-z0-9-]+\.search\.suggestions\.mozilla/.test(firstPartyDomain2),
"Check firstPartyDomain2");
Assert.notEqual(firstPartyDomain1, firstPartyDomain2,
"Check firstPartyDomain id unique per engine");
}

View File

@ -2276,7 +2276,7 @@ update:
description: >
If the binary transparency information for an update does not verify
successfully, this probe will contain an error code from
toolkit/mozapps/update/common/errors.h indicating why.
toolkit/mozapps/update/common/updatererrors.h indicating why.
expires: "73"
kind: uint
keyed: true

View File

@ -1420,17 +1420,13 @@ nsresult KeyedHistogram::GetSnapshot(const StaticMutexAutoLock& aLock,
* @param {aIncludeGPU} whether or not to include data for the GPU.
* @param {aOutSnapshot} the container in which the snapshot data will be
* stored.
* @param {aSkipEmpty} whether or not to skip empty keyed histograms from the
* snapshot. Can't always assume "true" for consistency with the other
* callers.
* @return {nsresult} NS_OK if the snapshot was successfully taken or
* NS_ERROR_OUT_OF_MEMORY if it failed to allocate memory.
*/
nsresult internal_GetKeyedHistogramsSnapshot(
const StaticMutexAutoLock& aLock, const nsACString& aStore,
unsigned int aDataset, bool aClearSubsession, bool aIncludeGPU,
bool aFilterTest, KeyedHistogramProcessSnapshotsArray& aOutSnapshot,
bool aSkipEmpty = false) {
bool aFilterTest, KeyedHistogramProcessSnapshotsArray& aOutSnapshot) {
if (!aOutSnapshot.resize(static_cast<uint32_t>(ProcessID::Count))) {
return NS_ERROR_OUT_OF_MEMORY;
}
@ -1458,8 +1454,7 @@ nsresult internal_GetKeyedHistogramsSnapshot(
KeyedHistogram* keyed =
internal_GetKeyedHistogramById(id, ProcessID(process),
/* instantiate = */ false);
if (!keyed || (aSkipEmpty && keyed->IsEmpty(aStore)) ||
keyed->IsExpired()) {
if (!keyed || keyed->IsEmpty(aStore) || keyed->IsExpired()) {
continue;
}
@ -2819,7 +2814,7 @@ nsresult TelemetryHistogram::GetKeyedHistogramSnapshots(
StaticMutexAutoLock locker(gTelemetryHistogramMutex);
nsresult rv = internal_GetKeyedHistogramsSnapshot(
locker, aStore, aDataset, aClearSubsession, includeGPUProcess,
aFilterTest, processHistArray, true /* skipEmpty */);
aFilterTest, processHistArray);
if (NS_FAILED(rv)) {
return rv;
}
@ -3121,8 +3116,7 @@ nsresult TelemetryHistogram::SerializeKeyedHistograms(
locker, NS_LITERAL_CSTRING("main"),
nsITelemetry::DATASET_RELEASE_CHANNEL_OPTIN,
false /* aClearSubsession */, includeGPUProcess,
false /* aFilterTest */, processHistArray,
true /* aSkipEmpty */))) {
false /* aFilterTest */, processHistArray))) {
return NS_ERROR_FAILURE;
}
}

View File

@ -101,6 +101,9 @@ class TestSearchCounts(TelemetryTestCase):
self.assertEqual(ping1_info["profileSubsessionCounter"], 1)
scalars1 = ping1["payload"]["processes"]["parent"]["scalars"]
self.assertNotIn(
"browser.engagement.window_open_event_count", scalars1
)
self.assertEqual(
scalars1["browser.engagement.tab_open_event_count"], 1
)
@ -161,6 +164,9 @@ class TestSearchCounts(TelemetryTestCase):
self.assertEqual(ping2_info["profileSubsessionCounter"], 2)
scalars2 = ping2["payload"]["processes"]["parent"]["scalars"]
self.assertNotIn(
"browser.engagement.window_open_event_count", scalars2
)
self.assertNotIn("browser.engagement.tab_open_event_count", scalars2)
keyed_histograms2 = ping2["payload"]["keyedHistograms"]
@ -212,6 +218,9 @@ class TestSearchCounts(TelemetryTestCase):
self.assertEqual(ping3_info["profileSubsessionCounter"], 3)
scalars3 = ping3["payload"]["processes"]["parent"]["scalars"]
self.assertNotIn(
"browser.engagement.window_open_event_count", scalars3
)
self.assertNotIn("browser.engagement.tab_open_event_count", scalars3)
keyed_histograms3 = ping3["payload"]["keyedHistograms"]

View File

@ -2897,8 +2897,8 @@ SOFTWARE.
<h1><a id="bspatch"></a>bspatch License</h1>
<p>This license applies to the files
<code>toolkit/mozapps/update/updater/bspatch.cpp</code> and
<code>toolkit/mozapps/update/updater/bspatch.h</code>.
<code>toolkit/mozapps/update/updater/bspatch/bspatch.cpp</code> and
<code>toolkit/mozapps/update/updater/bspatch/bspatch.h</code>.
</p>
<pre>

View File

@ -9,6 +9,7 @@ EXPORTS += [
'readstrings.h',
'updatecommon.h',
'updatedefines.h',
'updatererrors.h',
]
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':

View File

@ -8,7 +8,7 @@
#include <string.h>
#include <stdio.h>
#include "readstrings.h"
#include "errors.h"
#include "updatererrors.h"
#ifdef XP_WIN
#define NS_tfopen _wfopen

View File

@ -4,8 +4,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/. */
#ifndef Errors_h__
#define Errors_h__
#ifndef UPDATEERRORS_H
#define UPDATEERRORS_H
#define OK 0
@ -107,4 +107,4 @@
#define FALLBACKKEY_SERVICE_NO_STOP_ERROR 103
#define FALLBACKKEY_LAUNCH_ERROR 104
#endif // Errors_h__
#endif // UPDATEERRORS_H

View File

@ -53,7 +53,7 @@ interface nsIUpdatePatch : nsISupports
/**
* A numeric error code that conveys additional information about the state of
* a failed update. If the update is not in the "failed" state the value is
* zero. The possible values are located in common/errors.h and values between
* zero. The possible values are located in common/updatererrors.h and values between
* 80 and 99 are in nsUpdateService.js.
*/
attribute long errorCode;
@ -194,7 +194,7 @@ interface nsIUpdate : nsISupports
/**
* A numeric error code that conveys additional information about the state of
* a failed update. If the update is not in the "failed" state the value is
* zero. The possible values are located in common/errors.h and values between
* zero. The possible values are located in common/updatererrors.h and values between
* 80 and 99 are in nsUpdateService.js.
*/
attribute long errorCode;

View File

@ -79,7 +79,7 @@ const STATE_SUCCEEDED = "succeeded";
const STATE_DOWNLOAD_FAILED = "download-failed";
const STATE_FAILED = "failed";
// The values below used by this code are from common/errors.h
// The values below used by this code are from common/updatererrors.h
const WRITE_ERROR = 7;
const ELEVATION_CANCELED = 9;
const SERVICE_UPDATER_COULD_NOT_BE_STARTED = 24;
@ -141,7 +141,7 @@ const SERVICE_ERRORS = [SERVICE_UPDATER_COULD_NOT_BE_STARTED,
SERVICE_COULD_NOT_IMPERSONATE];
// Error codes 80 through 99 are reserved for nsUpdateService.js and are not
// defined in common/errors.h
// defined in common/updatererrors.h
const ERR_OLDER_VERSION_OR_SAME_BUILD = 90;
const ERR_UPDATE_STATE_NONE = 91;
const ERR_CHANNEL_CHANGE = 92;

View File

@ -26,7 +26,7 @@
#include "updater/resource.h"
#include "updater/progressui.h"
#include "common/readstrings.h"
#include "common/errors.h"
#include "common/updatererrors.h"
#include "common/updatedefines.h"
#include "mozilla/ArrayUtils.h"

View File

@ -46,7 +46,7 @@ const INVALID_CALLBACK_PATH_ERROR = 77;
const INVALID_CALLBACK_DIR_ERROR = 78;
// Error codes 80 through 99 are reserved for nsUpdateService.js and are not
// defined in common/errors.h
// defined in common/updatererrors.h
const ERR_OLDER_VERSION_OR_SAME_BUILD = 90;
const ERR_UPDATE_STATE_NONE = 91;
const ERR_CHANNEL_CHANGE = 92;

View File

@ -12,7 +12,7 @@
#include <windows.h>
#endif
#include "archivereader.h"
#include "errors.h"
#include "updatererrors.h"
#ifdef XP_WIN
#include "nsAlgorithm.h" // Needed by nsVersionComparator.cpp
#include "updatehelper.h"

View File

@ -0,0 +1,23 @@
Copyright 2003,2004 Colin Percival
All rights reserved
Redistribution and use in source and binary forms, with or without
modification, are permitted providing that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

View File

@ -30,7 +30,7 @@
*/
#include "bspatch.h"
#include "errors.h"
#include "updatererrors.h"
#include <sys/stat.h>
#include <stdlib.h>

View File

@ -0,0 +1,22 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
if CONFIG['OS_ARCH'] == 'WINNT':
USE_STATIC_LIBS = True
EXPORTS += [
'bspatch.h',
]
SOURCES += [
'bspatch.cpp',
]
USE_LIBS += [
'updatecommon',
]
Library('bspatch')

View File

@ -0,0 +1,30 @@
# Version of this schema
schema: 1
bugzilla:
# Bugzilla product and component for this directory and subdirectories
product: "Toolkit"
component: "Application Update"
# The source from this directory was adapted from Colin Percival's bspatch
# tool in mid 2005 and was obtained from bsdiff version 4.2. Edits were
# later added by the Chromium dev team and were copied to here as well
# Document the source of externally hosted code
origin:
name: "bsdiff/bspatch"
description: "Builds and applies patches to binary files"
# Full URL for the package's homepage/etc
# Usually different from repository url
url: "https://www.daemonology.net/bsdiff/bsdiff-4.2.tar.gz"
# Human-readable identifier for this version/release
# Generally "version NNN", "tag SSS", "bookmark SSS"
release: "version 4.2"
# The package's license, where possible using the mnemonic from
# https://spdx.org/licenses/
# Multiple licenses can be specified (as a YAML list)
# A "LICENSE" file must exist containing the full license text
license: "BSD-2-Clause"

View File

@ -10,7 +10,7 @@
#include "mozilla/Sprintf.h"
#include "progressui.h"
#include "readstrings.h"
#include "errors.h"
#include "updatererrors.h"
#define TIMER_INTERVAL 100

View File

@ -10,7 +10,7 @@
#include "mozilla/Sprintf.h"
#include "progressui.h"
#include "readstrings.h"
#include "errors.h"
#include "updatererrors.h"
#define TIMER_INTERVAL 0.2

View File

@ -13,7 +13,7 @@
#include "resource.h"
#include "progressui.h"
#include "readstrings.h"
#include "errors.h"
#include "updatererrors.h"
#define TIMER_ID 1
#define TIMER_INTERVAL 100

View File

@ -6,7 +6,6 @@
srcs = [
'archivereader.cpp',
'bspatch.cpp',
'updater.cpp',
]
@ -48,6 +47,7 @@ elif CONFIG['OS_ARCH'] == 'Linux' and CONFIG['MOZ_VERIFY_MAR_SIGNATURE']:
OS_LIBS += CONFIG['NSPR_LIBS']
USE_LIBS += [
'bspatch',
'mar',
'updatecommon',
'xz-embedded',

View File

@ -33,7 +33,7 @@
#include "progressui.h"
#include "archivereader.h"
#include "readstrings.h"
#include "errors.h"
#include "updatererrors.h"
#include <stdio.h>
#include <string.h>

View File

@ -64,7 +64,10 @@ if CONFIG['MOZ_AUTH_EXTENSION']:
DIRS += ['/extensions/auth']
if CONFIG['MOZ_UPDATER'] and CONFIG['OS_TARGET'] != 'Android':
DIRS += ['/other-licenses/bsdiff']
DIRS += [
'/toolkit/mozapps/update/updater/bspatch',
'/other-licenses/bsdiff',
]
# Gecko/Core components.

View File

@ -31,6 +31,9 @@ static void moz_container_init(MozContainer *container);
/* widget class methods */
static void moz_container_map(GtkWidget *widget);
#if defined(MOZ_WAYLAND)
static gboolean moz_container_map_wayland(GtkWidget *widget, GdkEventAny *event);
#endif
static void moz_container_unmap(GtkWidget *widget);
static void moz_container_realize(GtkWidget *widget);
static void moz_container_size_allocate(GtkWidget *widget,
@ -129,6 +132,11 @@ void moz_container_class_init(MozContainerClass *klass) {
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
widget_class->map = moz_container_map;
#if defined(MOZ_WAYLAND)
if (!GDK_IS_X11_DISPLAY(gdk_display_get_default())) {
widget_class->map_event = moz_container_map_wayland;
}
#endif
widget_class->unmap = moz_container_unmap;
widget_class->realize = moz_container_realize;
widget_class->size_allocate = moz_container_size_allocate;
@ -173,15 +181,23 @@ static void frame_callback_handler(void *data, struct wl_callback *callback,
static const struct wl_callback_listener frame_listener = {
frame_callback_handler};
static void moz_container_map_wayland(MozContainer *container) {
container->surface_needs_clear = true;
container->ready_to_draw = false;
static gboolean moz_container_map_wayland(GtkWidget *widget, GdkEventAny *event) {
MozContainer* container = MOZ_CONTAINER(widget);
if (container->ready_to_draw || container->frame_callback_handler) {
return FALSE;
}
wl_surface *gtk_container_surface =
moz_container_get_gtk_container_surface(container);
container->frame_callback_handler = wl_surface_frame(gtk_container_surface);
wl_callback_add_listener(container->frame_callback_handler, &frame_listener,
container);
if (gtk_container_surface) {
container->frame_callback_handler = wl_surface_frame(gtk_container_surface);
wl_callback_add_listener(container->frame_callback_handler, &frame_listener,
container);
}
return FALSE;
}
static void moz_container_unmap_wayland(MozContainer *container) {
@ -190,6 +206,7 @@ static void moz_container_unmap_wayland(MozContainer *container) {
g_clear_pointer(&container->surface, wl_surface_destroy);
g_clear_pointer(&container->frame_callback_handler, wl_callback_destroy);
container->surface_needs_clear = true;
container->ready_to_draw = false;
}
@ -230,7 +247,7 @@ void moz_container_map(GtkWidget *widget) {
gdk_window_show(gtk_widget_get_window(widget));
#if defined(MOZ_WAYLAND)
if (!GDK_IS_X11_DISPLAY(gdk_display_get_default())) {
moz_container_map_wayland(MOZ_CONTAINER(widget));
moz_container_map_wayland(widget, nullptr);
}
#endif
}

View File

@ -22,7 +22,7 @@ namespace mozilla {
* via a module loader.
*/
struct Module {
static const unsigned int kVersion = 65;
static const unsigned int kVersion = 66;
struct CIDEntry;

View File

@ -524,7 +524,6 @@ STATIC_ATOMS = [
Atom("infinity", "infinity"),
Atom("inherits", "inherits"),
Atom("inheritOverflow", "inherit-overflow"),
Atom("inheritScrollBehavior", "inherit-scroll-behavior"),
Atom("inheritstyle", "inheritstyle"),
Atom("initial_scale", "initial-scale"),
Atom("input", "input"),