зеркало из https://github.com/mozilla/gecko-dev.git
Merge autoland to mozilla-central. a=merge
This commit is contained in:
Коммит
bc1f3670dc
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();");
|
||||
|
|
|
@ -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);
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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 = {};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
/***/ }),
|
||||
|
|
|
@ -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}".`);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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/
|
||||
|
|
|
@ -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/**"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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 });
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
DIRS += [
|
||||
'connect',
|
||||
'debugtarget',
|
||||
'shared',
|
||||
'sidebar',
|
||||
]
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
|
@ -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',
|
||||
)
|
|
@ -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",
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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);
|
||||
});
|
|
@ -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]);
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
this is not valid json
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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;
|
||||
});
|
|
@ -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>
|
||||
|
|
До Ширина: | Высота: | Размер: 669 B После Ширина: | Высота: | Размер: 485 B |
|
@ -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,
|
||||
});
|
||||
},
|
||||
|
||||
|
|
|
@ -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;
|
||||
},
|
||||
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
},
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"]
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -9,6 +9,7 @@ EXPORTS += [
|
|||
'readstrings.h',
|
||||
'updatecommon.h',
|
||||
'updatedefines.h',
|
||||
'updatererrors.h',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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.
|
|
@ -30,7 +30,7 @@
|
|||
*/
|
||||
|
||||
#include "bspatch.h"
|
||||
#include "errors.h"
|
||||
#include "updatererrors.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <stdlib.h>
|
|
@ -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')
|
|
@ -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"
|
|
@ -10,7 +10,7 @@
|
|||
#include "mozilla/Sprintf.h"
|
||||
#include "progressui.h"
|
||||
#include "readstrings.h"
|
||||
#include "errors.h"
|
||||
#include "updatererrors.h"
|
||||
|
||||
#define TIMER_INTERVAL 100
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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"),
|
||||
|
|
Загрузка…
Ссылка в новой задаче