From af1538b456db0c03061a238a007e900c3f07fae0 Mon Sep 17 00:00:00 2001 From: Luca Greco Date: Wed, 11 Oct 2017 15:06:27 +0200 Subject: [PATCH 01/41] Bug 1403130 - Support result as value grip on WebExtension InspectorWindow actor eval method. r=ochameau MozReview-Commit-ID: Efxhsm4bApu --HG-- extra : rebase_source : 3c5b4ff02858b03c878a24089354914f557d4e9a --- .../actors/webextension-inspected-window.js | 24 ++++++++++++ .../browser_webextension_inspected_window.js | 37 +++++++++++++++++++ .../specs/webextension-inspected-window.js | 5 +++ 3 files changed, 66 insertions(+) diff --git a/devtools/server/actors/webextension-inspected-window.js b/devtools/server/actors/webextension-inspected-window.js index 2bac350829f7..14f783e62e47 100644 --- a/devtools/server/actors/webextension-inspected-window.js +++ b/devtools/server/actors/webextension-inspected-window.js @@ -501,6 +501,30 @@ var WebExtensionInspectedWindowActor = protocol.ActorClassWithSpec( if (evalResult) { try { + // Return the evalResult as a grip (used by the WebExtensions + // devtools inspector's sidebar.setExpression API method). + if (options.evalResultAsGrip) { + if (!options.toolboxConsoleActorID) { + return { + exceptionInfo: { + isError: true, + code: "E_PROTOCOLERROR", + description: "Inspector protocol error: %s - %s", + details: [ + "Unexpected invalid sidebar panel expression request", + "missing toolboxConsoleActorID", + ], + }, + }; + } + + let consoleActor = DebuggerServer.searchAllConnectionsForActor( + options.toolboxConsoleActorID + ); + + return {valueGrip: consoleActor.createValueGrip(evalResult)}; + } + if (evalResult && typeof evalResult === "object") { evalResult = evalResult.unsafeDereference(); } diff --git a/devtools/server/tests/browser/browser_webextension_inspected_window.js b/devtools/server/tests/browser/browser_webextension_inspected_window.js index ae42e828e81c..91de75c4f0e7 100644 --- a/devtools/server/tests/browser/browser_webextension_inspected_window.js +++ b/devtools/server/tests/browser/browser_webextension_inspected_window.js @@ -99,6 +99,43 @@ add_task(function* test_successfull_inspectedWindowEval_result() { yield teardown({client}); }); +add_task(function* test_successfull_inspectedWindowEval_resultAsGrip() { + const {client, inspectedWindowFront, form} = yield setup(MAIN_DOMAIN); + let result = yield inspectedWindowFront.eval(FAKE_CALLER_INFO, "window", { + evalResultAsGrip: true, + toolboxConsoleActorID: form.consoleActor + }); + + ok(result.valueGrip, "Got a result from inspectedWindow eval"); + ok(result.valueGrip.actor, "Got a object actor as expected"); + is(result.valueGrip.type, "object", "Got a value grip of type object"); + is(result.valueGrip.class, "Window", "Got a value grip which is instanceof Location"); + + // Test invalid evalResultAsGrip request. + result = yield inspectedWindowFront.eval( + FAKE_CALLER_INFO, "window", {evalResultAsGrip: true} + ); + + ok(!result.value && !result.valueGrip, + "Got a null result from the invalid inspectedWindow eval call"); + ok(result.exceptionInfo.isError, "Got an API Error result from inspectedWindow eval"); + ok(!result.exceptionInfo.isException, "An error isException is false as expected"); + is(result.exceptionInfo.code, "E_PROTOCOLERROR", + "Got the expected 'code' property in the error result"); + is(result.exceptionInfo.description, "Inspector protocol error: %s - %s", + "Got the expected 'description' property in the error result"); + is(result.exceptionInfo.details.length, 2, + "The 'details' array property should contains 1 element"); + is(result.exceptionInfo.details[0], + "Unexpected invalid sidebar panel expression request", + "Got the expected content in the error results's details"); + is(result.exceptionInfo.details[1], + "missing toolboxConsoleActorID", + "Got the expected content in the error results's details"); + + yield teardown({client}); +}); + add_task(function* test_error_inspectedWindowEval_result() { const {client, inspectedWindowFront} = yield setup(MAIN_DOMAIN); const result = yield inspectedWindowFront.eval(FAKE_CALLER_INFO, "window", {}); diff --git a/devtools/shared/specs/webextension-inspected-window.js b/devtools/shared/specs/webextension-inspected-window.js index 70a171f43db9..23abf076c58e 100644 --- a/devtools/shared/specs/webextension-inspected-window.js +++ b/devtools/shared/specs/webextension-inspected-window.js @@ -37,6 +37,10 @@ types.addDictType("webExtensionEvalOptions", { contextSecurityOrigin: "nullable:string", useContentScriptContext: "nullable:boolean", + // Return the evalResult as a grip (used by the WebExtensions + // devtools inspector's sidebar.setExpression API method). + evalResultAsGrip: "nullable:boolean", + // The actor ID of the node selected in the inspector if any, // used to provide the '$0' binding. toolboxSelectedNodeActorID: "nullable:string", @@ -73,6 +77,7 @@ types.addDictType("webExtensionEvalResult", { // The following properties are set if the evaluation has been // completed successfully. value: "nullable:json", + valueGrip: "nullable:json", // The following properties are set if the evalutation has been // completed with errors. exceptionInfo: "nullable:webExtensionEvalExceptionInfo", From 47e09897e900f7f4caafb80a10787970f5aad019 Mon Sep 17 00:00:00 2001 From: Luca Greco Date: Thu, 12 Oct 2017 16:20:39 +0200 Subject: [PATCH 02/41] Bug 1403130 - Support ObjectInspector-based object value grip view in ExtensionSidebar r=gl,nchevobbe MozReview-Commit-ID: DxU886yOCPu --HG-- extra : rebase_source : de4a98c9bb1943626bbd36abc819b8e6d5518a26 --- .../inspector/extensions/actions/index.js | 3 + .../inspector/extensions/actions/sidebar.js | 13 ++ .../extensions/components/ExtensionSidebar.js | 31 ++- .../components/ObjectValueGripView.js | 88 +++++++ .../inspector/extensions/components/moz.build | 1 + .../inspector/extensions/extension-sidebar.js | 59 +++++ .../client/inspector/extensions/moz.build | 1 + .../inspector/extensions/reducers/sidebar.js | 15 ++ .../inspector/extensions/test/browser.ini | 1 + .../browser_inspector_extension_sidebar.js | 214 +++++++++++++++--- .../client/inspector/extensions/test/head.js | 7 + .../test/head_devtools_inspector_sidebar.js | 160 +++++++++++++ devtools/client/inspector/extensions/types.js | 17 ++ 13 files changed, 570 insertions(+), 40 deletions(-) create mode 100644 devtools/client/inspector/extensions/components/ObjectValueGripView.js create mode 100644 devtools/client/inspector/extensions/test/head_devtools_inspector_sidebar.js create mode 100644 devtools/client/inspector/extensions/types.js diff --git a/devtools/client/inspector/extensions/actions/index.js b/devtools/client/inspector/extensions/actions/index.js index aa9e3caa3bd3..167939f0f5c3 100644 --- a/devtools/client/inspector/extensions/actions/index.js +++ b/devtools/client/inspector/extensions/actions/index.js @@ -11,6 +11,9 @@ createEnum([ // Update the extension sidebar with an object TreeView. "EXTENSION_SIDEBAR_OBJECT_TREEVIEW_UPDATE", + // Update the extension sidebar with an object value grip preview. + "EXTENSION_SIDEBAR_OBJECT_GRIP_VIEW_UPDATE", + // Remove an extension sidebar from the inspector store. "EXTENSION_SIDEBAR_REMOVE" diff --git a/devtools/client/inspector/extensions/actions/sidebar.js b/devtools/client/inspector/extensions/actions/sidebar.js index ba8bd9fe0802..0e5d48378d84 100644 --- a/devtools/client/inspector/extensions/actions/sidebar.js +++ b/devtools/client/inspector/extensions/actions/sidebar.js @@ -6,6 +6,7 @@ const { EXTENSION_SIDEBAR_OBJECT_TREEVIEW_UPDATE, + EXTENSION_SIDEBAR_OBJECT_GRIP_VIEW_UPDATE, EXTENSION_SIDEBAR_REMOVE, } = require("./index"); @@ -22,6 +23,18 @@ module.exports = { }; }, + /** + * Update the sidebar with an object actor preview. + */ + updateObjectValueGripView(sidebarId, objectValueGrip, rootTitle) { + return { + type: EXTENSION_SIDEBAR_OBJECT_GRIP_VIEW_UPDATE, + sidebarId, + objectValueGrip, + rootTitle, + }; + }, + /** * Remove the extension sidebar from the inspector store. */ diff --git a/devtools/client/inspector/extensions/components/ExtensionSidebar.js b/devtools/client/inspector/extensions/components/ExtensionSidebar.js index 36dcebe21188..9a7fd01102bd 100644 --- a/devtools/client/inspector/extensions/components/ExtensionSidebar.js +++ b/devtools/client/inspector/extensions/components/ExtensionSidebar.js @@ -10,13 +10,17 @@ const PropTypes = require("devtools/client/shared/vendor/react-prop-types"); const { connect } = require("devtools/client/shared/vendor/react-redux"); const ObjectTreeView = createFactory(require("./ObjectTreeView")); +const ObjectValueGripView = createFactory(require("./ObjectValueGripView")); +const Types = require("../types"); /** * The ExtensionSidebar is a React component with 2 supported viewMode: - * - an ObjectTreeView UI, used to show the JS objects (used by the sidebar.setObject - * and sidebar.setExpression WebExtensions APIs) - * - an ExtensionPage UI used to show an extension page (used by the sidebar.setPage - * WebExtensions APIs). + * - an ObjectTreeView UI, used to show the JS objects + * (used by the sidebar.setObject WebExtensions APIs) + * - an ObjectValueGripView UI, used to show the objects value grips + * (used by sidebar.setExpression WebExtensions APIs) + * - an ExtensionPage UI used to show an extension page + * (used by the sidebar.setPage WebExtensions APIs). * * TODO: implement the ExtensionPage viewMode. */ @@ -25,15 +29,23 @@ class ExtensionSidebar extends PureComponent { return { id: PropTypes.string.isRequired, extensionsSidebar: PropTypes.object.isRequired, + // Helpers injected as props by extension-sidebar.js. + serviceContainer: PropTypes.shape(Types.serviceContainer).isRequired, }; } render() { - const { id, extensionsSidebar } = this.props; + const { + id, + extensionsSidebar, + serviceContainer, + } = this.props; let { viewMode = "empty-sidebar", - object + object, + objectValueGrip, + rootTitle } = extensionsSidebar[id] || {}; let sidebarContentEl; @@ -42,6 +54,13 @@ class ExtensionSidebar extends PureComponent { case "object-treeview": sidebarContentEl = ObjectTreeView({ object }); break; + case "object-value-grip-view": + sidebarContentEl = ObjectValueGripView({ + objectValueGrip, + serviceContainer, + rootTitle, + }); + break; case "empty-sidebar": break; default: diff --git a/devtools/client/inspector/extensions/components/ObjectValueGripView.js b/devtools/client/inspector/extensions/components/ObjectValueGripView.js new file mode 100644 index 000000000000..99efd5ffe256 --- /dev/null +++ b/devtools/client/inspector/extensions/components/ObjectValueGripView.js @@ -0,0 +1,88 @@ +/* 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 PropTypes = require("devtools/client/shared/vendor/react-prop-types"); + +const Accordion = createFactory(require("devtools/client/inspector/layout/components/Accordion")); +const reps = require("devtools/client/shared/components/reps/reps"); +const Types = require("../types"); + +const { REPS, MODE } = reps; +const { Grip } = REPS; + +const ObjectInspector = createFactory(reps.ObjectInspector); + +class ObjectValueGripView extends PureComponent { + static get propTypes() { + return { + rootTitle: PropTypes.string, + objectValueGrip: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.number, + PropTypes.object, + ]).isRequired, + // Helpers injected as props by extension-sidebar.js. + serviceContainer: PropTypes.shape(Types.serviceContainer).isRequired, + }; + } + + render() { + const { + objectValueGrip, + serviceContainer, + rootTitle, + } = this.props; + + const objectInspectorProps = { + autoExpandDepth: 1, + mode: MODE.SHORT, + // TODO: we disable focus since it's not currently working well in ObjectInspector. + // Let's remove the property below when problem are fixed in OI. + disabledFocus: true, + roots: [{ + path: objectValueGrip && objectValueGrip.actor || JSON.stringify(objectValueGrip), + contents: { + value: objectValueGrip, + } + }], + createObjectClient: serviceContainer.createObjectClient, + releaseActor: serviceContainer.releaseActor, + // TODO: evaluate if there should also be a serviceContainer.openLink. + }; + + if (objectValueGrip && objectValueGrip.actor) { + Object.assign(objectInspectorProps, { + onDOMNodeMouseOver: serviceContainer.highlightDomElement, + onDOMNodeMouseOut: serviceContainer.unHighlightDomElement, + onInspectIconClick(object, e) { + // Stop the event propagation so we don't trigger ObjectInspector + // expand/collapse. + e.stopPropagation(); + serviceContainer.openNodeInInspector(object); + }, + defaultRep: Grip, + }); + } + + if (rootTitle) { + return Accordion({ + items: [ + { + component: ObjectInspector, + componentProps: objectInspectorProps, + header: rootTitle, + opened: true, + }, + ], + }); + } + + return ObjectInspector(objectInspectorProps); + } +} + +module.exports = ObjectValueGripView; diff --git a/devtools/client/inspector/extensions/components/moz.build b/devtools/client/inspector/extensions/components/moz.build index 04c07a1f70c7..dd595e11c578 100644 --- a/devtools/client/inspector/extensions/components/moz.build +++ b/devtools/client/inspector/extensions/components/moz.build @@ -7,4 +7,5 @@ DevToolsModules( 'ExtensionSidebar.js', 'ObjectTreeView.js', + 'ObjectValueGripView.js', ) diff --git a/devtools/client/inspector/extensions/extension-sidebar.js b/devtools/client/inspector/extensions/extension-sidebar.js index 38449049064f..b015d0a79f36 100644 --- a/devtools/client/inspector/extensions/extension-sidebar.js +++ b/devtools/client/inspector/extensions/extension-sidebar.js @@ -7,10 +7,12 @@ const { createElement, createFactory } = require("devtools/client/shared/vendor/react"); const { Provider } = require("devtools/client/shared/vendor/react-redux"); +const ObjectClient = require("devtools/shared/client/object-client"); const ExtensionSidebarComponent = createFactory(require("./components/ExtensionSidebar")); const { updateObjectTreeView, + updateObjectValueGripView, removeExtensionSidebar, } = require("./actions/sidebar"); @@ -52,6 +54,50 @@ class ExtensionSidebar { title: this.title, }, ExtensionSidebarComponent({ id: this.id, + serviceContainer: { + createObjectClient: (object) => { + return new ObjectClient(this.inspector.toolbox.target.client, object); + }, + releaseActor: (actor) => { + if (!actor) { + return; + } + this.inspector.toolbox.target.client.release(actor); + }, + highlightDomElement: (grip, options = {}) => { + const { highlighterUtils } = this.inspector.toolbox; + + if (!highlighterUtils) { + return null; + } + + return highlighterUtils.highlightDomValueGrip(grip, options); + }, + unHighlightDomElement: (forceHide = false) => { + const { highlighterUtils } = this.inspector.toolbox; + + if (!highlighterUtils) { + return null; + } + + return highlighterUtils.unhighlight(forceHide); + }, + openNodeInInspector: async (grip) => { + const { highlighterUtils } = this.inspector.toolbox; + + if (!highlighterUtils) { + return null; + } + + let front = await highlighterUtils.gripToNodeFront(grip); + let onInspectorUpdated = this.inspector.once("inspector-updated"); + let onNodeFrontSet = this.inspector.toolbox.selection.setNodeFront( + front, "inspector-extension-sidebar" + ); + + return Promise.all([onNodeFrontSet, onInspectorUpdated]); + } + }, })); } @@ -93,6 +139,19 @@ class ExtensionSidebar { this.store.dispatch(updateObjectTreeView(this.id, object)); } + + /** + * Dispatch an objectPreview action to change the SidebarComponent into an + * ObjectPreview React Component, which shows the passed value grip + * in the sidebar. + */ + setObjectValueGrip(objectValueGrip, rootTitle) { + if (this.removed) { + throw new Error("Unable to set an object preview on a removed ExtensionSidebar"); + } + + this.store.dispatch(updateObjectValueGripView(this.id, objectValueGrip, rootTitle)); + } } module.exports = ExtensionSidebar; diff --git a/devtools/client/inspector/extensions/moz.build b/devtools/client/inspector/extensions/moz.build index 4ef5f1ee24f5..dae7e8e58885 100644 --- a/devtools/client/inspector/extensions/moz.build +++ b/devtools/client/inspector/extensions/moz.build @@ -12,6 +12,7 @@ DIRS += [ DevToolsModules( 'extension-sidebar.js', + 'types.js', ) BROWSER_CHROME_MANIFESTS += ['test/browser.ini'] diff --git a/devtools/client/inspector/extensions/reducers/sidebar.js b/devtools/client/inspector/extensions/reducers/sidebar.js index 97125c90a1bc..df62d14a78db 100644 --- a/devtools/client/inspector/extensions/reducers/sidebar.js +++ b/devtools/client/inspector/extensions/reducers/sidebar.js @@ -6,6 +6,7 @@ const { EXTENSION_SIDEBAR_OBJECT_TREEVIEW_UPDATE, + EXTENSION_SIDEBAR_OBJECT_GRIP_VIEW_UPDATE, EXTENSION_SIDEBAR_REMOVE, } = require("../actions/index"); @@ -24,6 +25,20 @@ let reducers = { }); }, + [EXTENSION_SIDEBAR_OBJECT_GRIP_VIEW_UPDATE]( + sidebar, {sidebarId, objectValueGrip, rootTitle} + ) { + // Update the sidebar to a "object-treeview" which shows + // the passed object. + return Object.assign({}, sidebar, { + [sidebarId]: { + viewMode: "object-value-grip-view", + objectValueGrip, + rootTitle, + } + }); + }, + [EXTENSION_SIDEBAR_REMOVE](sidebar, {sidebarId}) { // Remove the sidebar from the Redux store. delete sidebar[sidebarId]; diff --git a/devtools/client/inspector/extensions/test/browser.ini b/devtools/client/inspector/extensions/test/browser.ini index f5cd44a0bf02..c28910f0e755 100644 --- a/devtools/client/inspector/extensions/test/browser.ini +++ b/devtools/client/inspector/extensions/test/browser.ini @@ -3,6 +3,7 @@ tags = devtools subsuite = devtools support-files = head.js + head_devtools_inspector_sidebar.js !/devtools/client/commandline/test/helpers.js !/devtools/client/framework/test/shared-head.js !/devtools/client/inspector/test/head.js diff --git a/devtools/client/inspector/extensions/test/browser_inspector_extension_sidebar.js b/devtools/client/inspector/extensions/test/browser_inspector_extension_sidebar.js index d262c2a7fffa..3d88c0aac8c2 100644 --- a/devtools/client/inspector/extensions/test/browser_inspector_extension_sidebar.js +++ b/devtools/client/inspector/extensions/test/browser_inspector_extension_sidebar.js @@ -4,35 +4,53 @@ "use strict"; -add_task(async function () { - const {inspector} = await openInspectorForURL("about:blank"); - const {toolbox} = inspector; +ChromeUtils.defineModuleGetter(this, "ContentTaskUtils", + "resource://testing-common/ContentTaskUtils.jsm"); - const sidebarId = "an-extension-sidebar"; - const sidebarTitle = "Sidebar Title"; +loader.lazyGetter(this, "WebExtensionInspectedWindowFront", () => { + return require( + "devtools/shared/fronts/webextension-inspected-window" + ).WebExtensionInspectedWindowFront; +}, true); - const waitSidebarCreated = toolbox.once(`extension-sidebar-created-${sidebarId}`); +const FAKE_CALLER_INFO = { + url: "moz-extension://fake-webextension-uuid/fake-caller-script.js", + lineNumber: 1, + addonId: "fake-webextension-uuid", +}; +const SIDEBAR_ID = "an-extension-sidebar"; +const SIDEBAR_TITLE = "Sidebar Title"; - toolbox.registerInspectorExtensionSidebar(sidebarId, {title: sidebarTitle}); +let toolbox; +let inspector; - const sidebar = await waitSidebarCreated; +add_task(async function setupExtensionSidebar() { + const res = await openInspectorForURL("about:blank"); + inspector = res.inspector; + toolbox = res.toolbox; - is(sidebar, inspector.getPanel(sidebarId), + const onceSidebarCreated = toolbox.once(`extension-sidebar-created-${SIDEBAR_ID}`); + toolbox.registerInspectorExtensionSidebar(SIDEBAR_ID, {title: SIDEBAR_TITLE}); + + const sidebar = await onceSidebarCreated; + + // Test sidebar properties. + is(sidebar, inspector.getPanel(SIDEBAR_ID), "Got an extension sidebar instance equal to the one saved in the inspector"); - - is(sidebar.title, sidebarTitle, + is(sidebar.title, SIDEBAR_TITLE, "Got the expected title in the extension sidebar instance"); - is(sidebar.provider.props.title, sidebarTitle, + is(sidebar.provider.props.title, SIDEBAR_TITLE, "Got the expeted title in the provider props"); + // Test sidebar Redux state. let inspectorStoreState = inspector.store.getState(); - ok("extensionsSidebar" in inspectorStoreState, "Got the extensionsSidebar sub-state in the inspector Redux store"); - Assert.deepEqual(inspectorStoreState.extensionsSidebar, {}, "The extensionsSidebar should be initially empty"); +}); +add_task(async function testSidebarSetObject() { let object = { propertyName: { nestedProperty: "propertyValue", @@ -40,56 +58,184 @@ add_task(async function () { }, }; + let sidebar = inspector.getPanel(SIDEBAR_ID); sidebar.setObject(object); - inspectorStoreState = inspector.store.getState(); - + // Test updated sidebar Redux state. + let inspectorStoreState = inspector.store.getState(); is(Object.keys(inspectorStoreState.extensionsSidebar).length, 1, "The extensionsSidebar state contains the newly registered extension sidebar state"); - Assert.deepEqual(inspectorStoreState.extensionsSidebar, { - [sidebarId]: { + [SIDEBAR_ID]: { viewMode: "object-treeview", object, }, }, "Got the expected state for the registered extension sidebar"); + // Select the extension sidebar. const waitSidebarSelected = toolbox.once(`inspector-sidebar-select`); - - inspector.sidebar.show(sidebarId); - + inspector.sidebar.show(SIDEBAR_ID); await waitSidebarSelected; - const sidebarPanelContent = inspector.sidebar.getTabPanel(sidebarId); + const sidebarPanelContent = inspector.sidebar.getTabPanel(SIDEBAR_ID); + // Test extension sidebar content. ok(sidebarPanelContent, "Got a sidebar panel for the registered extension sidebar"); - is(sidebarPanelContent.querySelectorAll("table.treeTable").length, 1, - "The sidebar panel contains a rendered TreeView component"); - - is(sidebarPanelContent.querySelectorAll("table.treeTable .stringCell").length, 2, - "The TreeView component contains the expected number of string cells."); + assertTreeView(sidebarPanelContent, { + expectedTreeTables: 1, + expectedStringCells: 2, + expectedNumberCells: 0, + }); + // Test sidebar refreshed on further sidebar.setObject calls. info("Change the inspected object in the extension sidebar object treeview"); sidebar.setObject({aNewProperty: 123}); - is(sidebarPanelContent.querySelectorAll("table.treeTable .stringCell").length, 0, - "The TreeView component doesn't contains any string cells anymore."); + assertTreeView(sidebarPanelContent, { + expectedTreeTables: 1, + expectedStringCells: 0, + expectedNumberCells: 1, + }); +}); - is(sidebarPanelContent.querySelectorAll("table.treeTable .numberCell").length, 1, - "The TreeView component contains one number cells."); +add_task(async function testSidebarSetObjectValueGrip() { + const inspectedWindowFront = new WebExtensionInspectedWindowFront( + toolbox.target.client, toolbox.target.form + ); + const sidebar = inspector.getPanel(SIDEBAR_ID); + const sidebarPanelContent = inspector.sidebar.getTabPanel(SIDEBAR_ID); + + info("Testing sidebar.setObjectValueGrip with rootTitle"); + + let expression = ` + var obj = Object.create(null); + obj.prop1 = 123; + obj[Symbol('sym1')] = 456; + obj.cyclic = obj; + obj; + `; + + let evalResult = await inspectedWindowFront.eval(FAKE_CALLER_INFO, expression, { + evalResultAsGrip: true, + toolboxConsoleActorID: toolbox.target.form.consoleActor + }); + + sidebar.setObjectValueGrip(evalResult.valueGrip, "Expected Root Title"); + + // Wait the ObjectInspector component to be rendered and test its content. + await testSetExpressionSidebarPanel(sidebarPanelContent, { + nodesLength: 4, + propertiesNames: ["cyclic", "prop1", "Symbol(sym1)"], + rootTitle: "Expected Root Title", + }); + + info("Testing sidebar.setObjectValueGrip without rootTitle"); + + sidebar.setObjectValueGrip(evalResult.valueGrip); + + // Wait the ObjectInspector component to be rendered and test its content. + await testSetExpressionSidebarPanel(sidebarPanelContent, { + nodesLength: 4, + propertiesNames: ["cyclic", "prop1", "Symbol(sym1)"], + }); + + inspectedWindowFront.destroy(); +}); + +add_task(async function testSidebarDOMNodeHighlighting() { + const inspectedWindowFront = new WebExtensionInspectedWindowFront( + toolbox.target.client, toolbox.target.form + ); + + const sidebar = inspector.getPanel(SIDEBAR_ID); + const sidebarPanelContent = inspector.sidebar.getTabPanel(SIDEBAR_ID); + + let expression = "({ body: document.body })"; + + let evalResult = await inspectedWindowFront.eval(FAKE_CALLER_INFO, expression, { + evalResultAsGrip: true, + toolboxConsoleActorID: toolbox.target.form.consoleActor + }); + + sidebar.setObjectValueGrip(evalResult.valueGrip); + + // Wait the DOM node to be rendered inside the component. + await waitForObjectInspector(sidebarPanelContent, "node"); + + // Get and verify the DOMNode and the "open inspector"" icon + // rendered inside the ObjectInspector. + assertObjectInspector(sidebarPanelContent, { + expectedDOMNodes: 1, + expectedOpenInspectors: 1, + }); + + // Test highlight DOMNode on mouseover. + info("Highlight the node by moving the cursor on it"); + + let onNodeHighlight = toolbox.once("node-highlight"); + + moveMouseOnObjectInspectorDOMNode(sidebarPanelContent); + + let nodeFront = await onNodeHighlight; + is(nodeFront.displayName, "body", "The correct node was highlighted"); + + // Test unhighlight DOMNode on mousemove. + info("Unhighlight the node by moving away from the node"); + let onNodeUnhighlight = toolbox.once("node-unhighlight"); + + moveMouseOnPanelCenter(sidebarPanelContent); + + await onNodeUnhighlight; + info("node-unhighlight event was fired when moving away from the node"); + + inspectedWindowFront.destroy(); +}); + +add_task(async function testSidebarDOMNodeOpenInspector() { + const sidebarPanelContent = inspector.sidebar.getTabPanel(SIDEBAR_ID); + + // Test DOMNode selected in the inspector when "open inspector"" icon clicked. + info("Unselect node in the inspector"); + let onceNewNodeFront = inspector.selection.once("new-node-front"); + inspector.selection.setNodeFront(null); + let nodeFront = await onceNewNodeFront; + is(nodeFront, undefined, "The inspector selection should have been unselected"); + + info("Select the ObjectInspector DOMNode in the inspector panel by clicking on it"); + + // Once we click the open-inspector icon we expect a new node front to be selected + // and the node to have been highlighted and unhighlighted. + let onNodeHighlight = toolbox.once("node-highlight"); + let onNodeUnhighlight = toolbox.once("node-unhighlight"); + onceNewNodeFront = inspector.selection.once("new-node-front"); + + clickOpenInspectorIcon(sidebarPanelContent); + + nodeFront = await onceNewNodeFront; + is(nodeFront.displayName, "body", "The correct node has been selected"); + nodeFront = await onNodeHighlight; + is(nodeFront.displayName, "body", "The correct node was highlighted"); + + await onNodeUnhighlight; +}); + +add_task(async function teardownExtensionSidebar() { info("Remove the sidebar instance"); - toolbox.unregisterInspectorExtensionSidebar(sidebarId); + toolbox.unregisterInspectorExtensionSidebar(SIDEBAR_ID); - ok(!inspector.sidebar.getTabPanel(sidebarId), + ok(!inspector.sidebar.getTabPanel(SIDEBAR_ID), "The rendered extension sidebar has been removed"); - inspectorStoreState = inspector.store.getState(); + let inspectorStoreState = inspector.store.getState(); Assert.deepEqual(inspectorStoreState.extensionsSidebar, {}, "The extensions sidebar Redux store data has been cleared"); await toolbox.destroy(); + + toolbox = null; + inspector = null; }); diff --git a/devtools/client/inspector/extensions/test/head.js b/devtools/client/inspector/extensions/test/head.js index f8ce18480a84..e9524a9d2ce1 100644 --- a/devtools/client/inspector/extensions/test/head.js +++ b/devtools/client/inspector/extensions/test/head.js @@ -12,3 +12,10 @@ Services.scriptloader.loadSubScript( "chrome://mochitests/content/browser/devtools/client/inspector/test/head.js", this); + +// Import the inspector extensions test helpers (shared between the tests that live +// in the current devtools test directory and the devtools sidebar tests that live +// in browser/components/extensions/test/browser). +Services.scriptloader.loadSubScript( + new URL("head_devtools_inspector_sidebar.js", gTestPath).href, + this); diff --git a/devtools/client/inspector/extensions/test/head_devtools_inspector_sidebar.js b/devtools/client/inspector/extensions/test/head_devtools_inspector_sidebar.js new file mode 100644 index 000000000000..1630eae86208 --- /dev/null +++ b/devtools/client/inspector/extensions/test/head_devtools_inspector_sidebar.js @@ -0,0 +1,160 @@ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* exported getExtensionSidebarActors, expectNoSuchActorIDs, + waitForObjectInspector, testSetExpressionSidebarPanel, assertTreeView, + assertObjectInspector, moveMouseOnObjectInspectorDOMNode, + moveMouseOnPanelCenter, clickOpenInspectorIcon */ + +"use strict"; + +// Retrieve the array of all the objectValueGrip actors from the +// inspector extension sidebars state +// (used in browser_ext_devtools_panels_elements_sidebar.js). +function getExtensionSidebarActors(inspector) { + const state = inspector.store.getState(); + + const actors = []; + + for (let sidebarId of Object.keys(state.extensionsSidebar)) { + const sidebarState = state.extensionsSidebar[sidebarId]; + + if (sidebarState.viewMode === "object-value-grip-view" && + sidebarState.objectValueGrip && sidebarState.objectValueGrip.actor) { + actors.push(sidebarState.objectValueGrip.actor); + } + } + + return actors; +} + +// Test that the specified objectValueGrip actors have been released +// on the remote debugging server +// (used in browser_ext_devtools_panels_elements_sidebar.js). +async function expectNoSuchActorIDs(client, actors) { + info(`Test that all the objectValueGrip actors have been released`); + for (let actor of actors) { + await Assert.rejects(client.request({to: actor, type: "requestTypes"}), + `No such actor for ID: ${actor}`); + } +} + +function waitForObjectInspector(panelDoc, waitForNodeWithType = "object") { + const selector = `.object-inspector .objectBox-${waitForNodeWithType}`; + return ContentTaskUtils.waitForCondition(() => { + return panelDoc.querySelectorAll(selector).length > 0; + }); +} + +// Helper function used inside the sidebar.setObjectValueGrip test case. +async function testSetExpressionSidebarPanel(panel, expected) { + const { + nodesLength, + propertiesNames, + rootTitle, + } = expected; + + await waitForObjectInspector(panel); + + let objectInspectors = [...panel.querySelectorAll(".tree")]; + is(objectInspectors.length, 1, "There is the expected number of object inspectors"); + let [objectInspector] = objectInspectors; + + // Wait the objectInspector to have been fully rendered. + await ContentTaskUtils.waitForCondition(() => { + return objectInspector.querySelectorAll(".node").length >= nodesLength; + }); + + let oiNodes = objectInspector.querySelectorAll(".node"); + + is(oiNodes.length, nodesLength, "Got the expected number of nodes in the tree"); + let propertiesNodes = [...objectInspector.querySelectorAll(".object-label")] + .map(el => el.textContent); + is(JSON.stringify(propertiesNodes), JSON.stringify(propertiesNames), + "Got the expected property names"); + + if (rootTitle) { + // Also check that the ObjectInspector is rendered inside + // an Accordion component with the expected title. + const accordion = panel.querySelector(".accordion"); + + ok(accordion, "Got an Accordion component as expected"); + + is(accordion.querySelector("._content").firstChild, objectInspector, + "The ObjectInspector should be inside the Accordion content"); + + is(accordion.querySelector("._header").textContent.trim(), rootTitle, + "The Accordion has the expected label"); + } else { + // Also check that there is no Accordion component rendered + // inside the sidebar panel. + ok(!panel.querySelector(".accordion"), + "Got no Accordion component as expected"); + } +} + +function assertTreeView(panelDoc, expectedContent) { + const { + expectedTreeTables, + expectedStringCells, + expectedNumberCells + } = expectedContent; + + if (expectedTreeTables) { + is(panelDoc.querySelectorAll("table.treeTable").length, expectedTreeTables, + "The panel document contains the expected number of TreeView components"); + } + + if (expectedStringCells) { + is(panelDoc.querySelectorAll("table.treeTable .stringCell").length, + expectedStringCells, + "The panel document contains the expected number of string cells."); + } + + if (expectedNumberCells) { + is(panelDoc.querySelectorAll("table.treeTable .numberCell").length, + expectedNumberCells, + "The panel document contains the expected number of number cells."); + } +} + +async function assertObjectInspector(panelDoc, expectedContent) { + const {expectedDOMNodes, expectedOpenInspectors} = expectedContent; + + // Get and verify the DOMNode and the "open inspector"" icon + // rendered inside the ObjectInspector. + let nodes = panelDoc.querySelectorAll(".objectBox-node"); + let nodeOpenInspectors = panelDoc.querySelectorAll( + ".objectBox-node .open-inspector" + ); + + is(nodes.length, expectedDOMNodes, + "Found the expected number of ObjectInspector DOMNodes"); + is(nodeOpenInspectors.length, expectedOpenInspectors, + "Found the expected nuber of open-inspector icons inside the ObjectInspector"); +} + +function moveMouseOnObjectInspectorDOMNode(panelDoc, nodeIndex = 0) { + let nodes = panelDoc.querySelectorAll(".objectBox-node"); + let node = nodes[nodeIndex]; + + ok(node, "Found the ObjectInspector DOMNode"); + + EventUtils.synthesizeMouseAtCenter(node, {type: "mousemove"}, + node.ownerDocument.defaultView); +} + +function moveMouseOnPanelCenter(panelDoc) { + EventUtils.synthesizeMouseAtCenter(panelDoc, {type: "mousemove"}, panelDoc.window); +} + +function clickOpenInspectorIcon(panelDoc, nodeIndex = 0) { + let nodes = panelDoc.querySelectorAll(".objectBox-node .open-inspector"); + let node = nodes[nodeIndex]; + + ok(node, "Found the ObjectInspector open-inspector icon"); + + node.click(); +} diff --git a/devtools/client/inspector/extensions/types.js b/devtools/client/inspector/extensions/types.js new file mode 100644 index 000000000000..decf79f97c2e --- /dev/null +++ b/devtools/client/inspector/extensions/types.js @@ -0,0 +1,17 @@ +/* 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 PropTypes = require("devtools/client/shared/vendor/react-prop-types"); + +// Helpers injected as props by extension-sidebar.js and used by the +// ObjectInspector component (which is part of the ObjectValueGripView). +exports.serviceContainer = { + createObjectClient: PropTypes.func.isRequired, + releaseActor: PropTypes.func.isRequired, + highlightDomElement: PropTypes.func.isRequired, + unHighlightDomElement: PropTypes.func.isRequired, + openNodeInInspector: PropTypes.func.isRequired, +}; From 126281c8a6d5c220082918505fd288acced9aa52 Mon Sep 17 00:00:00 2001 From: Luca Greco Date: Thu, 12 Oct 2017 15:55:47 +0200 Subject: [PATCH 03/41] Bug 1403130 - Allow DOMNodes and cyclic objects to be rendered with the sidebar.setExpression API method. r=aswan MozReview-Commit-ID: AjHn7KfVhas --HG-- extra : rebase_source : 006cb5df0649fc001c2ddfaecc1ddd3cba7d1f54 --- .../extensions/ext-devtools-panels.js | 63 ++++++-- .../test/browser/browser-common.ini | 2 + ...er_ext_devtools_panels_elements_sidebar.js | 134 +++++++++++------- 3 files changed, 140 insertions(+), 59 deletions(-) diff --git a/browser/components/extensions/ext-devtools-panels.js b/browser/components/extensions/ext-devtools-panels.js index 39c1ac67278f..f77abfc3dbfd 100644 --- a/browser/components/extensions/ext-devtools-panels.js +++ b/browser/components/extensions/ext-devtools-panels.js @@ -379,6 +379,11 @@ class ParentDevToolsInspectorSidebar { // Set by setObject if the sidebar has not been created yet. this._initializeSidebar = null; + // Set by _updateLastObjectValueGrip to keep track of the last + // object value grip (to release the previous selected actor + // on the remote debugging server when the actor changes). + this._lastObjectValueGrip = null; + this.toolbox.registerInspectorExtensionSidebar(this.id, { title: sidebarOptions.title, }); @@ -389,12 +394,15 @@ class ParentDevToolsInspectorSidebar { throw new Error("Unable to close a destroyed DevToolsSelectionObserver"); } + // Release the last selected actor on the remote debugging server. + this._updateLastObjectValueGrip(null); + this.toolbox.off(`extension-sidebar-created-${this.id}`, this.onSidebarCreated); this.toolbox.off(`inspector-sidebar-select`, this.onSidebarSelect); this.toolbox.unregisterInspectorExtensionSidebar(this.id); this.extensionSidebar = null; - this._initializeSidebar = null; + this._lazySidebarInit = null; this.destroyed = true; } @@ -402,9 +410,11 @@ class ParentDevToolsInspectorSidebar { onSidebarCreated(evt, sidebar) { this.extensionSidebar = sidebar; - if (typeof this._initializeSidebar === "function") { - this._initializeSidebar(); - this._initializeSidebar = null; + const {_lazySidebarInit} = this; + this._lazySidebarInit = null; + + if (typeof _lazySidebarInit === "function") { + _lazySidebarInit(); } } @@ -428,6 +438,8 @@ class ParentDevToolsInspectorSidebar { } setObject(object, rootTitle) { + this._updateLastObjectValueGrip(null); + // Nest the object inside an object, as the value of the `rootTitle` property. if (rootTitle) { object = {[rootTitle]: object}; @@ -437,7 +449,38 @@ class ParentDevToolsInspectorSidebar { this.extensionSidebar.setObject(object); } else { // Defer the sidebar.setObject call. - this._initializeSidebar = () => this.extensionSidebar.setObject(object); + this._setLazySidebarInit(() => this.extensionSidebar.setObject(object)); + } + } + + _setLazySidebarInit(cb) { + this._lazySidebarInit = cb; + } + + setObjectValueGrip(objectValueGrip, rootTitle) { + this._updateLastObjectValueGrip(objectValueGrip); + + if (this.extensionSidebar) { + this.extensionSidebar.setObjectValueGrip(objectValueGrip, rootTitle); + } else { + // Defer the sidebar.setObjectValueGrip call. + this._setLazySidebarInit(() => { + this.extensionSidebar.setObjectValueGrip(objectValueGrip, rootTitle); + }); + } + } + + _updateLastObjectValueGrip(newObjectValueGrip = null) { + const {_lastObjectValueGrip} = this; + + this._lastObjectValueGrip = newObjectValueGrip; + + const oldActor = _lastObjectValueGrip && _lastObjectValueGrip.actor; + const newActor = newObjectValueGrip && newObjectValueGrip.actor; + + // Release the previously active actor on the remote debugging server. + if (oldActor && oldActor !== newActor) { + this.toolbox.target.client.release(oldActor); } } } @@ -513,18 +556,20 @@ this.devtools_panels = class extends ExtensionAPI { } const front = await waitForInspectedWindowFront; - const evalOptions = Object.assign({}, getToolboxEvalOptions(context)); + const evalOptions = Object.assign({ + evalResultAsGrip: true, + }, getToolboxEvalOptions(context)); const evalResult = await front.eval(callerInfo, evalExpression, evalOptions); let jsonObject; if (evalResult.exceptionInfo) { jsonObject = evalResult.exceptionInfo; - } else { - jsonObject = evalResult.value; + + return sidebar.setObject(jsonObject, rootTitle); } - return sidebar.setObject(jsonObject, rootTitle); + return sidebar.setObjectValueGrip(evalResult.valueGrip, rootTitle); }, }, }, diff --git a/browser/components/extensions/test/browser/browser-common.ini b/browser/components/extensions/test/browser/browser-common.ini index 7362b29ef3b4..62ce63fd4cac 100644 --- a/browser/components/extensions/test/browser/browser-common.ini +++ b/browser/components/extensions/test/browser/browser-common.ini @@ -84,6 +84,8 @@ skip-if = (os == 'win' && !debug) # bug 1352668 [browser_ext_devtools_panel.js] [browser_ext_devtools_panels_elements.js] [browser_ext_devtools_panels_elements_sidebar.js] +support-files = + ../../../../../devtools/client/inspector/extensions/test/head_devtools_inspector_sidebar.js [browser_ext_find.js] skip-if = (os == 'win' && ccov) # Bug 1423667 [browser_ext_geckoProfiler_symbolicate.js] diff --git a/browser/components/extensions/test/browser/browser_ext_devtools_panels_elements_sidebar.js b/browser/components/extensions/test/browser/browser_ext_devtools_panels_elements_sidebar.js index 1b90f5aca7e8..bb2ebba5f7eb 100644 --- a/browser/components/extensions/test/browser/browser_ext_devtools_panels_elements_sidebar.js +++ b/browser/components/extensions/test/browser/browser_ext_devtools_panels_elements_sidebar.js @@ -9,11 +9,55 @@ ChromeUtils.defineModuleGetter(this, "devtools", ChromeUtils.defineModuleGetter(this, "ContentTaskUtils", "resource://testing-common/ContentTaskUtils.jsm"); +/* globals getExtensionSidebarActors, expectNoSuchActorIDs, testSetExpressionSidebarPanel */ + +// Import the shared test helpers from the related devtools tests. +Services.scriptloader.loadSubScript( + new URL("head_devtools_inspector_sidebar.js", gTestPath).href, + this); + function isActiveSidebarTabTitle(inspector, expectedTabTitle, message) { const actualTabTitle = inspector.panelDoc.querySelector(".tabs-menu-item.is-active").innerText; is(actualTabTitle, expectedTabTitle, message); } +function testSetObjectSidebarPanel(panel, expectedCellType, expectedTitle) { + is(panel.querySelectorAll("table.treeTable").length, 1, + "The sidebar panel contains a rendered TreeView component"); + + is(panel.querySelectorAll(`table.treeTable .${expectedCellType}Cell`).length, 1, + `The TreeView component contains the expected a cell of type ${expectedCellType}`); + + if (expectedTitle) { + const panelTree = panel.querySelector("table.treeTable"); + ok( + panelTree.innerText.includes(expectedTitle), + "The optional root object title has been included in the object tree" + ); + } +} + +async function testSidebarPanelSelect(extension, inspector, tabId, expected) { + const { + sidebarShown, + sidebarHidden, + activeSidebarTabTitle, + } = expected; + + inspector.sidebar.show(tabId); + + const shown = await extension.awaitMessage("devtools_sidebar_shown"); + is(shown, sidebarShown, "Got the shown event on the second extension sidebar"); + + if (sidebarHidden) { + const hidden = await extension.awaitMessage("devtools_sidebar_hidden"); + is(hidden, sidebarHidden, "Got the hidden event on the first extension sidebar"); + } + + isActiveSidebarTabTitle(inspector, activeSidebarTabTitle, + "Got the expected title on the active sidebar tab"); +} + add_task(async function test_devtools_panels_elements_sidebar() { let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "http://mochi.test:8888/"); @@ -34,14 +78,21 @@ add_task(async function test_devtools_panels_elements_sidebar() { sidebar2.onHidden.addListener(() => onShownListener("hidden", "sidebar2")); sidebar3.onHidden.addListener(() => onShownListener("hidden", "sidebar3")); - sidebar1.setObject({propertyName: "propertyValue"}, "Optional Root Object Title"); - sidebar2.setObject({anotherPropertyName: 123}); - // Refresh the sidebar content on every inspector selection. browser.devtools.panels.elements.onSelectionChanged.addListener(() => { - sidebar3.setExpression("$0 && $0.tagName", "Selected Element tagName"); + const expression = ` + var obj = Object.create(null); + obj.prop1 = 123; + obj[Symbol('sym1')] = 456; + obj.cyclic = obj; + obj; + `; + sidebar1.setExpression(expression, "sidebar.setExpression rootTitle"); }); + sidebar2.setObject({anotherPropertyName: 123}); + sidebar3.setObject({propertyName: "propertyValue"}, "Optional Root Object Title"); + browser.test.sendMessage("devtools_page_loaded"); } @@ -80,6 +131,8 @@ add_task(async function test_devtools_panels_elements_sidebar() { const inspector = await toolbox.getPanel("inspector"); + info("Test extension inspector sidebar 1 (sidebar.setExpression)"); + inspector.sidebar.show(sidebarIds[0]); const shownSidebarInstance = await extension.awaitMessage("devtools_sidebar_shown"); @@ -93,69 +146,48 @@ add_task(async function test_devtools_panels_elements_sidebar() { ok(sidebarPanel1, "Got a rendered sidebar panel for the first registered extension sidebar"); - is(sidebarPanel1.querySelectorAll("table.treeTable").length, 1, - "The first sidebar panel contains a rendered TreeView component"); + info("Waiting for the first panel to be rendered"); - is(sidebarPanel1.querySelectorAll("table.treeTable .stringCell").length, 1, - "The TreeView component contains the expected number of string cells."); + // Verify that the panel contains an ObjectInspector, with the expected number of nodes + // and with the expected property names. + await testSetExpressionSidebarPanel(sidebarPanel1, { + nodesLength: 4, + propertiesNames: ["cyclic", "prop1", "Symbol(sym1)"], + rootTitle: "sidebar.setExpression rootTitle", + }); - const sidebarPanel1Tree = sidebarPanel1.querySelector("table.treeTable"); - ok( - sidebarPanel1Tree.innerText.includes("Optional Root Object Title"), - "The optional root object title has been included in the object tree" - ); + // Retrieve the actors currently rendered into the extension sidebars. + const actors = getExtensionSidebarActors(inspector); - inspector.sidebar.show(sidebarIds[1]); + info("Test extension inspector sidebar 2 (sidebar.setObject without a root title)"); - const shownSidebarInstance2 = await extension.awaitMessage("devtools_sidebar_shown"); - const hiddenSidebarInstance1 = await extension.awaitMessage("devtools_sidebar_hidden"); - - is(shownSidebarInstance2, "sidebar2", "Got the shown event on the second extension sidebar"); - is(hiddenSidebarInstance1, "sidebar1", "Got the hidden event on the first extension sidebar"); - - isActiveSidebarTabTitle(inspector, "Test Sidebar 2", - "Got the expected title on the active sidebar tab"); + await testSidebarPanelSelect(extension, inspector, sidebarIds[1], { + sidebarShown: "sidebar2", + sidebarHidden: "sidebar1", + activeSidebarTabTitle: "Test Sidebar 2", + }); const sidebarPanel2 = inspector.sidebar.getTabPanel(sidebarIds[1]); ok(sidebarPanel2, "Got a rendered sidebar panel for the second registered extension sidebar"); - is(sidebarPanel2.querySelectorAll("table.treeTable").length, 1, - "The second sidebar panel contains a rendered TreeView component"); + testSetObjectSidebarPanel(sidebarPanel2, "number"); - is(sidebarPanel2.querySelectorAll("table.treeTable .numberCell").length, 1, - "The TreeView component contains the expected a cell of type number."); + info("Test extension inspector sidebar 3 (sidebar.setObject with a root title)"); - inspector.sidebar.show(sidebarIds[2]); - - const shownSidebarInstance3 = await extension.awaitMessage("devtools_sidebar_shown"); - const hiddenSidebarInstance2 = await extension.awaitMessage("devtools_sidebar_hidden"); - - is(shownSidebarInstance3, "sidebar3", "Got the shown event on the third extension sidebar"); - is(hiddenSidebarInstance2, "sidebar2", "Got the hidden event on the second extension sidebar"); - - isActiveSidebarTabTitle(inspector, "Test Sidebar 3", - "Got the expected title on the active sidebar tab"); + await testSidebarPanelSelect(extension, inspector, sidebarIds[2], { + sidebarShown: "sidebar3", + sidebarHidden: "sidebar2", + activeSidebarTabTitle: "Test Sidebar 3", + }); const sidebarPanel3 = inspector.sidebar.getTabPanel(sidebarIds[2]); ok(sidebarPanel3, "Got a rendered sidebar panel for the third registered extension sidebar"); - info("Waiting for the third panel to be rendered"); - await ContentTaskUtils.waitForCondition(() => { - return sidebarPanel3.querySelectorAll("table.treeTable").length > 0; - }); + testSetObjectSidebarPanel(sidebarPanel3, "string", "Optional Root Object Title"); - is(sidebarPanel3.querySelectorAll("table.treeTable").length, 1, - "The third sidebar panel contains a rendered TreeView component"); - - const treeViewStringValues = sidebarPanel3.querySelectorAll("table.treeTable .stringCell"); - - is(treeViewStringValues.length, 1, - "The TreeView component contains the expected content of type string."); - - is(treeViewStringValues[0].innerText, "\"BODY\"", - "Got the expected content in the sidebar.setExpression rendered TreeView"); + info("Unloading the extension and check that all the sidebar have been removed"); await extension.unload(); @@ -171,6 +203,8 @@ add_task(async function test_devtools_panels_elements_sidebar() { is(inspector.sidebar.getTabPanel(sidebarIds[2]), undefined, "The third registered sidebar has been removed"); + await expectNoSuchActorIDs(target.client, actors); + await gDevTools.closeToolbox(target); await target.destroy(); From a04da0af5901f58565409734d4622fa11d66896b Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Wed, 31 Jan 2018 17:04:20 +0900 Subject: [PATCH 04/41] Bug 1134542 - Get rid of nsIDOMWindowUtils::sendKeyEvent() and nsIFrameLoader::sendCrossProcessKeyEvent() r=smaug nsIDOMWindowUtils::sendKeyEvent() is already replaced with nsITextInputProcessor for making callers set any attributes of KeyboardEvent and guaranteeing consistency behavior with keyboard events caused by native key events. E.g., whether keypress event should be dispatched or not is automatically decided. nsIFrameLoader::sendCrossProcessKeyEvent() is similart to nsIDOMWindowUtils::sendKeyEvent() but it dispatches keyboard events in child process directly. Currently, nsITextInputProcessor doesn't have this feature but nobody wants/uses this feature. So, for removing actual implementation of nsIDOMWindowUtils::sendKeyEvent(), i.e., nsContentUtils::SendKeyEvent(), which is shared by both nsDOMWindowUtils::SendKeyEvent() and nsFrameLoader::SendCrossProcessKeyEvent(), we should remove this unused API too. (FYI: it's implemented for old Fennec, by bug 553149.) MozReview-Commit-ID: 9n0UVo8Me8k --HG-- extra : rebase_source : e9b117f5b9afec76e63d57ab8cd86dafb5873789 --- dom/base/nsContentUtils.cpp | 107 ---------------------- dom/base/nsContentUtils.h | 12 --- dom/base/nsDOMWindowUtils.cpp | 16 ---- dom/base/nsFrameLoader.cpp | 29 ------ dom/base/nsFrameLoader.h | 7 -- dom/base/nsIFrameLoader.idl | 9 -- dom/interfaces/base/nsIDOMWindowUtils.idl | 40 -------- dom/ipc/PBrowser.ipdl | 9 -- dom/ipc/TabChild.cpp | 13 --- dom/ipc/TabChild.h | 6 -- dom/ipc/TabParent.cpp | 14 --- dom/ipc/TabParent.h | 4 - dom/ipc/test.xul | 13 --- dom/webidl/FrameLoader.webidl | 10 -- 14 files changed, 289 deletions(-) diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index 35737825d56c..27a7dd9444c5 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -8570,112 +8570,6 @@ nsContentUtils::GetViewToDispatchEvent(nsPresContext* presContext, return nullptr; } -nsresult -nsContentUtils::SendKeyEvent(nsIWidget* aWidget, - const nsAString& aType, - int32_t aKeyCode, - int32_t aCharCode, - int32_t aModifiers, - uint32_t aAdditionalFlags, - bool* aDefaultActionTaken) -{ - // get the widget to send the event to - if (!aWidget) - return NS_ERROR_FAILURE; - - EventMessage msg; - if (aType.EqualsLiteral("keydown")) - msg = eKeyDown; - else if (aType.EqualsLiteral("keyup")) - msg = eKeyUp; - else if (aType.EqualsLiteral("keypress")) - msg = eKeyPress; - else - return NS_ERROR_FAILURE; - - WidgetKeyboardEvent event(true, msg, aWidget); - event.mModifiers = GetWidgetModifiers(aModifiers); - - if (msg == eKeyPress) { - event.mKeyCode = aCharCode ? 0 : aKeyCode; - event.mCharCode = aCharCode; - } else { - event.mKeyCode = aKeyCode; - event.mCharCode = 0; - } - - uint32_t locationFlag = (aAdditionalFlags & - (nsIDOMWindowUtils::KEY_FLAG_LOCATION_STANDARD | nsIDOMWindowUtils::KEY_FLAG_LOCATION_LEFT | - nsIDOMWindowUtils::KEY_FLAG_LOCATION_RIGHT | nsIDOMWindowUtils::KEY_FLAG_LOCATION_NUMPAD)); - switch (locationFlag) { - case nsIDOMWindowUtils::KEY_FLAG_LOCATION_STANDARD: - event.mLocation = eKeyLocationStandard; - break; - case nsIDOMWindowUtils::KEY_FLAG_LOCATION_LEFT: - event.mLocation = eKeyLocationLeft; - break; - case nsIDOMWindowUtils::KEY_FLAG_LOCATION_RIGHT: - event.mLocation = eKeyLocationRight; - break; - case nsIDOMWindowUtils::KEY_FLAG_LOCATION_NUMPAD: - event.mLocation = eKeyLocationNumpad; - break; - default: - if (locationFlag != 0) { - return NS_ERROR_INVALID_ARG; - } - // If location flag isn't set, choose the location from keycode. - switch (aKeyCode) { - case nsIDOMKeyEvent::DOM_VK_NUMPAD0: - case nsIDOMKeyEvent::DOM_VK_NUMPAD1: - case nsIDOMKeyEvent::DOM_VK_NUMPAD2: - case nsIDOMKeyEvent::DOM_VK_NUMPAD3: - case nsIDOMKeyEvent::DOM_VK_NUMPAD4: - case nsIDOMKeyEvent::DOM_VK_NUMPAD5: - case nsIDOMKeyEvent::DOM_VK_NUMPAD6: - case nsIDOMKeyEvent::DOM_VK_NUMPAD7: - case nsIDOMKeyEvent::DOM_VK_NUMPAD8: - case nsIDOMKeyEvent::DOM_VK_NUMPAD9: - case nsIDOMKeyEvent::DOM_VK_MULTIPLY: - case nsIDOMKeyEvent::DOM_VK_ADD: - case nsIDOMKeyEvent::DOM_VK_SEPARATOR: - case nsIDOMKeyEvent::DOM_VK_SUBTRACT: - case nsIDOMKeyEvent::DOM_VK_DECIMAL: - case nsIDOMKeyEvent::DOM_VK_DIVIDE: - event.mLocation = eKeyLocationNumpad; - break; - case nsIDOMKeyEvent::DOM_VK_SHIFT: - case nsIDOMKeyEvent::DOM_VK_CONTROL: - case nsIDOMKeyEvent::DOM_VK_ALT: - case nsIDOMKeyEvent::DOM_VK_META: - event.mLocation = eKeyLocationLeft; - break; - default: - event.mLocation = eKeyLocationStandard; - break; - } - break; - } - - event.mRefPoint = LayoutDeviceIntPoint(0, 0); - event.mTime = PR_IntervalNow(); - if (!(aAdditionalFlags & nsIDOMWindowUtils::KEY_FLAG_NOT_SYNTHESIZED_FOR_TESTS)) { - event.mFlags.mIsSynthesizedForTests = true; - } - - if (aAdditionalFlags & nsIDOMWindowUtils::KEY_FLAG_PREVENT_DEFAULT) { - event.PreventDefaultBeforeDispatch(); - } - - nsEventStatus status; - nsresult rv = aWidget->DispatchEvent(&event, status); - NS_ENSURE_SUCCESS(rv, rv); - - *aDefaultActionTaken = (status != nsEventStatus_eConsumeNoDefault); - - return NS_OK; -} - nsresult nsContentUtils::SendMouseEvent(const nsCOMPtr& aPresShell, const nsAString& aType, @@ -10958,7 +10852,6 @@ nsContentUtils::IsMessageInputEvent(const IPC::Message& aMsg) case mozilla::dom::PBrowser::Msg_RealDragEvent__ID: case mozilla::dom::PBrowser::Msg_UpdateDimensions__ID: case mozilla::dom::PBrowser::Msg_MouseEvent__ID: - case mozilla::dom::PBrowser::Msg_KeyEvent__ID: case mozilla::dom::PBrowser::Msg_SetDocShellIsActive__ID: return true; } diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h index 4f8e57e04751..bace7ea2be46 100644 --- a/dom/base/nsContentUtils.h +++ b/dom/base/nsContentUtils.h @@ -2875,18 +2875,6 @@ public: static nsView* GetViewToDispatchEvent(nsPresContext* aPresContext, nsIPresShell** aPresShell); - /** - * Synthesize a key event to the given widget - * (see nsIDOMWindowUtils.sendKeyEvent). - */ - static nsresult SendKeyEvent(nsIWidget* aWidget, - const nsAString& aType, - int32_t aKeyCode, - int32_t aCharCode, - int32_t aModifiers, - uint32_t aAdditionalFlags, - bool* aDefaultActionTaken); - /** * Synthesize a mouse event to the given widget * (see nsIDOMWindowUtils.sendMouseEvent). diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp index 62c66c31f88a..1f59efb913f2 100644 --- a/dom/base/nsDOMWindowUtils.cpp +++ b/dom/base/nsDOMWindowUtils.cpp @@ -977,22 +977,6 @@ nsDOMWindowUtils::SendTouchEventCommon(const nsAString& aType, return rv; } -NS_IMETHODIMP -nsDOMWindowUtils::SendKeyEvent(const nsAString& aType, - int32_t aKeyCode, - int32_t aCharCode, - int32_t aModifiers, - uint32_t aAdditionalFlags, - bool* aDefaultActionTaken) -{ - // get the widget to send the event to - nsCOMPtr widget = GetWidget(); - - return nsContentUtils::SendKeyEvent(widget, aType, aKeyCode, aCharCode, - aModifiers, aAdditionalFlags, - aDefaultActionTaken); -} - NS_IMETHODIMP nsDOMWindowUtils::SendNativeKeyEvent(int32_t aNativeKeyboardLayout, int32_t aNativeKeyCode, diff --git a/dom/base/nsFrameLoader.cpp b/dom/base/nsFrameLoader.cpp index a114d818faf1..029c4632f89d 100644 --- a/dom/base/nsFrameLoader.cpp +++ b/dom/base/nsFrameLoader.cpp @@ -2930,35 +2930,6 @@ nsFrameLoader::ActivateFrameEvent(const nsAString& aType, return NS_ERROR_FAILURE; } -void -nsFrameLoader::SendCrossProcessKeyEvent(const nsAString& aType, - int32_t aKeyCode, - int32_t aCharCode, - int32_t aModifiers, - bool aPreventDefault, - ErrorResult& aRv) -{ - nsresult rv = SendCrossProcessKeyEvent(aType, aKeyCode, aCharCode, aModifiers, aPreventDefault); - if (NS_FAILED(rv)) { - aRv.Throw(rv); - } -} - -NS_IMETHODIMP -nsFrameLoader::SendCrossProcessKeyEvent(const nsAString& aType, - int32_t aKeyCode, - int32_t aCharCode, - int32_t aModifiers, - bool aPreventDefault) -{ - if (mRemoteBrowser) { - mRemoteBrowser->SendKeyEvent(aType, aKeyCode, aCharCode, aModifiers, - aPreventDefault); - return NS_OK; - } - return NS_ERROR_FAILURE; -} - nsresult nsFrameLoader::CreateStaticClone(nsIFrameLoader* aDest) { diff --git a/dom/base/nsFrameLoader.h b/dom/base/nsFrameLoader.h index 962dc961dcca..367b89b2db34 100644 --- a/dom/base/nsFrameLoader.h +++ b/dom/base/nsFrameLoader.h @@ -138,13 +138,6 @@ public: bool aIgnoreRootScrollFrame, mozilla::ErrorResult& aRv); - void SendCrossProcessKeyEvent(const nsAString& aType, - int32_t aKeyCode, - int32_t aCharCode, - int32_t aModifiers, - bool aPreventDefault, - mozilla::ErrorResult& aRv); - void ActivateFrameEvent(const nsAString& aType, bool aCapture, mozilla::ErrorResult& aRv); diff --git a/dom/base/nsIFrameLoader.idl b/dom/base/nsIFrameLoader.idl index fef0482cc245..bb815bda70f9 100644 --- a/dom/base/nsIFrameLoader.idl +++ b/dom/base/nsIFrameLoader.idl @@ -110,15 +110,6 @@ interface nsIFrameLoader : nsISupports // Note, when frameloaders are swapped, also messageManagers are swapped. readonly attribute nsIMessageSender messageManager; - /** - * @see nsIDOMWindowUtils sendKeyEvent. - */ - void sendCrossProcessKeyEvent(in AString aType, - in long aKeyCode, - in long aCharCode, - in long aModifiers, - [optional] in boolean aPreventDefault); - /** * Request that the next time a remote layer transaction has been * received by the Compositor, a MozAfterRemoteFrame event be sent diff --git a/dom/interfaces/base/nsIDOMWindowUtils.idl b/dom/interfaces/base/nsIDOMWindowUtils.idl index 6b610bf6c503..06fa78194f39 100644 --- a/dom/interfaces/base/nsIDOMWindowUtils.idl +++ b/dom/interfaces/base/nsIDOMWindowUtils.idl @@ -462,46 +462,6 @@ interface nsIDOMWindowUtils : nsISupports { in long aLineOrPageDeltaY, in unsigned long aOptions); - /** - * Synthesize a key event to the window. The event types supported are: - * keydown, keyup, keypress - * - * Key events generally end up being sent to the focused node. - * - * Cannot be accessed from unprivileged context (not content-accessible) - * Will throw a DOM security error if called without chrome privileges. - * - * @param aType event type - * @param aKeyCode key code - * @param aCharCode character code - * @param aModifiers modifiers pressed, using constants defined as MODIFIER_* - * @param aAdditionalFlags special flags for the key event, see KEY_FLAG_*. - * - * @return false if the event had preventDefault() called on it, - * true otherwise. In other words, true if and only if the - * default action was taken. - */ - - // If this is set, preventDefault() the event before dispatch. - const unsigned long KEY_FLAG_PREVENT_DEFAULT = 0x0001; - - // If this is set, the mIsSynthesizedForTests flag is set to false - // on the key event. Otherwise it is true. - const unsigned long KEY_FLAG_NOT_SYNTHESIZED_FOR_TESTS = 0x0002; - - // if one of these flags is set, the KeyboardEvent.location will be the value. - // Otherwise, it will be computed from aKeyCode. - const unsigned long KEY_FLAG_LOCATION_STANDARD = 0x0010; - const unsigned long KEY_FLAG_LOCATION_LEFT = 0x0020; - const unsigned long KEY_FLAG_LOCATION_RIGHT = 0x0040; - const unsigned long KEY_FLAG_LOCATION_NUMPAD = 0x0080; - - boolean sendKeyEvent(in AString aType, - in long aKeyCode, - in long aCharCode, - in long aModifiers, - [optional] in unsigned long aAdditionalFlags); - /** * See nsIWidget::SynthesizeNativeKeyEvent * diff --git a/dom/ipc/PBrowser.ipdl b/dom/ipc/PBrowser.ipdl index b9beca123ab7..ed071d154c55 100644 --- a/dom/ipc/PBrowser.ipdl +++ b/dom/ipc/PBrowser.ipdl @@ -710,15 +710,6 @@ child: async PluginEvent(WidgetPluginEvent aEvent); - /** - * @see nsIDOMWindowUtils sendKeyEvent. - */ - async KeyEvent(nsString aType, - int32_t aKeyCode, - int32_t aCharCode, - int32_t aModifiers, - bool aPreventDefault); - prio(input) async CompositionEvent(WidgetCompositionEvent event); async NormalPriorityCompositionEvent(WidgetCompositionEvent event); diff --git a/dom/ipc/TabChild.cpp b/dom/ipc/TabChild.cpp index a856a3207b66..57363db018b6 100644 --- a/dom/ipc/TabChild.cpp +++ b/dom/ipc/TabChild.cpp @@ -2131,19 +2131,6 @@ TabChild::RecvNormalPriorityRealKeyEvent(const WidgetKeyboardEvent& aEvent) return RecvRealKeyEvent(aEvent); } -mozilla::ipc::IPCResult -TabChild::RecvKeyEvent(const nsString& aType, - const int32_t& aKeyCode, - const int32_t& aCharCode, - const int32_t& aModifiers, - const bool& aPreventDefault) -{ - bool ignored = false; - nsContentUtils::SendKeyEvent(mPuppetWidget, aType, aKeyCode, aCharCode, - aModifiers, aPreventDefault, &ignored); - return IPC_OK(); -} - mozilla::ipc::IPCResult TabChild::RecvCompositionEvent(const WidgetCompositionEvent& aEvent) { diff --git a/dom/ipc/TabChild.h b/dom/ipc/TabChild.h index bc7c1293d920..a4267cf160ba 100644 --- a/dom/ipc/TabChild.h +++ b/dom/ipc/TabChild.h @@ -432,12 +432,6 @@ public: const uint64_t& aInputBlockId, const nsEventStatus& aApzResponse) override; - virtual mozilla::ipc::IPCResult RecvKeyEvent(const nsString& aType, - const int32_t& aKeyCode, - const int32_t& aCharCode, - const int32_t& aModifiers, - const bool& aPreventDefault) override; - virtual mozilla::ipc::IPCResult RecvNativeSynthesisResponse(const uint64_t& aObserverId, const nsCString& aResponse) override; diff --git a/dom/ipc/TabParent.cpp b/dom/ipc/TabParent.cpp index 1c55d335ac5d..95406f98368e 100644 --- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -1103,20 +1103,6 @@ TabParent::SendMouseEvent(const nsAString& aType, float aX, float aY, } } -void -TabParent::SendKeyEvent(const nsAString& aType, - int32_t aKeyCode, - int32_t aCharCode, - int32_t aModifiers, - bool aPreventDefault) -{ - if (mIsDestroyed || !mIsReadyToHandleInputEvents) { - return; - } - Unused << PBrowserParent::SendKeyEvent(nsString(aType), aKeyCode, aCharCode, - aModifiers, aPreventDefault); -} - void TabParent::SendRealMouseEvent(WidgetMouseEvent& aEvent) { diff --git a/dom/ipc/TabParent.h b/dom/ipc/TabParent.h index cddf3e59dca1..5fbde77b923a 100644 --- a/dom/ipc/TabParent.h +++ b/dom/ipc/TabParent.h @@ -429,10 +429,6 @@ public: int32_t aButton, int32_t aClickCount, int32_t aModifiers, bool aIgnoreRootScrollFrame); - void SendKeyEvent(const nsAString& aType, int32_t aKeyCode, - int32_t aCharCode, int32_t aModifiers, - bool aPreventDefault); - /** * The following Send*Event() marks aEvent as posted to remote process if * it succeeded. So, you can check the result with diff --git a/dom/ipc/test.xul b/dom/ipc/test.xul index 8a6d1e682891..4489312bc818 100644 --- a/dom/ipc/test.xul +++ b/dom/ipc/test.xul @@ -73,18 +73,6 @@ frameLoader.sendCrossProcessMouseEvent("mouseup", x, y, 0, 1, 0, false); } - function keyPress() { - // First focus the remote frame, then dispatch click. This way remote frame gets focus before - // mouse event. - document.getElementById('page').focus(); - var frameLoader = document.getElementById('page').QueryInterface(Components.interfaces.nsIFrameLoaderOwner).frameLoader; - - var keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_A; - frameLoader.sendCrossProcessKeyEvent("keydown", keyCode, 0, 0); - frameLoader.sendCrossProcessKeyEvent("keypress", keyCode, 0, 0); - frameLoader.sendCrossProcessKeyEvent("keyup", keyCode, 0, 0); - } - function openWindow() { window.open('chrome://global/content/test-ipc.xul', '_blank', 'chrome,resizable,width=800,height=800'); } @@ -248,7 +236,6 @@ - diff --git a/dom/webidl/FrameLoader.webidl b/dom/webidl/FrameLoader.webidl index e136917446d2..8e92f35ac4db 100644 --- a/dom/webidl/FrameLoader.webidl +++ b/dom/webidl/FrameLoader.webidl @@ -106,16 +106,6 @@ interface FrameLoader { // Note, when frameloaders are swapped, also messageManagers are swapped. readonly attribute nsIMessageSender? messageManager; - /** - * @see nsIDOMWindowUtils sendKeyEvent. - */ - [Throws] - void sendCrossProcessKeyEvent(DOMString aType, - long aKeyCode, - long aCharCode, - long aModifiers, - optional boolean aPreventDefault = false); - /** * Request that the next time a remote layer transaction has been * received by the Compositor, a MozAfterRemoteFrame event be sent From 12516af1985de45e7b940a49592b6d82d0b259aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Fri, 9 Feb 2018 06:32:39 -0500 Subject: [PATCH 05/41] servo: Merge #20003 - style: Remove unneeded clone (from emilio:simplify-font-family-serialize); r=nox Source-Repo: https://github.com/servo/servo Source-Revision: f8ac623047085fbb46eab44f6ad7682a45f032b7 --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : ef54cf56fc87241cd276be38cf5089cca7fadcc9 --- servo/components/style/values/computed/font.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/servo/components/style/values/computed/font.rs b/servo/components/style/values/computed/font.rs index 31bd859dd3a7..646f91155f78 100644 --- a/servo/components/style/values/computed/font.rs +++ b/servo/components/style/values/computed/font.rs @@ -475,7 +475,7 @@ impl SingleFontFamily { let mut serialization = String::new(); serialize_atom_identifier(&name, &mut serialization).unwrap(); SingleFontFamily::FamilyName(FamilyName { - name: name.clone(), + name, syntax: FamilyNameSyntax::Identifiers(serialization), }) }, From 5f077444bc106cc1a2f5d97f623321e222de65bc Mon Sep 17 00:00:00 2001 From: Tim Nguyen Date: Fri, 9 Feb 2018 13:47:44 +0000 Subject: [PATCH 06/41] Bug 1429573 - Use input[type=number] in textbox[type=number] implementation. r=Paolo,surkov * The number is no longer selected on number input focus MozReview-Commit-ID: 6XQdnJP65m0 --HG-- extra : rebase_source : 96d16469e99fc52c15a0b5024bdf9c3b4211a171 --- .../tests/mochitest/tree/test_txtctrl.xul | 8 +- .../tests/chrome/test_textbox_number.xul | 88 +------------------ toolkit/content/widgets/numberbox.xml | 80 +---------------- toolkit/content/widgets/textbox.xml | 50 ++++++----- .../themes/linux/global/in-content/common.css | 4 - toolkit/themes/linux/global/numberbox.css | 11 +-- .../themes/osx/global/in-content/common.css | 24 +---- toolkit/themes/osx/global/numberbox.css | 6 +- .../themes/shared/in-content/common.inc.css | 45 ++++------ toolkit/themes/shared/non-mac.jar.inc.mn | 2 - toolkit/themes/windows/global/jar.mn | 2 + toolkit/themes/windows/global/numberbox.css | 5 +- 12 files changed, 68 insertions(+), 257 deletions(-) diff --git a/accessible/tests/mochitest/tree/test_txtctrl.xul b/accessible/tests/mochitest/tree/test_txtctrl.xul index 9a85d4603a33..d2b9da99a653 100644 --- a/accessible/tests/mochitest/tree/test_txtctrl.xul +++ b/accessible/tests/mochitest/tree/test_txtctrl.xul @@ -75,10 +75,12 @@ accTree = { SECTION: [ - { ENTRY: [ { TEXT_LEAF: [] } ] }, + { SPINBUTTON: [ + { ENTRY: [ { TEXT_LEAF: [] } ] }, + { PUSHBUTTON: [ ] }, + { PUSHBUTTON: [ ] } + ] }, { MENUPOPUP: [] }, - { PUSHBUTTON: [] }, - { PUSHBUTTON: [] } ] }; testAccessibleTree("txc_number", accTree); diff --git a/toolkit/content/tests/chrome/test_textbox_number.xul b/toolkit/content/tests/chrome/test_textbox_number.xul index fba395b864a7..6fc9e0115c67 100644 --- a/toolkit/content/tests/chrome/test_textbox_number.xul +++ b/toolkit/content/tests/chrome/test_textbox_number.xul @@ -6,8 +6,8 @@ --> - - + + @@ -48,8 +48,6 @@ function doTests() { testValsMinMax(n5, "initial n5", -10, -10, -3); testValsMinMax(n6, "initial n6", 12, 12, 12); - ok(n1.spinButtons != null && n1.spinButtons.localName == "spinbuttons", "spinButtons set"); - // test changing the value n1.value = "1700"; testVals(n1, "set value,", 1700); @@ -93,67 +91,19 @@ function doTests() { n1.max = 22; testValsMinMax(n1, "set integer max,", 22, 8, 22); - // test increase and decrease via the keyboard and the spinbuttons - testIncreaseDecrease(n1, "integer", 1, 0, 8, 22); - - // UI tests - n1.min = 5; - n1.max = 15; - n1.value = 5; - n1.focus(); - - var sb = n1.spinButtons; - var sbbottom = sb.getBoundingClientRect().bottom - sb.getBoundingClientRect().top - 2; - - synthesizeKey("VK_UP", {}); - testVals(n1, "key up", 6); - - synthesizeKey("VK_DOWN", {}); - testVals(n1, "key down", 5); - - synthesizeMouse(sb, 2, 2, {}); - testVals(n1, "spinbuttons up", 6); - synthesizeMouse(sb, 2, sbbottom, {}); - testVals(n1, "spinbuttons down", 5); - - n1.value = 15; - synthesizeKey("VK_UP", {}); - testVals(n1, "key up at max", 15); - synthesizeMouse(sb, 2, 2, {}); - testVals(n1, "spinbuttons up at max", 15); - - n1.value = 5; - synthesizeKey("VK_DOWN", {}); - testVals(n1, "key down at min", 5); - synthesizeMouse(sb, 2, sbbottom, {}); - testVals(n1, "spinbuttons down at min", 5); - // check read only state n1.readOnly = true; n1.min = -10; n1.max = 15; n1.value = 12; + n1.inputField.focus(); // no events should fire and no changes should occur when the field is read only synthesizeKeyExpectEvent("VK_UP", { }, n1, "!change", "key up read only"); is(n1.value, "12", "key up read only value"); synthesizeKeyExpectEvent("VK_DOWN", { }, n1, "!change", "key down read only"); is(n1.value, "12", "key down read only value"); - synthesizeMouseExpectEvent(sb, 2, 2, { }, n1, "!change", "mouse up read only"); - is(n1.value, "12", "mouse up read only value"); - synthesizeMouseExpectEvent(sb, 2, sbbottom, { }, n1, "!change", "mouse down read only"); - is(n1.value, "12", "mouse down read only value"); - n1.readOnly = false; - n1.disabled = true; - synthesizeMouseExpectEvent(sb, 2, 2, { }, n1, "!change", "mouse up disabled"); - is(n1.value, "12", "mouse up disabled value"); - synthesizeMouseExpectEvent(sb, 2, sbbottom, { }, n1, "!change", "mouse down disabled"); - is(n1.value, "12", "mouse down disabled value"); - - var nsbrect = $("n8").spinButtons.getBoundingClientRect(); - ok(nsbrect.left == 0 && nsbrect.top == 0 && nsbrect.right == 0, nsbrect.bottom == 0, - "hidespinbuttons"); var n9 = $("n9"); is(n9.value, "0", "initial value"); @@ -202,38 +152,6 @@ function testValsMinMax(nb, name, valueNumber, min, max, valueFieldNumber) { SimpleTest.is(nb.max, max, name + " max is " + max); } -function testIncreaseDecrease(nb, testid, increment, fixedCount, min, max) { - testid += " "; - - nb.focus(); - nb.value = min; - - // pressing the cursor up and down keys should adjust the value - synthesizeKeyExpectEvent("VK_UP", { }, nb, "change", testid + "key up"); - is(nb.value, String(min + increment), testid + "key up"); - nb.value = max; - synthesizeKeyExpectEvent("VK_UP", { }, nb, "!change", testid + "key up at max"); - is(nb.value, String(max), testid + "key up at max"); - synthesizeKeyExpectEvent("VK_DOWN", { }, nb, "change", testid + "key down"); - is(nb.value, String(max - increment), testid + "key down"); - nb.value = min; - synthesizeKeyExpectEvent("VK_DOWN", { }, nb, "!change", testid + "key down at min"); - is(nb.value, String(min), testid + "key down at min"); - - // check pressing the spinbutton arrows - var sb = nb.spinButtons; - var sbbottom = sb.getBoundingClientRect().bottom - sb.getBoundingClientRect().top - 2; - nb.value = min; - synthesizeMouseExpectEvent(sb, 2, 2, { }, nb, "change", testid + "mouse up"); - is(nb.value, String(min + increment), testid + "mouse up"); - nb.value = max; - synthesizeMouseExpectEvent(sb, 2, 2, { }, nb, "!change", testid + "mouse up at max"); - synthesizeMouseExpectEvent(sb, 2, sbbottom, { }, nb, "change", testid + "mouse down"); - is(nb.value, String(max - increment), testid + "mouse down"); - nb.value = min; - synthesizeMouseExpectEvent(sb, 2, sbbottom, { }, nb, "!change", testid + "mouse down at min"); -} - SimpleTest.waitForFocus(doTests); ]]> diff --git a/toolkit/content/widgets/numberbox.xml b/toolkit/content/widgets/numberbox.xml index cc1a8d3d188f..d0bcfab04a23 100644 --- a/toolkit/content/widgets/numberbox.xml +++ b/toolkit/content/widgets/numberbox.xml @@ -19,28 +19,16 @@ - + - false - null 0 - - - - - - - @@ -93,47 +81,6 @@ - - - - - - - - - - - - - - = this.max); - } - ]]> - - - @@ -152,8 +99,6 @@ this._value = Number(aValue); this.inputField.value = aValue; - this._enableDisableButtons(); - return aValue; ]]> @@ -194,26 +139,9 @@ ]]> - - this._modifyUp(); - - - - this._modifyDown(); - - - - this._modifyUp(); - - - - this._modifyDown(); - - if (event.originalTarget == this.inputField) { - var newval = this.inputField.value; - this._validateValue(newval); + this._validateValue(this.inputField.value); } diff --git a/toolkit/content/widgets/textbox.xml b/toolkit/content/widgets/textbox.xml index 08148d4e22e1..ed43a20fd4c1 100644 --- a/toolkit/content/widgets/textbox.xml +++ b/toolkit/content/widgets/textbox.xml @@ -127,7 +127,12 @@ - this.inputField.setSelectionRange( aSelectionStart, aSelectionEnd ); + // According to https://html.spec.whatwg.org/#do-not-apply, + // setSelectionRange() is only available on a limited set of input types. + if (this.inputField.type == "text" || + this.inputField.tagName == "html:textarea") { + this.inputField.setSelectionRange( aSelectionStart, aSelectionEnd ); + } @@ -188,26 +193,29 @@ if (this.hasAttribute("focused")) return; - switch (event.originalTarget) { - case this: - // Forward focus to actual HTML input - this.inputField.focus(); - break; - case this.inputField: - if (this.mIgnoreFocus) { - this.mIgnoreFocus = false; - } else if (this.clickSelectsAll) { - try { - if (!this.editor || !this.editor.composing) - this.editor.selectAll(); - } catch (e) {} - } - break; - default: - // Allow other children (e.g. URL bar buttons) to get focus - return; + let { originalTarget } = event; + if (originalTarget == this) { + // Forward focus to actual HTML input + this.inputField.focus(); + this.setAttribute("focused", "true"); + return; } - this.setAttribute("focused", "true"); + + // We check for the parent nodes to support input[type=number] where originalTarget may be an + // anonymous child input. + if (originalTarget == this.inputField || + originalTarget.localName == "input" && originalTarget.parentNode.parentNode == this.inputField) { + if (this.mIgnoreFocus) { + this.mIgnoreFocus = false; + } else if (this.clickSelectsAll) { + try { + if (!this.editor || !this.editor.composing) + this.editor.selectAll(); + } catch (e) {} + } + this.setAttribute("focused", "true"); + } + // Otherwise, allow other children (e.g. URL bar buttons) to get focus ]]> @@ -229,7 +237,7 @@ if (!this.mIgnoreClick) { this.mIgnoreFocus = true; - this.inputField.setSelectionRange(0, 0); + this.setSelectionRange(0, 0); if (event.originalTarget == this || event.originalTarget == this.inputField.parentNode) this.inputField.focus(); diff --git a/toolkit/themes/linux/global/in-content/common.css b/toolkit/themes/linux/global/in-content/common.css index c82331c9a2f9..3f6e10f5500c 100644 --- a/toolkit/themes/linux/global/in-content/common.css +++ b/toolkit/themes/linux/global/in-content/common.css @@ -81,10 +81,6 @@ html|input[type="checkbox"]:-moz-focusring + html|label:before { outline: 1px dotted; } -xul|spinbuttons { - -moz-appearance: none; -} - xul|treechildren::-moz-tree-row(multicol, odd) { background-color: var(--in-content-box-background-odd); } diff --git a/toolkit/themes/linux/global/numberbox.css b/toolkit/themes/linux/global/numberbox.css index 0b60d952fd1c..59f189019405 100644 --- a/toolkit/themes/linux/global/numberbox.css +++ b/toolkit/themes/linux/global/numberbox.css @@ -21,13 +21,6 @@ html|*.numberbox-input { text-align: right; } -.numberbox-input-box { - -moz-box-align: center; - -moz-appearance: spinner-textfield; - margin-right: -1px; - padding: 3px; -} - -textbox[hidespinbuttons="true"] > .numberbox-input-box { - -moz-appearance: textfield; +textbox[type="number"][hidespinbuttons="true"] > html|*.numberbox-input { + -moz-appearance: textfield !important; } diff --git a/toolkit/themes/osx/global/in-content/common.css b/toolkit/themes/osx/global/in-content/common.css index 99471334c2ce..ba1b24208145 100644 --- a/toolkit/themes/osx/global/in-content/common.css +++ b/toolkit/themes/osx/global/in-content/common.css @@ -57,11 +57,6 @@ xul|*.radio-icon { margin-inline-end: 0; } -xul|*.numberbox-input-box { - -moz-appearance: none; - border-width: 0; -} - xul|*.text-link:-moz-focusring { color: var(--in-content-link-highlight); text-decoration: underline; @@ -83,29 +78,14 @@ xul|radio[focused="true"] > .radio-check { -moz-outline-radius: 100%; } -xul|spinbuttons { - -moz-appearance: none; -} - -xul|*.spinbuttons-up { - margin-top: 0 !important; +html|*.numberbox-input::-moz-number-spin-up { border-radius: 4px 4px 0 0; } -xul|*.spinbuttons-down { - margin-bottom: 0 !important; +html|*.numberbox-input::-moz-number-spin-down { border-radius: 0 0 4px 4px; } -xul|*.spinbuttons-button > xul|*.button-box { - padding-inline-start: 2px !important; - padding-inline-end: 3px !important; -} - -xul|*.spinbuttons-button > xul|*.button-box > xul|*.button-text { - display: none; -} - xul|textbox[type="search"]:not([searchbutton]) > .textbox-input-box > .textbox-search-sign { list-style-image: url(chrome://global/skin/icons/search-textbox.svg); margin-inline-end: 5px; diff --git a/toolkit/themes/osx/global/numberbox.css b/toolkit/themes/osx/global/numberbox.css index 73db12495948..f14702aedf1a 100644 --- a/toolkit/themes/osx/global/numberbox.css +++ b/toolkit/themes/osx/global/numberbox.css @@ -7,7 +7,6 @@ textbox[type="number"] { -moz-appearance: none; - -moz-box-align: center; padding: 0 !important; border: none; background-color: transparent; @@ -19,7 +18,6 @@ html|*.numberbox-input { padding: 0 1px !important; } -.numberbox-input-box { - -moz-appearance: textfield; - margin-right: 4px; +textbox[type="number"][hidespinbuttons="true"] > html|*.numberbox-input { + -moz-appearance: textfield !important; } diff --git a/toolkit/themes/shared/in-content/common.inc.css b/toolkit/themes/shared/in-content/common.inc.css index 081b67c0837b..157cd707014a 100644 --- a/toolkit/themes/shared/in-content/common.inc.css +++ b/toolkit/themes/shared/in-content/common.inc.css @@ -165,7 +165,9 @@ html|button { *|button, html|select, xul|colorpicker[type="button"], -xul|menulist { +xul|menulist, +html|*.numberbox-input::-moz-number-spin-up, +html|*.numberbox-input::-moz-number-spin-down { -moz-appearance: none; min-height: 30px; color: var(--in-content-text-color); @@ -201,6 +203,8 @@ html|select:not([size]):not([multiple]):dir(rtl){ html|button:enabled:hover, html|select:not([size]):not([multiple]):enabled:hover, +html|*.numberbox-input::-moz-number-spin-up:hover, +html|*.numberbox-input::-moz-number-spin-down:hover, xul|button:not([disabled="true"]):hover, xul|colorpicker[type="button"]:not([disabled="true"]):hover, xul|menulist:not([disabled="true"]):hover { @@ -209,6 +213,8 @@ xul|menulist:not([disabled="true"]):hover { html|button:enabled:hover:active, html|select:not([size]):not([multiple]):enabled:hover:active, +html|*.numberbox-input::-moz-number-spin-up:hover:active, +html|*.numberbox-input::-moz-number-spin-down:hover:active, xul|button:not([disabled="true"]):hover:active, xul|colorpicker[type="button"]:not([disabled="true"]):hover:active, xul|menulist[open="true"]:not([disabled="true"]) { @@ -217,6 +223,7 @@ xul|menulist[open="true"]:not([disabled="true"]) { html|button:disabled, html|select:disabled, +html|*.numberbox-input:disabled::-moz-number-spin-box, xul|button[disabled="true"], xul|colorpicker[type="button"][disabled="true"], xul|menulist[disabled="true"], @@ -347,40 +354,22 @@ html|*.help-button:hover:active { background-color: var(--in-content-category-background-active); } -xul|*.spinbuttons-button { +html|*.numberbox-input::-moz-number-spin-up, +html|*.numberbox-input::-moz-number-spin-down { + padding: 5px 8px; + margin: 1px; + margin-inline-start: 10px; min-height: initial; - margin-inline-start: 10px !important; - margin-inline-end: 2px !important; } -xul|*.spinbuttons-up { - margin-top: 2px !important; +html|*.numberbox-input::-moz-number-spin-up { border-radius: 1px 1px 0 0; + background-image: url("chrome://global/skin/arrow/arrow-up.gif"); } -xul|*.spinbuttons-down { - margin-bottom: 2px !important; +html|*.numberbox-input::-moz-number-spin-down { border-radius: 0 0 1px 1px; -} - -xul|*.spinbuttons-button > xul|*.button-box { - padding: 1px 5px 2px !important; -} - -xul|*.spinbuttons-up > xul|*.button-box > xul|*.button-icon { - list-style-image: url("chrome://global/skin/arrow/arrow-up.gif"); -} - -xul|*.spinbuttons-up[disabled="true"] > xul|*.button-box > xul|*.button-icon { - list-style-image: url("chrome://global/skin/arrow/arrow-up-dis.gif"); -} - -xul|*.spinbuttons-down > xul|*.button-box > xul|*.button-icon { - list-style-image: url("chrome://global/skin/arrow/arrow-dn.gif"); -} - -xul|*.spinbuttons-down[disabled="true"] > xul|*.button-box > xul|*.button-icon { - list-style-image: url("chrome://global/skin/arrow/arrow-dn-dis.gif"); + background-image: url("chrome://global/skin/arrow/arrow-dn.gif"); } xul|menulist:not([editable="true"]) > xul|*.menulist-dropmarker { diff --git a/toolkit/themes/shared/non-mac.jar.inc.mn b/toolkit/themes/shared/non-mac.jar.inc.mn index 584b7ef9c992..f5809ca5ba1c 100644 --- a/toolkit/themes/shared/non-mac.jar.inc.mn +++ b/toolkit/themes/shared/non-mac.jar.inc.mn @@ -21,9 +21,7 @@ skin/classic/global/wizard.css (../../windows/global/wizard.css) skin/classic/global/arrow/arrow-dn.gif (../../windows/global/arrow/arrow-dn.gif) - skin/classic/global/arrow/arrow-dn-dis.gif (../../windows/global/arrow/arrow-dn-dis.gif) skin/classic/global/arrow/arrow-up.gif (../../windows/global/arrow/arrow-up.gif) - skin/classic/global/arrow/arrow-up-dis.gif (../../windows/global/arrow/arrow-up-dis.gif) skin/classic/global/arrow/panelarrow-horizontal.svg (../../windows/global/arrow/panelarrow-horizontal.svg) skin/classic/global/arrow/panelarrow-vertical.svg (../../windows/global/arrow/panelarrow-vertical.svg) diff --git a/toolkit/themes/windows/global/jar.mn b/toolkit/themes/windows/global/jar.mn index 317332cfcf4b..52d30807f2c0 100644 --- a/toolkit/themes/windows/global/jar.mn +++ b/toolkit/themes/windows/global/jar.mn @@ -36,6 +36,8 @@ toolkit.jar: skin/classic/global/arrow/arrow-lft-dis.gif (arrow/arrow-lft-dis.gif) skin/classic/global/arrow/arrow-rit.gif (arrow/arrow-rit.gif) skin/classic/global/arrow/arrow-rit-dis.gif (arrow/arrow-rit-dis.gif) + skin/classic/global/arrow/arrow-up-dis.gif (arrow/arrow-up-dis.gif) + skin/classic/global/arrow/arrow-dn-dis.gif (arrow/arrow-dn-dis.gif) skin/classic/global/dirListing/folder.png (dirListing/folder.png) skin/classic/global/dirListing/up.png (dirListing/up.png) skin/classic/global/icons/blacklist_favicon.png (icons/blacklist_favicon.png) diff --git a/toolkit/themes/windows/global/numberbox.css b/toolkit/themes/windows/global/numberbox.css index b5289c4d8237..b3f3c455b6a4 100644 --- a/toolkit/themes/windows/global/numberbox.css +++ b/toolkit/themes/windows/global/numberbox.css @@ -18,7 +18,6 @@ html|*.numberbox-input { text-align: right; } -.numberbox-input-box { - -moz-box-align: center; +textbox[type="number"][hidespinbuttons="true"] > html|*.numberbox-input { + -moz-appearance: textfield !important; } - From 96e5c9837cedc1c63426fb6d137b4a130c5d04ce Mon Sep 17 00:00:00 2001 From: Tim Nguyen Date: Fri, 9 Feb 2018 13:53:49 +0000 Subject: [PATCH 07/41] Bug 1429573 - Remove spinbuttons.xml bindings now that they are unused. r=Paolo MozReview-Commit-ID: 6sb1zcGv4k9 --HG-- extra : rebase_source : 35636617336551fb3aadc8fb321c66b5e5993239 --- accessible/base/Role.h | 2 +- accessible/interfaces/nsIAccessibleRole.idl | 2 +- browser/installer/allowed-dupes.mn | 1 - mobile/android/installer/allowed-dupes.mn | 1 - toolkit/content/jar.mn | 1 - toolkit/content/widgets/spinbuttons.xml | 96 ------------------- toolkit/content/xul.css | 10 -- toolkit/themes/mobile/jar.mn | 1 - toolkit/themes/osx/global/jar.mn | 1 - toolkit/themes/osx/global/spinbuttons.css | 31 ------ toolkit/themes/shared/non-mac.jar.inc.mn | 1 - toolkit/themes/windows/global/spinbuttons.css | 24 ----- 12 files changed, 2 insertions(+), 169 deletions(-) delete mode 100644 toolkit/content/widgets/spinbuttons.xml delete mode 100644 toolkit/themes/osx/global/spinbuttons.css delete mode 100644 toolkit/themes/windows/global/spinbuttons.css diff --git a/accessible/base/Role.h b/accessible/base/Role.h index 2e4a2ff54df9..509de9f392da 100644 --- a/accessible/base/Role.h +++ b/accessible/base/Role.h @@ -345,7 +345,7 @@ enum Role { /** * Represents a spin box, which is a control that allows the user to increment * or decrement the value displayed in a separate "buddy" control associated - * with the spin box. It is used for xul:spinbuttons. + * with the spin box. It is used for input[type=number] spin buttons. */ SPINBUTTON = 52, diff --git a/accessible/interfaces/nsIAccessibleRole.idl b/accessible/interfaces/nsIAccessibleRole.idl index 0cded53abb6a..ac41b865be48 100644 --- a/accessible/interfaces/nsIAccessibleRole.idl +++ b/accessible/interfaces/nsIAccessibleRole.idl @@ -338,7 +338,7 @@ interface nsIAccessibleRole : nsISupports /** * Represents a spin box, which is a control that allows the user to increment * or decrement the value displayed in a separate "buddy" control associated - * with the spin box. It is used for xul:spinbuttons. + * with the spin box. It is used for input[type=number] spin buttons. */ const unsigned long ROLE_SPINBUTTON = 52; diff --git a/browser/installer/allowed-dupes.mn b/browser/installer/allowed-dupes.mn index 0b67197fbcb4..2a8ebd3afb64 100644 --- a/browser/installer/allowed-dupes.mn +++ b/browser/installer/allowed-dupes.mn @@ -113,7 +113,6 @@ chrome/toolkit/skin/classic/global/richlistbox.css chrome/toolkit/skin/classic/global/scale.css chrome/toolkit/skin/classic/global/scrollbars.css chrome/toolkit/skin/classic/global/scrollbox.css -chrome/toolkit/skin/classic/global/spinbuttons.css chrome/toolkit/skin/classic/global/splitter.css chrome/toolkit/skin/classic/global/tabbox.css chrome/toolkit/skin/classic/global/textbox.css diff --git a/mobile/android/installer/allowed-dupes.mn b/mobile/android/installer/allowed-dupes.mn index f8a2210740ee..9959d00e5e27 100644 --- a/mobile/android/installer/allowed-dupes.mn +++ b/mobile/android/installer/allowed-dupes.mn @@ -25,7 +25,6 @@ chrome/toolkit/skin/classic/global/richlistbox.css chrome/toolkit/skin/classic/global/scale.css chrome/toolkit/skin/classic/global/scrollbars.css chrome/toolkit/skin/classic/global/scrollbox.css -chrome/toolkit/skin/classic/global/spinbuttons.css chrome/toolkit/skin/classic/global/splitter.css chrome/toolkit/skin/classic/global/tabbox.css chrome/toolkit/skin/classic/global/textbox.css diff --git a/toolkit/content/jar.mn b/toolkit/content/jar.mn index 6e52f7577c33..f13f8fa43bf8 100644 --- a/toolkit/content/jar.mn +++ b/toolkit/content/jar.mn @@ -94,7 +94,6 @@ toolkit.jar: content/global/bindings/scrollbox.xml (widgets/scrollbox.xml) content/global/bindings/spinner.js (widgets/spinner.js) content/global/bindings/splitter.xml (widgets/splitter.xml) - content/global/bindings/spinbuttons.xml (widgets/spinbuttons.xml) content/global/bindings/stringbundle.xml (widgets/stringbundle.xml) * content/global/bindings/tabbox.xml (widgets/tabbox.xml) content/global/bindings/text.xml (widgets/text.xml) diff --git a/toolkit/content/widgets/spinbuttons.xml b/toolkit/content/widgets/spinbuttons.xml deleted file mode 100644 index 3a695beacffb..000000000000 --- a/toolkit/content/widgets/spinbuttons.xml +++ /dev/null @@ -1,96 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - return document.getAnonymousElementByAttribute(this, "anonid", "increaseButton"); - - - - - return document.getAnonymousElementByAttribute(this, "anonid", "decreaseButton"); - - - - - - - - - - - - - - this.removeAttribute("state"); - - - this.removeAttribute("state"); - - - - - - - - - - diff --git a/toolkit/content/xul.css b/toolkit/content/xul.css index 0831195eb2d6..5d8662b6286a 100644 --- a/toolkit/content/xul.css +++ b/toolkit/content/xul.css @@ -919,16 +919,6 @@ autorepeatbutton { -moz-binding: url("chrome://global/content/bindings/scrollbox.xml#autorepeatbutton"); } -/********** spinbuttons ***********/ - -spinbuttons { - -moz-binding: url("chrome://global/content/bindings/spinbuttons.xml#spinbuttons"); -} - -.spinbuttons-button { - -moz-user-focus: ignore; -} - /********** stringbundle **********/ stringbundleset { diff --git a/toolkit/themes/mobile/jar.mn b/toolkit/themes/mobile/jar.mn index 1e3c9e1e0a13..c3fe3ded869c 100644 --- a/toolkit/themes/mobile/jar.mn +++ b/toolkit/themes/mobile/jar.mn @@ -23,7 +23,6 @@ toolkit.jar: skin/classic/global/richlistbox.css (global/empty.css) skin/classic/global/scale.css (global/empty.css) skin/classic/global/scrollbox.css (global/empty.css) - skin/classic/global/spinbuttons.css (global/empty.css) skin/classic/global/splitter.css (global/empty.css) skin/classic/global/tabbox.css (global/empty.css) skin/classic/global/textbox.css (global/empty.css) diff --git a/toolkit/themes/osx/global/jar.mn b/toolkit/themes/osx/global/jar.mn index 8c249332d2d8..0f4e5fd4dac6 100644 --- a/toolkit/themes/osx/global/jar.mn +++ b/toolkit/themes/osx/global/jar.mn @@ -30,7 +30,6 @@ toolkit.jar: skin/classic/global/richlistbox.css skin/classic/global/scrollbars.css (nativescrollbars.css) skin/classic/global/scrollbox.css - skin/classic/global/spinbuttons.css skin/classic/global/splitter.css skin/classic/global/tabprompts.css skin/classic/global/tabbox.css diff --git a/toolkit/themes/osx/global/spinbuttons.css b/toolkit/themes/osx/global/spinbuttons.css deleted file mode 100644 index bf89520f6812..000000000000 --- a/toolkit/themes/osx/global/spinbuttons.css +++ /dev/null @@ -1,31 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); - -spinbuttons { - height: 24px; - min-height: 24px; - -moz-appearance: spinner; - cursor: default; -} - -.spinbuttons-up { - -moz-appearance: none; - -moz-box-flex: 1; - min-width: 1px; - min-height: 1px; - margin: 0; - padding: 0; -} - -.spinbuttons-down { - -moz-appearance: none; - -moz-box-flex: 1; - min-width: 1px; - min-height: 1px; - margin: 0; - padding: 0; -} - diff --git a/toolkit/themes/shared/non-mac.jar.inc.mn b/toolkit/themes/shared/non-mac.jar.inc.mn index f5809ca5ba1c..4fc04384e6e1 100644 --- a/toolkit/themes/shared/non-mac.jar.inc.mn +++ b/toolkit/themes/shared/non-mac.jar.inc.mn @@ -16,7 +16,6 @@ skin/classic/global/resizer.css (../../windows/global/resizer.css) skin/classic/global/richlistbox.css (../../windows/global/richlistbox.css) skin/classic/global/scrollbars.css (../../windows/global/xulscrollbars.css) - skin/classic/global/spinbuttons.css (../../windows/global/spinbuttons.css) skin/classic/global/tabprompts.css (../../windows/global/tabprompts.css) skin/classic/global/wizard.css (../../windows/global/wizard.css) diff --git a/toolkit/themes/windows/global/spinbuttons.css b/toolkit/themes/windows/global/spinbuttons.css deleted file mode 100644 index 3e333bb47480..000000000000 --- a/toolkit/themes/windows/global/spinbuttons.css +++ /dev/null @@ -1,24 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); - -spinbuttons { - -moz-appearance: spinner; - cursor: default; -} - -.spinbuttons-button { - min-width: 13px; - min-height: 11px; - margin: 0 !important; -} - -.spinbuttons-up { - -moz-appearance: spinner-upbutton; -} - -.spinbuttons-down { - -moz-appearance: spinner-downbutton; -} From ca409ab72de8a961929c86604b8ff626139db273 Mon Sep 17 00:00:00 2001 From: Tom Ritter Date: Fri, 2 Feb 2018 11:05:40 -0600 Subject: [PATCH 08/41] Bug 1435296 Bump the default timer precision resolution to 2ms r=baku MozReview-Commit-ID: G33jNNJVRSU --HG-- extra : rebase_source : 5a07abf77c00b66fad77c1add1b4646f287c6e26 --- modules/libpref/init/all.js | 2 +- toolkit/components/resistfingerprinting/nsRFPService.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index e06bc5f61fbd..4d0e6ed7bf3f 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -1409,7 +1409,7 @@ pref("privacy.resistFingerprinting", false); // File.lastModified, audioContext.currentTime, canvas.captureStream.currentTime pref("privacy.reduceTimerPrecision", true); // Dynamically tune the resolution of the timer reduction for both of the two above prefs -pref("privacy.resistFingerprinting.reduceTimerPrecision.microseconds", 20); +pref("privacy.resistFingerprinting.reduceTimerPrecision.microseconds", 2000); // Lower the priority of network loads for resources on the tracking protection list. // Note that this requires the privacy.trackingprotection.annotate_channels pref to be on in order to have any effect. #ifdef NIGHTLY_BUILD diff --git a/toolkit/components/resistfingerprinting/nsRFPService.cpp b/toolkit/components/resistfingerprinting/nsRFPService.cpp index 6c6d50de2f96..d7de972041df 100644 --- a/toolkit/components/resistfingerprinting/nsRFPService.cpp +++ b/toolkit/components/resistfingerprinting/nsRFPService.cpp @@ -43,7 +43,7 @@ static mozilla::LazyLogModule gResistFingerprintingLog("nsResistFingerprinting") #define RESIST_FINGERPRINTING_PREF "privacy.resistFingerprinting" #define RFP_TIMER_PREF "privacy.reduceTimerPrecision" #define RFP_TIMER_VALUE_PREF "privacy.resistFingerprinting.reduceTimerPrecision.microseconds" -#define RFP_TIMER_VALUE_DEFAULT 20 +#define RFP_TIMER_VALUE_DEFAULT 2000 #define RFP_SPOOFED_FRAMES_PER_SEC_PREF "privacy.resistFingerprinting.video_frames_per_sec" #define RFP_SPOOFED_DROPPED_RATIO_PREF "privacy.resistFingerprinting.video_dropped_ratio" #define RFP_TARGET_VIDEO_RES_PREF "privacy.resistFingerprinting.target_video_res" From b5eec936540f2ee2292efd3aed7c9e4e73309d82 Mon Sep 17 00:00:00 2001 From: Tom Ritter Date: Wed, 7 Feb 2018 16:50:57 -0600 Subject: [PATCH 09/41] Bug 1435296 Do not apply timer clamping to CSS animations. r=birtles This patch creates the capability to have callsites specify if timestamps should be clamped only in Resist Fingerprinting Mode, or in the more expansive Timer PRecision Reduction Mode. Then it changes the CSS Animation callsite to only apply in RFP Mode. This avoids regressing RFP. MozReview-Commit-ID: B1pSri0kRk6 --HG-- extra : rebase_source : 5c1a3a1bb7cb10cd5c4a608f30bf097bd7e119b9 --- dom/animation/AnimationUtils.h | 2 +- .../resistfingerprinting/nsRFPService.cpp | 18 +++++++++++------- .../resistfingerprinting/nsRFPService.h | 19 +++++++++++++++---- 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/dom/animation/AnimationUtils.h b/dom/animation/AnimationUtils.h index 04b5f98812bb..f19e94182ca0 100644 --- a/dom/animation/AnimationUtils.h +++ b/dom/animation/AnimationUtils.h @@ -33,7 +33,7 @@ public: if (!aTime.IsNull()) { result.SetValue( - nsRFPService::ReduceTimePrecisionAsMSecs(aTime.Value().ToMilliseconds()) + nsRFPService::ReduceTimePrecisionAsMSecs(aTime.Value().ToMilliseconds(), TimerPrecisionType::RFPOnly) ); } diff --git a/toolkit/components/resistfingerprinting/nsRFPService.cpp b/toolkit/components/resistfingerprinting/nsRFPService.cpp index d7de972041df..eaf90ab26244 100644 --- a/toolkit/components/resistfingerprinting/nsRFPService.cpp +++ b/toolkit/components/resistfingerprinting/nsRFPService.cpp @@ -107,17 +107,21 @@ nsRFPService::IsResistFingerprintingEnabled() /* static */ bool -nsRFPService::IsTimerPrecisionReductionEnabled() +nsRFPService::IsTimerPrecisionReductionEnabled(TimerPrecisionType aType) { + if (aType == TimerPrecisionType::RFPOnly) { + return IsResistFingerprintingEnabled(); + } + return (sPrivacyTimerPrecisionReduction || IsResistFingerprintingEnabled()) && TimerResolution() != 0; } /* static */ double -nsRFPService::ReduceTimePrecisionAsMSecs(double aTime) +nsRFPService::ReduceTimePrecisionAsMSecs(double aTime, TimerPrecisionType aType /* = TimerPrecisionType::All */) { - if (!IsTimerPrecisionReductionEnabled()) { + if (!IsTimerPrecisionReductionEnabled(aType)) { return aTime; } const double resolutionMSec = TimerResolution() / 1000.0; @@ -132,9 +136,9 @@ nsRFPService::ReduceTimePrecisionAsMSecs(double aTime) /* static */ double -nsRFPService::ReduceTimePrecisionAsUSecs(double aTime) +nsRFPService::ReduceTimePrecisionAsUSecs(double aTime, TimerPrecisionType aType /* = TimerPrecisionType::All */) { - if (!IsTimerPrecisionReductionEnabled()) { + if (!IsTimerPrecisionReductionEnabled(aType)) { return aTime; } double resolutionUSec = TimerResolution(); @@ -157,9 +161,9 @@ nsRFPService::CalculateTargetVideoResolution(uint32_t aVideoQuality) /* static */ double -nsRFPService::ReduceTimePrecisionAsSecs(double aTime) +nsRFPService::ReduceTimePrecisionAsSecs(double aTime, TimerPrecisionType aType /* = TimerPrecisionType::All */) { - if (!IsTimerPrecisionReductionEnabled()) { + if (!IsTimerPrecisionReductionEnabled(aType)) { return aTime; } double resolutionUSec = TimerResolution(); diff --git a/toolkit/components/resistfingerprinting/nsRFPService.h b/toolkit/components/resistfingerprinting/nsRFPService.h index cf17c46ac51c..b491ebe854f3 100644 --- a/toolkit/components/resistfingerprinting/nsRFPService.h +++ b/toolkit/components/resistfingerprinting/nsRFPService.h @@ -148,6 +148,11 @@ public: nsString mKey; }; +enum TimerPrecisionType { + All = 1, + RFPOnly = 2 +}; + class nsRFPService final : public nsIObserver { public: @@ -156,12 +161,18 @@ public: static nsRFPService* GetOrCreate(); static bool IsResistFingerprintingEnabled(); - static bool IsTimerPrecisionReductionEnabled(); + static bool IsTimerPrecisionReductionEnabled(TimerPrecisionType aType); // The following Reduce methods can be called off main thread. - static double ReduceTimePrecisionAsMSecs(double aTime); - static double ReduceTimePrecisionAsUSecs(double aTime); - static double ReduceTimePrecisionAsSecs(double aTime); + static double ReduceTimePrecisionAsMSecs( + double aTime, + TimerPrecisionType aType = TimerPrecisionType::All); + static double ReduceTimePrecisionAsUSecs( + double aTime, + TimerPrecisionType aType = TimerPrecisionType::All); + static double ReduceTimePrecisionAsSecs( + double aTime, + TimerPrecisionType aType = TimerPrecisionType::All); // This method calculates the video resolution (i.e. height x width) based // on the video quality (480p, 720p, etc). From fa5021da771895f43c34fea720ef68cc3b7b6aec Mon Sep 17 00:00:00 2001 From: Tom Ritter Date: Tue, 6 Feb 2018 15:11:56 -0600 Subject: [PATCH 10/41] Bug 1435296 Address test failures caused by bumping timer precision to 2 ms r=baku This affects several tests, and in all but one case merely disables timer precision reduction on those tests. In the other singular test, it no longer requires the end time of an operation to be strictly greater than the start time, and allows it to be equal to it. MozReview-Commit-ID: J59c7xQtZZJ --HG-- extra : rebase_source : c82310ce0269798a9c5bfffaec1f63a24ddc98e5 --- devtools/client/canvasdebugger/test/head.js | 4 ++++ devtools/server/tests/mochitest/memory-helpers.js | 3 +++ docshell/test/chrome/test_bug453650.xul | 4 ++-- dom/events/test/test_eventTimeStamp.html | 13 +++++++++---- ...est_baseline_requirements_subject_common_name.js | 3 +++ security/manager/ssl/tests/unit/test_cert_eku.js | 6 ++++++ .../mediasource-getvideoplaybackquality.html.ini | 1 + .../performance-timeline.https.html.ini | 1 + 8 files changed, 29 insertions(+), 6 deletions(-) diff --git a/devtools/client/canvasdebugger/test/head.js b/devtools/client/canvasdebugger/test/head.js index afe2e3a0376f..203e87caf10a 100644 --- a/devtools/client/canvasdebugger/test/head.js +++ b/devtools/client/canvasdebugger/test/head.js @@ -40,6 +40,9 @@ const RAF_BEGIN_URL = EXAMPLE_URL + "doc_raf-begin.html"; var gEnableLogging = Services.prefs.getBoolPref("devtools.debugger.log"); Services.prefs.setBoolPref("devtools.debugger.log", false); +var gReduceTimePrecision = Services.prefs.getBoolPref("privacy.reduceTimerPrecision"); +Services.prefs.setBoolPref("privacy.reduceTimerPrecision", false); + // All tests are asynchronous. waitForExplicitFinish(); @@ -52,6 +55,7 @@ registerCleanupFunction(() => { flags.testing = false; Services.prefs.setBoolPref("devtools.debugger.log", gEnableLogging); Services.prefs.setBoolPref("devtools.canvasdebugger.enabled", gToolEnabled); + Services.prefs.setBoolPref("privacy.reduceTimerPrecision", gReduceTimePrecision); // Some of yhese tests use a lot of memory due to GL contexts, so force a GC // to help fragmentation. diff --git a/devtools/server/tests/mochitest/memory-helpers.js b/devtools/server/tests/mochitest/memory-helpers.js index 86057bdf57df..ae04f80b3535 100644 --- a/devtools/server/tests/mochitest/memory-helpers.js +++ b/devtools/server/tests/mochitest/memory-helpers.js @@ -12,8 +12,11 @@ const { MemoryFront } = require("devtools/shared/fronts/memory"); // Always log packets when running tests. Services.prefs.setBoolPref("devtools.debugger.log", true); +var gReduceTimePrecision = Services.prefs.getBoolPref("privacy.reduceTimerPrecision"); +Services.prefs.setBoolPref("privacy.reduceTimerPrecision", false); SimpleTest.registerCleanupFunction(function () { Services.prefs.clearUserPref("devtools.debugger.log"); + Services.prefs.setBoolPref("privacy.reduceTimerPrecision", gReduceTimePrecision); }); function startServerAndGetSelectedTabMemory() { diff --git a/docshell/test/chrome/test_bug453650.xul b/docshell/test/chrome/test_bug453650.xul index 32e3ea1df720..4dec60a6112e 100644 --- a/docshell/test/chrome/test_bug453650.xul +++ b/docshell/test/chrome/test_bug453650.xul @@ -60,7 +60,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=453650 } info("times: " + start + ", " + end); - ok(start < end, "reflow start time lower than end time"); + ok(start <= end, "reflow start time lower than end time"); done(); }, @@ -72,7 +72,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=453650 } info("times: " + start + ", " + end); - ok(start < end, "reflow start time lower than end time"); + ok(start <= end, "reflow start time lower than end time"); done(); }, diff --git a/dom/events/test/test_eventTimeStamp.html b/dom/events/test/test_eventTimeStamp.html index fe9b10fa0add..7141562ec1cb 100644 --- a/dom/events/test/test_eventTimeStamp.html +++ b/dom/events/test/test_eventTimeStamp.html @@ -38,9 +38,13 @@ SimpleTest.requestFlakyTimeout("untriaged"); // We don't use SpecialPowers.pushPrefEnv since it can delay the test // function until after the load event has fired which means we can't // test the timestamp of the load event. -const kPrefName = "dom.event.highrestimestamp.enabled"; -var prevPrefValue = SpecialPowers.getBoolPref(kPrefName); -SpecialPowers.setBoolPref(kPrefName, true); +const kHighResTimestampsPrefName = "dom.event.highrestimestamp.enabled"; +var highRestimerPrevPrefValue = SpecialPowers.getBoolPref(kHighResTimestampsPrefName); +SpecialPowers.setBoolPref(kHighResTimestampsPrefName, true); + +const kReduceTimePrecisionPrefName = "privacy.reduceTimerPrecision"; +var reduceTimePrecisionPrevPrefValue = SpecialPowers.getBoolPref(kReduceTimePrecisionPrefName); +SpecialPowers.setBoolPref(kReduceTimePrecisionPrefName, false); testRegularEvents(); // Event.timeStamp should be relative to the time origin which is: @@ -111,7 +115,8 @@ function testSharedWorkerEvents() { } var finishTests = function() { - SpecialPowers.setBoolPref(kPrefName, prevPrefValue); + SpecialPowers.setBoolPref(kHighResTimestampsPrefName, highRestimerPrevPrefValue); + SpecialPowers.setBoolPref(kReduceTimePrecisionPrefName, reduceTimePrecisionPrevPrefValue); SimpleTest.finish(); }; diff --git a/security/manager/ssl/tests/unit/test_baseline_requirements_subject_common_name.js b/security/manager/ssl/tests/unit/test_baseline_requirements_subject_common_name.js index 291f1cf50d1c..26580890f902 100644 --- a/security/manager/ssl/tests/unit/test_baseline_requirements_subject_common_name.js +++ b/security/manager/ssl/tests/unit/test_baseline_requirements_subject_common_name.js @@ -40,8 +40,11 @@ function run_test() { registerCleanupFunction(() => { Services.prefs.clearUserPref("security.pki.name_matching_mode"); Services.prefs.clearUserPref("security.test.built_in_root_hash"); + Services.prefs.clearUserPref("privacy.reduceTimerPrecision"); }); + Services.prefs.setBoolPref("privacy.reduceTimerPrecision", false); + loadCertWithTrust("ca", "CTu,,"); // When verifying a certificate, if the trust anchor is not a built-in root, diff --git a/security/manager/ssl/tests/unit/test_cert_eku.js b/security/manager/ssl/tests/unit/test_cert_eku.js index 65bf584cf9fc..c91df26ba20a 100644 --- a/security/manager/ssl/tests/unit/test_cert_eku.js +++ b/security/manager/ssl/tests/unit/test_cert_eku.js @@ -33,7 +33,13 @@ function checkCertOn25August2016(cert, expectedResult) { certificateUsageSSLServer, VALIDATION_TIME); } + function run_test() { + registerCleanupFunction(() => { + Services.prefs.clearUserPref("privacy.reduceTimerPrecision"); + }); + Services.prefs.setBoolPref("privacy.reduceTimerPrecision", false); + loadCertWithTrust("ca", "CTu,,"); // end-entity has id-kp-serverAuth => success checkEndEntity(certFromFile("ee-SA"), PRErrorCodeSuccess); diff --git a/testing/web-platform/meta/media-source/mediasource-getvideoplaybackquality.html.ini b/testing/web-platform/meta/media-source/mediasource-getvideoplaybackquality.html.ini index 79384c3d0ed3..caa5317f627f 100644 --- a/testing/web-platform/meta/media-source/mediasource-getvideoplaybackquality.html.ini +++ b/testing/web-platform/meta/media-source/mediasource-getvideoplaybackquality.html.ini @@ -1,3 +1,4 @@ +prefs: [privacy.reduceTimerPrecision:false] [mediasource-getvideoplaybackquality.html] [Test the totalFrameDelay attribute of HTMLVideoElement.getVideoPlaybackQuality() with MediaSource API] expected: FAIL diff --git a/testing/web-platform/meta/service-workers/service-worker/performance-timeline.https.html.ini b/testing/web-platform/meta/service-workers/service-worker/performance-timeline.https.html.ini index 5ad18e9a06ff..d7cc3b02a95f 100644 --- a/testing/web-platform/meta/service-workers/service-worker/performance-timeline.https.html.ini +++ b/testing/web-platform/meta/service-workers/service-worker/performance-timeline.https.html.ini @@ -1,3 +1,4 @@ +prefs: [privacy.reduceTimerPrecision:false] [performance-timeline.https.html] expected: TIMEOUT [Resource Timing] From 0c3763404df2cd9897d2a3b9a3afb4ec5fd4309e Mon Sep 17 00:00:00 2001 From: Tom Ritter Date: Wed, 7 Feb 2018 20:35:38 -0600 Subject: [PATCH 11/41] Bug 1435296 Update the CSS Animations tests to handle our new Timer Precision decision r=baku This commit does several subtle things. 1: It changes ok() to opener.ok() ok is not defined, we have to use opener.ok. This was not caught before because this call is used to provide additional debugging information when a test fails. Test didn't fail, didn't hit that line. 2: It disables the call to opener.ok() we just fixed. As the comment there describes, we expect that function to fail, so we don't want to assert(false). 3: It inverts failures to successes if only the reduceTimerPrecision pref is set MozReview-Commit-ID: lpKKhJoDs6 --HG-- extra : rebase_source : 01386c0a91dd5262cbee95ecbd0be6df5539006a --- .../test/mochitest/file_animation_api.html | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/browser/components/resistfingerprinting/test/mochitest/file_animation_api.html b/browser/components/resistfingerprinting/test/mochitest/file_animation_api.html index 7b1cbad80d82..789afecbe94f 100644 --- a/browser/components/resistfingerprinting/test/mochitest/file_animation_api.html +++ b/browser/components/resistfingerprinting/test/mochitest/file_animation_api.html @@ -52,9 +52,11 @@ } } - ok(false, "Looming Test Failure, Additional Debugging Info: Expected Precision: " + expectedPrecision + " Measured Value: " + x + - " Rounded Vaue: " + rounded + " Fuzzy1: " + Math.abs(rounded - x + expectedPrecision) + - " Fuzzy 2: " + Math.abs(rounded - x)); + // We are temporarily disabling this extra debugging failure because we expect to return false in some instances + // When we correct things we will re-enable it for debugging assistance + // opener.ok(false, "Looming Test Failure, Additional Debugging Info: Expected Precision: " + expectedPrecision + " Measured Value: " + x + + // " Rounded Vaue: " + rounded + " Fuzzy1: " + Math.abs(rounded - x + expectedPrecision) + + // " Fuzzy 2: " + Math.abs(rounded - x)); return false; }; @@ -65,14 +67,24 @@ waitForCondition( () => animation.currentTime > 100, () => { - opener.ok(isRounded(animation.startTime), + + // We have disabled Time Precision Reduction for CSS Animations, so we expect those tests to fail. + // If we are testing that preference, turn failures into successes and successes into failures + var maybeInvert = function(value) { + if (opener.prefName.includes("privacy.reduceTimerPrecision") && + !opener.prefName.includes("privacy.resistFingerprinting")) + return !value; + return value; + }; + + opener.ok(maybeInvert(isRounded(animation.startTime)), "pref: " + opener.prefName + " - animation.startTime with precision " + expectedPrecision + " is not rounded: " + animation.startTime); - opener.ok(isRounded(animation.currentTime), + opener.ok(maybeInvert(isRounded(animation.currentTime)), "pref: " + opener.prefName + " - animation.currentTime with precision " + expectedPrecision + " is not rounded: " + animation.currentTime); - opener.ok(isRounded(animation.timeline.currentTime), + opener.ok(maybeInvert(isRounded(animation.timeline.currentTime)), "pref: " + opener.prefName + " - animation.timeline.currentTime with precision " + expectedPrecision + " is not rounded: " + animation.timeline.currentTime); if (document.timeline) { - opener.ok(isRounded(document.timeline.currentTime), + opener.ok(maybeInvert(isRounded(document.timeline.currentTime)), "pref: " + opener.prefName + " - document.timeline.currentTime with precision " + expectedPrecision + " is not rounded: " + document.timeline.currentTime); } opener.done(); From ee6fffd33436b43e42985decb524a7e7e543e524 Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Wed, 31 Jan 2018 20:00:29 -0500 Subject: [PATCH 12/41] Bug 1412332 - Enable sync passwords validator for nightly and beta users. r=markh This also fixes an issue where our engine enabled preference listener was overzealous. MozReview-Commit-ID: DphLaEUkyOz --HG-- extra : rebase_source : fdcf154adf2cb11ac3bb0140670ce2dce68f4586 --- services/sync/modules/engines/passwords.js | 4 ++++ services/sync/modules/service.js | 5 +++++ services/sync/services-sync.js | 4 ++++ 3 files changed, 13 insertions(+) diff --git a/services/sync/modules/engines/passwords.js b/services/sync/modules/engines/passwords.js index b0d8108d64c9..a15ad6ca5725 100644 --- a/services/sync/modules/engines/passwords.js +++ b/services/sync/modules/engines/passwords.js @@ -378,6 +378,10 @@ PasswordTracker.prototype = { } }, + getValidator() { + return new PasswordValidator(); + }, + async _trackLogin(login) { if (Utils.getSyncCredentialsHosts().has(login.hostname)) { // Skip over Weave password/passphrase changes. diff --git a/services/sync/modules/service.js b/services/sync/modules/service.js index 7319fcfee751..6d418abe562e 100644 --- a/services/sync/modules/service.js +++ b/services/sync/modules/service.js @@ -451,6 +451,11 @@ Sync11Service.prototype = { return; } const engine = data.slice((PREFS_BRANCH + "engine.").length); + if (engine.includes(".")) { + // A sub-preference of the engine was changed. For example + // `services.sync.engine.bookmarks.validation.percentageChance`. + return; + } this._handleEngineStatusChanged(engine); break; } diff --git a/services/sync/services-sync.js b/services/sync/services-sync.js index a13ba881eb02..72ac494c4704 100644 --- a/services/sync/services-sync.js +++ b/services/sync/services-sync.js @@ -78,6 +78,7 @@ pref("services.sync.telemetry.maxPayloadCount", 500); // Enable the (fairly costly) client/server validation through early Beta, but // not release candidates or Release. pref("services.sync.engine.bookmarks.validation.enabled", true); +pref("services.sync.engine.passwords.validation.enabled", true); #endif #if defined(NIGHTLY_BUILD) @@ -89,14 +90,17 @@ pref("services.sync.engine.bookmarks.repair.enabled", true); // We consider validation this frequently. After considering validation, even // if we don't end up validating, we won't try again unless this much time has passed. pref("services.sync.engine.bookmarks.validation.interval", 86400); // 24 hours in seconds +pref("services.sync.engine.passwords.validation.interval", 86400); // 24 hours in seconds // We only run validation `services.sync.validation.percentageChance` percent of // the time, even if it's been the right amount of time since the last validation, // and you meet the maxRecord checks. pref("services.sync.engine.bookmarks.validation.percentageChance", 10); +pref("services.sync.engine.passwords.validation.percentageChance", 10); // We won't validate an engine if it has more than this many records on the server. pref("services.sync.engine.bookmarks.validation.maxRecords", 1000); +pref("services.sync.engine.passwords.validation.maxRecords", 1000); // The maximum number of immediate resyncs to trigger for changes made during // a sync. From 6bebb6d5f889f6e0ce21b0f68f2598be2bb4c006 Mon Sep 17 00:00:00 2001 From: Kit Cambridge Date: Thu, 8 Feb 2018 11:50:02 -0800 Subject: [PATCH 13/41] Bug 1436837 - Always prefer the local value state for synced roots. r=mak Currently, the mirror treat roots like any other folder, and applies remote value changes like titles, descriptions, and creation dates. We should instead treat roots as immutable, and only apply new structure states, to match the behavior of the legacy engine, iOS, and Android. This has a semantic change: if a root is changed locally, but we dedupe all its children to match the remote tree, we'll still reupload a record for the root. However, this change is consistent with the legacy engine, as well as how we handle orphans moved into a locally modified "unfiled". MozReview-Commit-ID: 6hi0VcrG9ew --HG-- extra : rebase_source : d72550ea3c8f82ab6a33654a021d55c487fbcd46 --- .../places/SyncedBookmarksMirror.jsm | 117 ++++++++++-------- .../tests/sync/test_bookmark_corruption.js | 6 - .../tests/sync/test_bookmark_deduping.js | 11 +- .../tests/sync/test_bookmark_deletion.js | 11 -- .../places/tests/sync/test_bookmark_kinds.js | 22 +++- .../sync/test_bookmark_structure_changes.js | 12 -- .../tests/sync/test_bookmark_value_changes.js | 16 +-- 7 files changed, 91 insertions(+), 104 deletions(-) diff --git a/toolkit/components/places/SyncedBookmarksMirror.jsm b/toolkit/components/places/SyncedBookmarksMirror.jsm index 1db0b544f93c..c71609626fee 100644 --- a/toolkit/components/places/SyncedBookmarksMirror.jsm +++ b/toolkit/components/places/SyncedBookmarksMirror.jsm @@ -1030,10 +1030,10 @@ class SyncedBookmarksMirror { valueState: BookmarkMergeState.TYPE.REMOTE }); await this.db.execute(`DELETE FROM moz_updatehostsinsert_temp`); - // Deleting from `newRemoteItems` fires the `insertNewLocalItems` and + // Deleting from `itemsToMerge` fires the `insertNewLocalItems` and // `updateExistingLocalItems` triggers. MirrorLog.debug("Updating value states for local bookmarks"); - await this.db.execute(`DELETE FROM newRemoteItems`); + await this.db.execute(`DELETE FROM itemsToMerge`); // Update the structure. The mirror stores structure info in a separate // table, like iOS, while Places stores structure info on children. We don't @@ -1042,7 +1042,7 @@ class SyncedBookmarksMirror { // without parents to "unfiled". In that case, we *don't* want to reupload // the new local structure to the server. MirrorLog.debug("Updating structure states for local bookmarks"); - await this.db.execute(`DELETE FROM newRemoteStructure`); + await this.db.execute(`DELETE FROM structureToMerge`); MirrorLog.debug("Removing remotely deleted items from Places"); for (let chunk of PlacesSyncUtils.chunkArray(localDeletions, @@ -1860,7 +1860,7 @@ async function createMirrorRoots(db) { * Creates temporary tables, views, and triggers to apply the mirror to Places. * * The bulk of the logic to apply all remotely changed items is defined in - * `INSTEAD OF DELETE` triggers on the `newRemoteItems` and `newRemoteStructure` + * `INSTEAD OF DELETE` triggers on the `itemsToMerge` and `structureToMerge` * views. When we execute `DELETE FROM newRemote{Items, Structure}`, SQLite * fires the triggers for each row in the view. This is equivalent to, but more * efficient than, issuing `SELECT * FROM newRemote{Items, Structure}`, @@ -1879,23 +1879,23 @@ async function initializeTempMirrorEntities(db) { // `updateExistingLocalItems` triggers below. const syncedAnnoTriggers = [{ annoName: PlacesSyncUtils.bookmarks.DESCRIPTION_ANNO, - columnName: "description", + columnName: "newDescription", type: PlacesUtils.annotations.TYPE_STRING, }, { annoName: PlacesSyncUtils.bookmarks.SIDEBAR_ANNO, - columnName: "loadInSidebar", + columnName: "newLoadInSidebar", type: PlacesUtils.annotations.TYPE_INT32, }, { annoName: PlacesSyncUtils.bookmarks.SMART_BOOKMARKS_ANNO, - columnName: "smartBookmarkName", + columnName: "newSmartBookmarkName", type: PlacesUtils.annotations.TYPE_STRING, }, { annoName: PlacesUtils.LMANNO_FEEDURI, - columnName: "feedURL", + columnName: "newFeedURL", type: PlacesUtils.annotations.TYPE_STRING, }, { annoName: PlacesUtils.LMANNO_SITEURI, - columnName: "siteURL", + columnName: "newSiteURL", type: PlacesUtils.annotations.TYPE_STRING, }]; @@ -1916,14 +1916,14 @@ async function initializeTempMirrorEntities(db) { // moz_bookmarks`, because `REPLACE` doesn't fire the `AFTER DELETE` triggers // that Places uses to maintain schema coherency. await db.execute(` - CREATE TEMP VIEW newRemoteItems(localId, remoteId, localGuid, mergedGuid, - mergedLevel, needsUpdate, type, dateAdded, - title, oldPlaceId, newPlaceId, newKeyword, - description, loadInSidebar, - smartBookmarkName, feedURL, siteURL, - syncChangeCounter) AS - SELECT b.id, v.id, r.localGuid, r.mergedGuid, r.level, - r.valueState = ${BookmarkMergeState.TYPE.REMOTE}, + CREATE TEMP VIEW itemsToMerge(localId, remoteId, hasRemoteValue, newLevel, + oldGuid, newGuid, newType, newDateAdded, + newTitle, oldPlaceId, newPlaceId, newKeyword, + newDescription, newLoadInSidebar, + newSmartBookmarkName, newFeedURL, + newSiteURL) AS + SELECT b.id, v.id, r.valueState = ${BookmarkMergeState.TYPE.REMOTE}, + r.level, r.localGuid, r.mergedGuid, (CASE WHEN v.kind IN (${[ SyncedBookmarksMirror.KIND.BOOKMARK, SyncedBookmarksMirror.KIND.QUERY, @@ -1936,9 +1936,7 @@ async function initializeTempMirrorEntities(db) { (CASE WHEN b.dateAdded < v.dateAdded THEN b.dateAdded ELSE v.dateAdded END), v.title, h.id, u.newPlaceId, v.keyword, v.description, - v.loadInSidebar, v.smartBookmarkName, v.feedURL, v.siteURL, - (CASE r.structureState WHEN ${BookmarkMergeState.TYPE.REMOTE} THEN 0 - ELSE 1 END) + v.loadInSidebar, v.smartBookmarkName, v.feedURL, v.siteURL FROM items v JOIN mergeStates r ON r.mergedGuid = v.guid LEFT JOIN moz_bookmarks b ON b.guid = r.localGuid @@ -1953,37 +1951,38 @@ async function initializeTempMirrorEntities(db) { // Changes local GUIDs to remote GUIDs, drops local tombstones for revived // remote items, and flags remote items as merged. In the trigger body, `OLD` - // refers to the row for the unmerged item in `newRemoteItems`. + // refers to the row for the unmerged item in `itemsToMerge`. await db.execute(` CREATE TEMP TRIGGER mergeGuids - INSTEAD OF DELETE ON newRemoteItems + INSTEAD OF DELETE ON itemsToMerge BEGIN /* We update GUIDs here, instead of in the "updateExistingLocalItems" trigger, because deduped items where we're keeping the local value state won't have "needsMerge" set. */ UPDATE moz_bookmarks SET - guid = OLD.mergedGuid - WHERE OLD.localGuid <> OLD.mergedGuid AND - guid = OLD.localGuid; + guid = OLD.newGuid + WHERE OLD.oldGuid <> OLD.newGuid AND + id = OLD.localId; /* Record item changed notifications for the updated GUIDs. */ INSERT INTO guidsChanged(itemId, oldGuid, level) - SELECT OLD.localId, OLD.localGuid, OLD.mergedLevel - WHERE OLD.localGuid <> OLD.mergedGuid; + SELECT OLD.localId, OLD.oldGuid, OLD.newLevel + WHERE OLD.oldGuid <> OLD.newGuid; - DELETE FROM moz_bookmarks_deleted WHERE guid = OLD.mergedGuid; + /* Drop local tombstones for revived remote items. */ + DELETE FROM moz_bookmarks_deleted WHERE guid = OLD.newGuid; /* Flag the remote item as merged. */ UPDATE items SET needsMerge = 0 WHERE needsMerge AND - guid = OLD.mergedGuid; + id = OLD.remoteId; END`); // Inserts items from the mirror that don't exist locally. await db.execute(` CREATE TEMP TRIGGER insertNewLocalItems - INSTEAD OF DELETE ON newRemoteItems WHEN OLD.localId IS NULL + INSTEAD OF DELETE ON itemsToMerge WHEN OLD.localId IS NULL BEGIN /* Sync associates keywords with bookmarks, and doesn't sync POST data; Places associates keywords with (URL, POST data) pairs, and multiple @@ -2024,14 +2023,14 @@ async function initializeTempMirrorEntities(db) { INSERT INTO moz_bookmarks(guid, parent, position, type, fk, title, dateAdded, lastModified, syncStatus, syncChangeCounter) - VALUES(OLD.mergedGuid, -1, -1, OLD.type, OLD.newPlaceId, OLD.title, - OLD.dateAdded, STRFTIME('%s', 'now', 'localtime', 'utc') * 1000000, - ${PlacesUtils.bookmarks.SYNC_STATUS.NORMAL}, - OLD.syncChangeCounter); + VALUES(OLD.newGuid, -1, -1, OLD.newType, OLD.newPlaceId, OLD.newTitle, + OLD.newDateAdded, + STRFTIME('%s', 'now', 'localtime', 'utc') * 1000000, + ${PlacesUtils.bookmarks.SYNC_STATUS.NORMAL}, 0); /* Record an item added notification for the new item. */ INSERT INTO itemsAdded(guid, level) - VALUES(OLD.mergedGuid, OLD.mergedLevel); + VALUES(OLD.newGuid, OLD.newLevel); /* Insert new keywords after the item, so that "noteKeywordAdded" can find the new item by Place ID. */ @@ -2042,7 +2041,7 @@ async function initializeTempMirrorEntities(db) { /* Record item changed notifications for the new keyword. */ INSERT INTO keywordsChanged(itemId, placeId, keyword) SELECT b.id, OLD.newPlaceId, OLD.newKeyword FROM moz_bookmarks b - WHERE b.guid = OLD.mergedGuid AND + WHERE b.guid = OLD.newGuid AND OLD.newKeyword NOT NULL; /* Insert new tags for the URL. */ @@ -2062,7 +2061,7 @@ async function initializeTempMirrorEntities(db) { INSERT INTO moz_items_annos(item_id, anno_attribute_id, content, flags, expiration, type, lastModified, dateAdded) SELECT (SELECT id FROM moz_bookmarks - WHERE guid = OLD.mergedGuid), + WHERE guid = OLD.newGuid), (SELECT id FROM moz_anno_attributes WHERE name = '${annoTrigger.annoName}'), OLD.${annoTrigger.columnName}, 0, @@ -2074,7 +2073,7 @@ async function initializeTempMirrorEntities(db) { /* Record an anno set notification for the new synced anno. */ REPLACE INTO annosChanged(itemId, annoName, wasRemoved) SELECT b.id, '${annoTrigger.annoName}', 0 FROM moz_bookmarks b - WHERE b.guid = OLD.mergedGuid AND + WHERE b.guid = OLD.newGuid AND OLD.${annoTrigger.columnName} NOT NULL; `).join("")} END`); @@ -2082,20 +2081,20 @@ async function initializeTempMirrorEntities(db) { // Updates existing items with new values from the mirror. await db.execute(` CREATE TEMP TRIGGER updateExistingLocalItems - INSTEAD OF DELETE ON newRemoteItems WHEN OLD.needsUpdate AND - OLD.localId NOT NULL + INSTEAD OF DELETE ON itemsToMerge WHEN OLD.hasRemoteValue AND + OLD.localId NOT NULL BEGIN /* Record item changed notifications for the title and URL. */ INSERT INTO itemsChanged(itemId, oldTitle, oldPlaceId, level) - SELECT id, title, OLD.oldPlaceId, OLD.mergedLevel FROM moz_bookmarks + SELECT id, title, OLD.oldPlaceId, OLD.newLevel FROM moz_bookmarks WHERE id = OLD.localId; UPDATE moz_bookmarks SET - title = OLD.title, - dateAdded = OLD.dateAdded, + title = OLD.newTitle, + dateAdded = OLD.newDateAdded, lastModified = STRFTIME('%s', 'now', 'localtime', 'utc') * 1000000, syncStatus = ${PlacesUtils.bookmarks.SYNC_STATUS.NORMAL}, - syncChangeCounter = OLD.syncChangeCounter + syncChangeCounter = 0 WHERE id = OLD.localId; /* Bump the change counter for items with the old URL, new URL, and new @@ -2194,7 +2193,7 @@ async function initializeTempMirrorEntities(db) { `).join("")} END`); - // A view of the new structure state for all items in the merged tree. The + // A view of the structure states for all items in the merged tree. The // mirror stores structure info in a separate table, like iOS, while Places // stores structure info on children. Unlike iOS, we can't simply check the // parent's merge state to know if its children changed. This is because our @@ -2203,18 +2202,20 @@ async function initializeTempMirrorEntities(db) { // case, we want to keep syncing, but *don't* want to reupload the new local // structure to the server. await db.execute(` - CREATE TEMP VIEW newRemoteStructure(localId, oldParentId, newParentId, - oldPosition, newPosition, newLevel) AS - SELECT b.id, b.parent, p.id, b.position, r.position, r.level + CREATE TEMP VIEW structureToMerge(localId, hasNewStructure, isRoot, + oldParentId, newParentId, oldPosition, + newPosition, newLevel) AS + SELECT b.id, r.structureState = ${BookmarkMergeState.TYPE.NEW}, + '${PlacesUtils.bookmarks.rootGuid}' IN (r.mergedGuid, r.parentGuid), + b.parent, p.id, b.position, r.position, r.level FROM moz_bookmarks b JOIN mergeStates r ON r.mergedGuid = b.guid - JOIN moz_bookmarks p ON p.guid = r.parentGuid - WHERE r.parentGuid <> '${PlacesUtils.bookmarks.rootGuid}'`); + JOIN moz_bookmarks p ON p.guid = r.parentGuid`); // Updates all parents and positions to reflect the merged tree. await db.execute(` CREATE TEMP TRIGGER updateLocalStructure - INSTEAD OF DELETE ON newRemoteStructure + INSTEAD OF DELETE ON structureToMerge WHEN NOT OLD.isRoot BEGIN UPDATE moz_bookmarks SET parent = OLD.newParentId @@ -2240,6 +2241,17 @@ async function initializeTempMirrorEntities(db) { OLD.oldPosition <> OLD.newPosition); END`); + // Bump the change counter for folders with new structure state, so that + // they're reuploaded to the server. + await db.execute(` + CREATE TEMP TRIGGER flagNewStructure + INSTEAD OF DELETE ON structureToMerge WHEN OLD.hasNewStructure + BEGIN + UPDATE moz_bookmarks SET + syncChangeCounter = syncChangeCounter + 1 + WHERE id = OLD.localId; + END`); + // A view of local bookmark tags. Tags, like keywords, are associated with // URLs, so two bookmarks with the same URL should have the same tags. Unlike // keywords, one tag may be associated with many different URLs. Tags are also @@ -3269,6 +3281,9 @@ class BookmarkMerger { * The two-way merge state. */ resolveTwoWayValueConflict(mergedGuid, localNode, remoteNode) { + if (PlacesUtils.bookmarks.userContentRoots.includes(mergedGuid)) { + return BookmarkMergeState.local; + } if (!remoteNode.needsMerge) { // The node wasn't changed remotely since the last sync. Keep the local // state. diff --git a/toolkit/components/places/tests/sync/test_bookmark_corruption.js b/toolkit/components/places/tests/sync/test_bookmark_corruption.js index 70611f812377..d2850056b74d 100644 --- a/toolkit/components/places/tests/sync/test_bookmark_corruption.js +++ b/toolkit/components/places/tests/sync/test_bookmark_corruption.js @@ -9,7 +9,6 @@ add_task(async function test_missing_children() { await buf.store(shuffle([{ id: "menu", type: "folder", - title: "Bookmarks Menu", children: ["bookmarkBBBB", "bookmarkCCCC", "bookmarkDDDD", "bookmarkEEEE"], }, { @@ -330,7 +329,6 @@ add_task(async function test_new_orphan_without_local_parent() { await buf.store([{ id: "menu", type: "folder", - title: "Bookmarks Menu", children: ["folderEEEEEE"], }]); @@ -446,7 +444,6 @@ add_task(async function test_move_into_orphaned() { await buf.store([{ id: "menu", type: "folder", - title: "Bookmarks Menu", children: ["bookmarkAAAA", "bookmarkBBBB", "folderCCCCCC"], }, { id: "bookmarkAAAA", @@ -624,7 +621,6 @@ add_task(async function test_new_orphan_with_local_parent() { await buf.store(shuffle([{ id: "menu", type: "folder", - title: "Bookmarks Menu", children: ["folderAAAAAA"], }, { id: "folderAAAAAA", @@ -822,7 +818,6 @@ add_task(async function test_partial_cycle() { await buf.store(shuffle([{ id: "menu", type: "folder", - title: "Bookmarks Menu", children: ["folderAAAAAA"], }, { id: "folderAAAAAA", @@ -932,7 +927,6 @@ add_task(async function test_complete_cycle() { await buf.store([{ id: "menu", type: "folder", - title: "Bookmarks Menu", children: ["folderAAAAAA"], }, { id: "folderAAAAAA", diff --git a/toolkit/components/places/tests/sync/test_bookmark_deduping.js b/toolkit/components/places/tests/sync/test_bookmark_deduping.js index 53ad39ceb476..e2865d4c26ce 100644 --- a/toolkit/components/places/tests/sync/test_bookmark_deduping.js +++ b/toolkit/components/places/tests/sync/test_bookmark_deduping.js @@ -20,7 +20,6 @@ add_task(async function test_duping() { await buf.store(shuffle([{ id: "menu", type: "folder", - title: "Bookmarks Menu", children: ["folderAAAAAA"], }, { id: "folderAAAAAA", @@ -85,7 +84,6 @@ add_task(async function test_duping() { await buf.store(shuffle([{ id: "menu", type: "folder", - title: "Bookmarks Menu", children: ["folderAAAAAA", "folderB11111", "folderA11111", "separatorE11", "queryD111111"], }, { @@ -252,7 +250,6 @@ add_task(async function test_applying_two_empty_folders_doesnt_smush() { await buf.store(shuffle([{ id: "mobile", type: "folder", - title: "mobile", children: ["emptyempty01", "emptyempty02"], }, { id: "emptyempty01", @@ -321,7 +318,6 @@ add_task(async function test_applying_two_empty_folders_matches_only_one() { await buf.store(shuffle([{ id: "mobile", type: "folder", - title: "mobile", children: ["emptyempty01", "emptyempty02", "emptyempty03"], }, { id: "emptyempty01", @@ -343,7 +339,7 @@ add_task(async function test_applying_two_empty_folders_matches_only_one() { let idsToUpload = inspectChangeRecords(changesToUpload); deepEqual(idsToUpload, { - updated: [], + updated: ["mobile"], deleted: [], }, "Should not upload records after applying empty folders"); @@ -400,7 +396,6 @@ add_task(async function test_duping_mobile_bookmarks() { await buf.store(shuffle([{ id: "mobile", type: "folder", - title: "Mobile Bookmarks", children: ["bookmarkAAAA"], }, { id: "bookmarkAAAA", @@ -415,7 +410,7 @@ add_task(async function test_duping_mobile_bookmarks() { let idsToUpload = inspectChangeRecords(changesToUpload); deepEqual(idsToUpload, { - updated: [], + updated: ["mobile"], deleted: [], }, "Should not upload records after applying deduped mobile bookmark"); @@ -423,7 +418,7 @@ add_task(async function test_duping_mobile_bookmarks() { guid: PlacesUtils.bookmarks.mobileGuid, type: PlacesUtils.bookmarks.TYPE_FOLDER, index: 4, - title: "Mobile Bookmarks", + title: "Favoritos do celular", children: [{ guid: "bookmarkAAAA", type: PlacesUtils.bookmarks.TYPE_BOOKMARK, diff --git a/toolkit/components/places/tests/sync/test_bookmark_deletion.js b/toolkit/components/places/tests/sync/test_bookmark_deletion.js index 86bfdf068772..1297383b2af2 100644 --- a/toolkit/components/places/tests/sync/test_bookmark_deletion.js +++ b/toolkit/components/places/tests/sync/test_bookmark_deletion.js @@ -20,7 +20,6 @@ add_task(async function test_complex_orphaning() { await buf.store(shuffle([{ id: "toolbar", type: "folder", - title: "Bookmarks Toolbar", children: ["folderAAAAAA"], }, { id: "folderAAAAAA", @@ -53,7 +52,6 @@ add_task(async function test_complex_orphaning() { await buf.store(shuffle([{ id: "menu", type: "folder", - title: "Bookmarks Menu", children: ["folderGGGGGG"], }, { id: "folderGGGGGG", @@ -210,7 +208,6 @@ add_task(async function test_locally_modified_remotely_deleted() { await buf.store([{ id: "menu", type: "folder", - title: "Bookmarks Menu", children: ["bookmarkAAAA", "folderBBBBBB"], }, { id: "bookmarkAAAA", @@ -263,7 +260,6 @@ add_task(async function test_locally_modified_remotely_deleted() { await buf.store([{ id: "menu", type: "folder", - title: "Bookmarks Menu", children: [], }, { id: "bookmarkAAAA", @@ -356,7 +352,6 @@ add_task(async function test_locally_deleted_remotely_modified() { await buf.store([{ id: "menu", type: "folder", - title: "Bookmarks Menu", children: ["bookmarkAAAA", "folderBBBBBB"], }, { id: "bookmarkAAAA", @@ -488,7 +483,6 @@ add_task(async function test_move_to_new_then_delete() { await buf.store(shuffle([{ id: "menu", type: "folder", - title: "Bookmarks Menu", children: ["folderAAAAAA"], }, { id: "folderAAAAAA", @@ -687,7 +681,6 @@ add_task(async function test_clear_folder_then_delete() { await buf.store([{ id: "menu", type: "folder", - title: "Bookmarks Menu", children: ["folderAAAAAA", "bookmarkDDDD"], }, { id: "folderAAAAAA", @@ -739,12 +732,10 @@ add_task(async function test_clear_folder_then_delete() { await buf.store([{ id: "menu", type: "folder", - title: "Bookmarks Menu", children: ["bookmarkBBBB", "bookmarkDDDD"], }, { id: "unfiled", type: "folder", - title: "Other Bookmarks", children: ["bookmarkCCCC"], }, { id: "folderAAAAAA", @@ -850,7 +841,6 @@ add_task(async function test_newer_move_to_deleted() { await buf.store([{ id: "menu", type: "folder", - title: "Bookmarks Menu", children: ["folderAAAAAA", "folderCCCCCC"], }, { id: "folderAAAAAA", @@ -915,7 +905,6 @@ add_task(async function test_newer_move_to_deleted() { }, { id: "toolbar", type: "folder", - title: "Bookmarks Toolbar", children: ["bookmarkBBBB"], modified: (now / 1000) - 5, }, { diff --git a/toolkit/components/places/tests/sync/test_bookmark_kinds.js b/toolkit/components/places/tests/sync/test_bookmark_kinds.js index 9ee2840090b4..53a92a6260c7 100644 --- a/toolkit/components/places/tests/sync/test_bookmark_kinds.js +++ b/toolkit/components/places/tests/sync/test_bookmark_kinds.js @@ -20,7 +20,6 @@ add_task(async function test_livemarks() { await buf.store(shuffle([{ id: "menu", type: "folder", - title: "Bookmarks Menu", children: ["livemarkAAAA"], }, { id: "livemarkAAAA", @@ -55,12 +54,10 @@ add_task(async function test_livemarks() { }, { id: "toolbar", type: "folder", - title: "Bookmarks Toolbar", children: ["livemarkCCCC", "livemarkB111"], }, { id: "unfiled", type: "folder", - title: "Other Bookmarks", children: ["livemarkEEEE"], }, { id: "livemarkCCCC", @@ -86,6 +83,8 @@ add_task(async function test_livemarks() { let menuInfo = await PlacesUtils.bookmarks.fetch( PlacesUtils.bookmarks.menuGuid); + let toolbarInfo = await PlacesUtils.bookmarks.fetch( + PlacesUtils.bookmarks.toolbarGuid); deepEqual(changesToUpload, { livemarkDDDD: { tombstone: false, @@ -105,7 +104,7 @@ add_task(async function test_livemarks() { }, menu: { tombstone: false, - counter: 1, + counter: 2, synced: false, cleartext: { id: "menu", @@ -118,6 +117,21 @@ add_task(async function test_livemarks() { children: ["livemarkAAAA", "livemarkDDDD"], }, }, + toolbar: { + tombstone: false, + counter: 1, + synced: false, + cleartext: { + id: "toolbar", + type: "folder", + parentid: "places", + hasDupe: false, + parentName: "", + dateAdded: toolbarInfo.dateAdded.getTime(), + title: toolbarInfo.title, + children: ["livemarkCCCC", "livemarkB111"], + }, + }, }, "Should upload new local livemark A"); await assertLocalTree(PlacesUtils.bookmarks.rootGuid, { diff --git a/toolkit/components/places/tests/sync/test_bookmark_structure_changes.js b/toolkit/components/places/tests/sync/test_bookmark_structure_changes.js index 1246e89453ad..411dc0fa2a60 100644 --- a/toolkit/components/places/tests/sync/test_bookmark_structure_changes.js +++ b/toolkit/components/places/tests/sync/test_bookmark_structure_changes.js @@ -31,7 +31,6 @@ add_task(async function test_value_structure_conflict() { await buf.store(shuffle([{ id: "menu", type: "folder", - title: "Bookmarks Menu", children: ["folderAAAAAA", "folderDDDDDD"], modified: Date.now() / 1000 - 60, }, { @@ -219,12 +218,10 @@ add_task(async function test_move() { await buf.store(shuffle([{ id: "unfiled", type: "folder", - title: "Other Bookmarks", children: ["mozFolder___"], }, { id: "toolbar", type: "folder", - title: "Bookmarks Toolbar", children: ["devFolder___"], }, { id: "devFolder___", @@ -452,7 +449,6 @@ add_task(async function test_move_into_parent_sibling() { await buf.store(shuffle([{ id: "menu", type: "folder", - title: "Bookmarks Menu", children: ["folderAAAAAA"], }, { id: "folderAAAAAA", @@ -471,7 +467,6 @@ add_task(async function test_move_into_parent_sibling() { await buf.store([{ id: "menu", type: "folder", - title: "Bookmarks Menu", children: ["folderAAAAAA", "folderCCCCCC"], }, { id: "folderAAAAAA", @@ -572,7 +567,6 @@ add_task(async function test_complex_move_with_additions() { await buf.store(shuffle([{ id: "menu", type: "folder", - title: "Bookmarks Menu", children: ["folderAAAAAA"], }, { id: "folderAAAAAA", @@ -604,12 +598,10 @@ add_task(async function test_complex_move_with_additions() { await buf.store(shuffle([{ id: "menu", type: "folder", - title: "Bookmarks Menu", children: ["bookmarkCCCC"], }, { id: "toolbar", type: "folder", - title: "Bookmarks Toolbar", children: ["folderAAAAAA"], }, { id: "folderAAAAAA", @@ -780,7 +772,6 @@ add_task(async function test_reorder_and_insert() { await buf.store(shuffle([{ id: "menu", type: "folder", - title: "Bookmarks Menu", children: ["bookmarkAAAA", "bookmarkBBBB", "bookmarkCCCC"], }, { id: "bookmarkAAAA", @@ -800,7 +791,6 @@ add_task(async function test_reorder_and_insert() { }, { id: "toolbar", type: "folder", - title: "Bookmarks Toolbar", children: ["bookmarkDDDD", "bookmarkEEEE", "bookmarkFFFF"], }, { id: "bookmarkDDDD", @@ -848,7 +838,6 @@ add_task(async function test_reorder_and_insert() { // as the base, then append (G H). id: "toolbar", type: "folder", - title: "Bookmarks Toolbar", children: ["bookmarkFFFF", "bookmarkDDDD", "bookmarkEEEE"], modified: now / 1000 + 5, }, { @@ -856,7 +845,6 @@ add_task(async function test_reorder_and_insert() { // as the base, then append (I J). id: "menu", type: "folder", - title: "Bookmarks Menu", children: ["bookmarkAAAA", "bookmarkBBBB", "bookmarkCCCC", "bookmarkIIII", "bookmarkJJJJ"], modified: now / 1000 - 5, diff --git a/toolkit/components/places/tests/sync/test_bookmark_value_changes.js b/toolkit/components/places/tests/sync/test_bookmark_value_changes.js index fd0008a7ec6b..8903f24a457a 100644 --- a/toolkit/components/places/tests/sync/test_bookmark_value_changes.js +++ b/toolkit/components/places/tests/sync/test_bookmark_value_changes.js @@ -14,7 +14,6 @@ add_task(async function test_value_combo() { await buf.store(shuffle([{ id: "menu", type: "folder", - title: "Bookmarks Menu", children: ["mozBmk______"], }, { id: "mozBmk______", @@ -46,7 +45,6 @@ add_task(async function test_value_combo() { }, { id: "toolbar", type: "folder", - title: "Bookmarks Toolbar", children: ["fxBmk_______", "tFolder_____"], }, { id: "fxBmk_______", @@ -72,6 +70,8 @@ add_task(async function test_value_combo() { let changesToUpload = await buf.apply(); deepEqual(await buf.fetchUnmergedGuids(), [], "Should merge all items"); + let menuInfo = await PlacesUtils.bookmarks.fetch( + PlacesUtils.bookmarks.menuGuid); deepEqual(changesToUpload, { bzBmk_______: { tombstone: false, @@ -91,7 +91,7 @@ add_task(async function test_value_combo() { }, toolbar: { tombstone: false, - counter: 1, + counter: 2, synced: false, cleartext: { id: "toolbar", @@ -99,7 +99,7 @@ add_task(async function test_value_combo() { parentid: "places", hasDupe: false, parentName: "", - dateAdded: 0, + dateAdded: menuInfo.dateAdded.getTime(), title: "Bookmarks Toolbar", children: ["fxBmk_______", "tFolder_____", "bzBmk_______"], }, @@ -254,7 +254,6 @@ add_task(async function test_value_only_changes() { await buf.store(shuffle([{ id: "menu", type: "folder", - title: "Bookmarks Menu", children: ["folderAAAAAA", "folderFFFFFF"], }, { id: "folderAAAAAA", @@ -478,7 +477,6 @@ add_task(async function test_keywords() { await buf.store(shuffle([{ id: "menu", type: "folder", - title: "Bookmarks Menu", children: ["bookmarkAAAA", "bookmarkBBBB", "bookmarkCCCC", "bookmarkDDDD"], }, { id: "bookmarkAAAA", @@ -616,7 +614,6 @@ add_task(async function test_keywords_complex() { await buf.store(shuffle([{ id: "menu", type: "folder", - title: "Bookmarks Menu", children: ["bookmarkBBBB", "bookmarkCCCC", "bookmarkDDDD", "bookmarkEEEE"], }, { id: "bookmarkBBBB", @@ -648,7 +645,6 @@ add_task(async function test_keywords_complex() { await buf.store(shuffle([{ id: "menu", type: "folder", - title: "Bookmarks Menu", children: ["bookmarkAAAA", "bookmarkAAA1", "bookmarkBBBB", "bookmarkCCCC", "bookmarkDDDD", "bookmarkEEEE"], }, { @@ -916,7 +912,6 @@ add_task(async function test_tags() { await buf.store(shuffle([{ id: "menu", type: "folder", - title: "Bookmarks Menu", children: ["bookmarkAAAA", "bookmarkBBBB", "bookmarkCCCC", "bookmarkDDDD"], }, { id: "bookmarkAAAA", @@ -1013,7 +1008,6 @@ add_task(async function test_rewrite_tag_queries() { await buf.store([{ id: "menu", type: "folder", - title: "Bookmarks Menu", children: ["bookmarkAAAA", "bookmarkDDDD"], }, { id: "bookmarkAAAA", @@ -1033,7 +1027,6 @@ add_task(async function test_rewrite_tag_queries() { await buf.store([{ id: "toolbar", type: "folder", - title: "Bookmarks Toolbar", children: ["queryBBBBBBB", "queryCCCCCCC", "bookmarkEEEE"], }, { id: "queryBBBBBBB", @@ -1123,7 +1116,6 @@ add_task(async function test_date_added() { await buf.store([{ id: "menu", type: "folder", - title: "Bookmarks Menu", children: ["bookmarkAAAA", "bookmarkBBBB"], }, { id: "bookmarkAAAA", From f004749d6380b939d0bf570ec454cea06017c92f Mon Sep 17 00:00:00 2001 From: Ted Campbell Date: Thu, 8 Feb 2018 17:01:59 -0500 Subject: [PATCH 14/41] Bug 1382458 - Make tests using inIon() more reliable r=nbp A number of jit-tests can fail if an ill-timed GC throws away their JitCode. This adds jit options to those tests to prevent JitCode being tossed. MozReview-Commit-ID: 3hay0oIl9Fg --HG-- extra : rebase_source : f2ef811f7f25f960cf49414c614a549296252836 --- js/src/jit-test/tests/auto-regress/bug1343513-2.js | 4 ++++ js/src/jit-test/tests/auto-regress/bug1343513.js | 4 ++++ js/src/jit-test/tests/basic/bug1292858.js | 4 ++++ js/src/jit-test/tests/basic/bug1295031.js | 4 ++++ js/src/jit-test/tests/basic/bug1296015.js | 4 ++++ js/src/jit-test/tests/basic/bug1302682.js | 4 ++++ js/src/jit-test/tests/basic/testApplyArrayInline.js | 4 ++++ js/src/jit-test/tests/ion/bug1298354.js | 4 ++++ js/src/jit-test/tests/ion/bug1330662.js | 3 +++ js/src/jit-test/tests/ion/getprop-primitive.js | 3 +++ js/src/jit-test/tests/ion/osr-with-optimized-out.js | 1 + 11 files changed, 39 insertions(+) diff --git a/js/src/jit-test/tests/auto-regress/bug1343513-2.js b/js/src/jit-test/tests/auto-regress/bug1343513-2.js index f610e39260b6..184359cf4359 100644 --- a/js/src/jit-test/tests/auto-regress/bug1343513-2.js +++ b/js/src/jit-test/tests/auto-regress/bug1343513-2.js @@ -1,4 +1,8 @@ // |jit-test| error:RangeError +setJitCompilerOption("ion.warmup.trigger", 50); +setJitCompilerOption("offthread-compilation.enable", 0); +gcPreserveCode(); + var i = 0; do { i++; diff --git a/js/src/jit-test/tests/auto-regress/bug1343513.js b/js/src/jit-test/tests/auto-regress/bug1343513.js index 2c77086bb9a7..530f3e70fd83 100644 --- a/js/src/jit-test/tests/auto-regress/bug1343513.js +++ b/js/src/jit-test/tests/auto-regress/bug1343513.js @@ -1,4 +1,8 @@ // |jit-test| error:RangeError +setJitCompilerOption("ion.warmup.trigger", 50); +setJitCompilerOption("offthread-compilation.enable", 0); +gcPreserveCode(); + var i = 0; do { i++; diff --git a/js/src/jit-test/tests/basic/bug1292858.js b/js/src/jit-test/tests/basic/bug1292858.js index f905274e17a2..8077d17a9972 100644 --- a/js/src/jit-test/tests/basic/bug1292858.js +++ b/js/src/jit-test/tests/basic/bug1292858.js @@ -1,3 +1,7 @@ +setJitCompilerOption("ion.warmup.trigger", 50); +setJitCompilerOption("offthread-compilation.enable", 0); +gcPreserveCode(); + var caughtInvalidArguments = false; var a = -1 try { diff --git a/js/src/jit-test/tests/basic/bug1295031.js b/js/src/jit-test/tests/basic/bug1295031.js index 386ffc93abb9..c0fc770e0446 100644 --- a/js/src/jit-test/tests/basic/bug1295031.js +++ b/js/src/jit-test/tests/basic/bug1295031.js @@ -1,3 +1,7 @@ +setJitCompilerOption("ion.warmup.trigger", 50); +setJitCompilerOption("offthread-compilation.enable", 0); +gcPreserveCode(); + try { while (true) { a = inIon() ? 0 : 300; diff --git a/js/src/jit-test/tests/basic/bug1296015.js b/js/src/jit-test/tests/basic/bug1296015.js index ce1b270d212a..aacd5775ebbe 100644 --- a/js/src/jit-test/tests/basic/bug1296015.js +++ b/js/src/jit-test/tests/basic/bug1296015.js @@ -1,3 +1,7 @@ +setJitCompilerOption("ion.warmup.trigger", 50); +setJitCompilerOption("offthread-compilation.enable", 0); +gcPreserveCode(); + function f() { for (var i=0; i<30000; i++) { var a = inIon() ? 0 : 300; diff --git a/js/src/jit-test/tests/basic/bug1302682.js b/js/src/jit-test/tests/basic/bug1302682.js index 1fdb7fe16f6e..0a33c42972d8 100644 --- a/js/src/jit-test/tests/basic/bug1302682.js +++ b/js/src/jit-test/tests/basic/bug1302682.js @@ -1,3 +1,7 @@ +setJitCompilerOption("ion.warmup.trigger", 50); +setJitCompilerOption("offthread-compilation.enable", 0); +gcPreserveCode(); + for (var i = 0; i < 30000; i++) { var a = inIon() ? 7 : 300; var buf = new Uint8ClampedArray(a); diff --git a/js/src/jit-test/tests/basic/testApplyArrayInline.js b/js/src/jit-test/tests/basic/testApplyArrayInline.js index d39770e19d58..8c917502b68d 100644 --- a/js/src/jit-test/tests/basic/testApplyArrayInline.js +++ b/js/src/jit-test/tests/basic/testApplyArrayInline.js @@ -1,5 +1,9 @@ // Test inlining in Ion of fun.apply(..., array). +setJitCompilerOption("ion.warmup.trigger", 50); +setJitCompilerOption("offthread-compilation.enable", 0); +gcPreserveCode(); + if (!this.getJitCompilerOptions() || !getJitCompilerOptions()['ion.enable']) quit(0); diff --git a/js/src/jit-test/tests/ion/bug1298354.js b/js/src/jit-test/tests/ion/bug1298354.js index b443031fe126..69cbb67213bd 100644 --- a/js/src/jit-test/tests/ion/bug1298354.js +++ b/js/src/jit-test/tests/ion/bug1298354.js @@ -1,5 +1,9 @@ // |jit-test| error: ReferenceError +setJitCompilerOption("ion.warmup.trigger", 50); +setJitCompilerOption("offthread-compilation.enable", 0); +gcPreserveCode(); + new Function(` while (true) { try { diff --git a/js/src/jit-test/tests/ion/bug1330662.js b/js/src/jit-test/tests/ion/bug1330662.js index c19959b889cb..f4e561b7e053 100644 --- a/js/src/jit-test/tests/ion/bug1330662.js +++ b/js/src/jit-test/tests/ion/bug1330662.js @@ -1,3 +1,6 @@ +setJitCompilerOption("ion.warmup.trigger", 50); +setJitCompilerOption("offthread-compilation.enable", 0); +gcPreserveCode(); for (i=0;i<10000;++i) { a = inIon() ? 0 : 300; diff --git a/js/src/jit-test/tests/ion/getprop-primitive.js b/js/src/jit-test/tests/ion/getprop-primitive.js index 27606c413bf4..2cb912d7d4d4 100644 --- a/js/src/jit-test/tests/ion/getprop-primitive.js +++ b/js/src/jit-test/tests/ion/getprop-primitive.js @@ -1,3 +1,6 @@ +setJitCompilerOption("ion.warmup.trigger", 50); +setJitCompilerOption("offthread-compilation.enable", 0); +gcPreserveCode(); var testSet1 = [1, "", Symbol("a"), true]; var testSet2 = [1, "", Symbol("a"), true, { bar: 5 }]; diff --git a/js/src/jit-test/tests/ion/osr-with-optimized-out.js b/js/src/jit-test/tests/ion/osr-with-optimized-out.js index 5f4ae86e36dc..78e2685ff2f2 100644 --- a/js/src/jit-test/tests/ion/osr-with-optimized-out.js +++ b/js/src/jit-test/tests/ion/osr-with-optimized-out.js @@ -4,6 +4,7 @@ // Ion compilation, such that we can garantee that we would OSR into the inner // loop before we reach the end of the loop. setJitCompilerOption("ion.warmup.trigger", 30); +gcPreserveCode(); function f (n) { while (!inIon()) { From 4dadb65ad1ea65769741d71b7b8e334095ec8347 Mon Sep 17 00:00:00 2001 From: Ted Campbell Date: Thu, 8 Feb 2018 16:20:18 -0500 Subject: [PATCH 15/41] Bug 1432764 - Support Debug OSR with CacheIR_Regular ICs on stack r=jandem MozReview-Commit-ID: 1ONbWxPpS4t --HG-- extra : rebase_source : 30a107741d37fd4a49cf0701798266190fcceb82 --- js/src/jit-test/tests/debug/bug1432764.js | 16 ++++++++++++++++ js/src/jit/BaselineCacheIRCompiler.cpp | 18 ++++++++++++++++++ js/src/jit/BaselineDebugModeOSR.cpp | 1 + js/src/jit/SharedIC.h | 3 +++ 4 files changed, 38 insertions(+) create mode 100644 js/src/jit-test/tests/debug/bug1432764.js diff --git a/js/src/jit-test/tests/debug/bug1432764.js b/js/src/jit-test/tests/debug/bug1432764.js new file mode 100644 index 000000000000..219b7390fcf9 --- /dev/null +++ b/js/src/jit-test/tests/debug/bug1432764.js @@ -0,0 +1,16 @@ +// |jit-test| error: uncaught exception +g = newGlobal(); +g.parent = this; +g.eval(` + Debugger(parent).onExceptionUnwind = function(frame) { frame.older }; +`); + +var handler = { + has: function(tgt, key) { if (key == 'throw') { throw null; } } +}; + +var proxy = new Proxy({}, handler); + +for (let k of ['foo', 'throw']) { + k in proxy; +} diff --git a/js/src/jit/BaselineCacheIRCompiler.cpp b/js/src/jit/BaselineCacheIRCompiler.cpp index 3f027e3f81c8..7ac203834cc6 100644 --- a/js/src/jit/BaselineCacheIRCompiler.cpp +++ b/js/src/jit/BaselineCacheIRCompiler.cpp @@ -2343,6 +2343,24 @@ ICCacheIR_Updated::stubDataStart() return reinterpret_cast(this) + stubInfo_->stubDataOffset(); } +/* static */ ICCacheIR_Regular* +ICCacheIR_Regular::Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub, + ICCacheIR_Regular& other) +{ + const CacheIRStubInfo* stubInfo = other.stubInfo(); + MOZ_ASSERT(stubInfo->makesGCCalls()); + + size_t bytesNeeded = stubInfo->stubDataOffset() + stubInfo->stubDataSize(); + void* newStub = space->alloc(bytesNeeded); + if (!newStub) + return nullptr; + + ICCacheIR_Regular* res = new(newStub) ICCacheIR_Regular(other.jitCode(), stubInfo); + stubInfo->copyStubData(&other, res); + return res; +} + + /* static */ ICCacheIR_Monitored* ICCacheIR_Monitored::Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub, ICCacheIR_Monitored& other) diff --git a/js/src/jit/BaselineDebugModeOSR.cpp b/js/src/jit/BaselineDebugModeOSR.cpp index 5a6d2d4b9a11..4df5f53e36e2 100644 --- a/js/src/jit/BaselineDebugModeOSR.cpp +++ b/js/src/jit/BaselineDebugModeOSR.cpp @@ -695,6 +695,7 @@ RecompileBaselineScriptForDebugMode(JSContext* cx, JSScript* script, #define PATCHABLE_ICSTUB_KIND_LIST(_) \ _(CacheIR_Monitored) \ + _(CacheIR_Regular) \ _(CacheIR_Updated) \ _(Call_Scripted) \ _(Call_AnyScripted) \ diff --git a/js/src/jit/SharedIC.h b/js/src/jit/SharedIC.h index 0b922224b72b..55bb6abde180 100644 --- a/js/src/jit/SharedIC.h +++ b/js/src/jit/SharedIC.h @@ -846,6 +846,9 @@ class ICCacheIR_Regular : public ICStub stubInfo_(stubInfo) {} + static ICCacheIR_Regular* Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub, + ICCacheIR_Regular& other); + void notePreliminaryObject() { extra_ = 1; } From 2c6a0a92734ec74a489f08dfd78c2cee5d942f8d Mon Sep 17 00:00:00 2001 From: Adrian Wielgosik Date: Thu, 8 Feb 2018 22:33:10 +0100 Subject: [PATCH 16/41] Bug 1436864 - Remove nsIDOMHistory. r=bz MozReview-Commit-ID: HVOR03mvW2S --HG-- extra : rebase_source : d4d81217ee17ca4b9d5e966fc1954cd77ee2437b --- dom/base/nsHistory.cpp | 1 - dom/base/nsHistory.h | 6 ++---- dom/interfaces/base/moz.build | 1 - dom/interfaces/base/nsIDOMHistory.idl | 12 ------------ xpcom/reflect/xptinfo/ShimInterfaceInfo.cpp | 3 --- 5 files changed, 2 insertions(+), 21 deletions(-) delete mode 100644 dom/interfaces/base/nsIDOMHistory.idl diff --git a/dom/base/nsHistory.cpp b/dom/base/nsHistory.cpp index f84ed6005a25..c894143a2ab9 100644 --- a/dom/base/nsHistory.cpp +++ b/dom/base/nsHistory.cpp @@ -34,7 +34,6 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(nsHistory) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsHistory) NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY NS_INTERFACE_MAP_ENTRY(nsISupports) - NS_INTERFACE_MAP_ENTRY(nsIDOMHistory) // Empty, needed for extension compat NS_INTERFACE_MAP_END nsHistory::nsHistory(nsPIDOMWindowInner* aInnerWindow) diff --git a/dom/base/nsHistory.h b/dom/base/nsHistory.h index be556934dfe6..9ffe9a3466e1 100644 --- a/dom/base/nsHistory.h +++ b/dom/base/nsHistory.h @@ -11,7 +11,6 @@ #include "mozilla/dom/HistoryBinding.h" #include "nsCOMPtr.h" #include "nsCycleCollectionParticipant.h" -#include "nsIDOMHistory.h" #include "nsPIDOMWindow.h" // for GetParentObject #include "nsStringFwd.h" #include "nsWrapperCache.h" @@ -22,9 +21,8 @@ class nsIWeakReference; class nsPIDOMWindowInner; // Script "History" object -class nsHistory final : public nsIDOMHistory, // Empty, needed for extension - // backwards compat - public nsWrapperCache +class nsHistory final : public nsISupports, + public nsWrapperCache { public: NS_DECL_CYCLE_COLLECTING_ISUPPORTS diff --git a/dom/interfaces/base/moz.build b/dom/interfaces/base/moz.build index 8793178206fc..2932b485700c 100644 --- a/dom/interfaces/base/moz.build +++ b/dom/interfaces/base/moz.build @@ -20,7 +20,6 @@ XPIDL_SOURCES += [ 'nsIDOMClientRectList.idl', 'nsIDOMConstructor.idl', 'nsIDOMGlobalPropertyInitializer.idl', - 'nsIDOMHistory.idl', 'nsIDOMModalContentWindow.idl', 'nsIDOMScreen.idl', 'nsIDOMWindow.idl', diff --git a/dom/interfaces/base/nsIDOMHistory.idl b/dom/interfaces/base/nsIDOMHistory.idl deleted file mode 100644 index b520b6212134..000000000000 --- a/dom/interfaces/base/nsIDOMHistory.idl +++ /dev/null @@ -1,12 +0,0 @@ -/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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/. */ - -#include "domstubs.idl" - -[uuid(55226663-fe68-48ba-addf-08e32eaab569)] -interface nsIDOMHistory : nsISupports -{ - // Empty interface that exists only for extension backwards compat -}; diff --git a/xpcom/reflect/xptinfo/ShimInterfaceInfo.cpp b/xpcom/reflect/xptinfo/ShimInterfaceInfo.cpp index fe70082a1a2a..a2abbb5ef7a5 100644 --- a/xpcom/reflect/xptinfo/ShimInterfaceInfo.cpp +++ b/xpcom/reflect/xptinfo/ShimInterfaceInfo.cpp @@ -37,7 +37,6 @@ #include "nsIDOMFocusEvent.h" #include "nsIDOMFormData.h" #include "nsIDOMGeoPositionError.h" -#include "nsIDOMHistory.h" #include "nsIDOMHTMLFormElement.h" #include "nsIDOMHTMLInputElement.h" #include "nsIDOMHTMLMediaElement.h" @@ -112,7 +111,6 @@ #include "mozilla/dom/FocusEventBinding.h" #include "mozilla/dom/FormDataBinding.h" #include "mozilla/dom/FrameLoaderBinding.h" -#include "mozilla/dom/HistoryBinding.h" #include "mozilla/dom/HTMLAnchorElementBinding.h" #include "mozilla/dom/HTMLAreaElementBinding.h" #include "mozilla/dom/HTMLButtonElementBinding.h" @@ -250,7 +248,6 @@ const ComponentsInterfaceShimEntry kComponentsInterfaceShimMap[] = DEFINE_SHIM(FormData), DEFINE_SHIM_WITH_CUSTOM_INTERFACE(nsIFrameLoader, FrameLoader), DEFINE_SHIM_WITH_CUSTOM_INTERFACE(nsIDOMGeoPositionError, PositionError), - DEFINE_SHIM(History), DEFINE_SHIM(HTMLFormElement), DEFINE_SHIM(HTMLInputElement), DEFINE_SHIM(HTMLMediaElement), From ee7273f84fad0c777ac1f09c8e65e1b79d71f05e Mon Sep 17 00:00:00 2001 From: Adrian Wielgosik Date: Thu, 8 Feb 2018 17:24:03 +0100 Subject: [PATCH 17/41] Bug 1436869 - Remove nsIDOMPaintRequest. r=bz MozReview-Commit-ID: 3Xpk2v1xbPp --HG-- extra : rebase_source : e66727a028649557246f005a9b69c850f7831146 --- dom/events/PaintRequest.cpp | 16 ----------- dom/events/PaintRequest.h | 4 +-- dom/interfaces/events/moz.build | 1 - dom/interfaces/events/nsIDOMPaintRequest.idl | 30 -------------------- xpcom/reflect/xptinfo/ShimInterfaceInfo.cpp | 3 -- 5 files changed, 1 insertion(+), 53 deletions(-) delete mode 100644 dom/interfaces/events/nsIDOMPaintRequest.idl diff --git a/dom/events/PaintRequest.cpp b/dom/events/PaintRequest.cpp index c442bccb463d..858951afbf73 100644 --- a/dom/events/PaintRequest.cpp +++ b/dom/events/PaintRequest.cpp @@ -21,7 +21,6 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PaintRequest, mParent) NS_INTERFACE_TABLE_HEAD(PaintRequest) NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY - NS_INTERFACE_TABLE(PaintRequest, nsIDOMPaintRequest) NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(PaintRequest) NS_INTERFACE_MAP_END @@ -42,21 +41,6 @@ PaintRequest::ClientRect() return clientRect.forget(); } -NS_IMETHODIMP -PaintRequest::GetClientRect(nsIDOMClientRect** aResult) -{ - RefPtr clientRect = ClientRect(); - clientRect.forget(aResult); - return NS_OK; -} - -NS_IMETHODIMP -PaintRequest::GetXPCOMReason(nsAString& aResult) -{ - GetReason(aResult); - return NS_OK; -} - /****************************************************************************** * mozilla::dom::PaintRequestList *****************************************************************************/ diff --git a/dom/events/PaintRequest.h b/dom/events/PaintRequest.h index 0a541c72e599..9d2d1b2081ad 100644 --- a/dom/events/PaintRequest.h +++ b/dom/events/PaintRequest.h @@ -7,7 +7,6 @@ #ifndef mozilla_dom_PaintRequest_h_ #define mozilla_dom_PaintRequest_h_ -#include "nsIDOMPaintRequest.h" #include "nsPresContext.h" #include "nsIDOMEvent.h" #include "mozilla/Attributes.h" @@ -18,7 +17,7 @@ namespace dom { class DOMRect; -class PaintRequest final : public nsIDOMPaintRequest +class PaintRequest final : public nsISupports , public nsWrapperCache { public: @@ -29,7 +28,6 @@ public: NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(PaintRequest) - NS_DECL_NSIDOMPAINTREQUEST virtual JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; diff --git a/dom/interfaces/events/moz.build b/dom/interfaces/events/moz.build index a45acb153a77..29b00155c6de 100644 --- a/dom/interfaces/events/moz.build +++ b/dom/interfaces/events/moz.build @@ -25,7 +25,6 @@ XPIDL_SOURCES += [ 'nsIDOMMutationEvent.idl', 'nsIDOMNotifyPaintEvent.idl', 'nsIDOMNSEvent.idl', - 'nsIDOMPaintRequest.idl', 'nsIDOMScrollAreaEvent.idl', 'nsIDOMSimpleGestureEvent.idl', 'nsIDOMTransitionEvent.idl', diff --git a/dom/interfaces/events/nsIDOMPaintRequest.idl b/dom/interfaces/events/nsIDOMPaintRequest.idl deleted file mode 100644 index 64f107ed997d..000000000000 --- a/dom/interfaces/events/nsIDOMPaintRequest.idl +++ /dev/null @@ -1,30 +0,0 @@ -/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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/. */ - -#include "domstubs.idl" - -interface nsIDOMClientRect; - -/** - * These objects are exposed by the MozDOMAfterPaint event. Each one represents - * a request to repaint a rectangle that was generated by the browser. - */ -[uuid(9eb5268f-73a4-41da-9790-d21fcefd5ffa)] -interface nsIDOMPaintRequest : nsISupports -{ - /** - * The client rect where invalidation was triggered. - */ - readonly attribute nsIDOMClientRect clientRect; - /** - * The reason for the request, as a string. If an empty string, then we don't know - * the reason (this is common). Reasons include "scroll repaint", meaning that we - * needed to repaint the rectangle due to scrolling, and "scroll copy", meaning - * that we updated the rectangle due to scrolling but instead of painting - * manually, we were able to do a copy from another area of the screen. - */ - [binaryname(XPCOMReason)] - readonly attribute DOMString reason; -}; diff --git a/xpcom/reflect/xptinfo/ShimInterfaceInfo.cpp b/xpcom/reflect/xptinfo/ShimInterfaceInfo.cpp index a2abbb5ef7a5..7b4bbfe7e336 100644 --- a/xpcom/reflect/xptinfo/ShimInterfaceInfo.cpp +++ b/xpcom/reflect/xptinfo/ShimInterfaceInfo.cpp @@ -49,7 +49,6 @@ #include "nsIDOMNotifyPaintEvent.h" #include "nsIDOMNSEvent.h" #include "nsIDOMOfflineResourceList.h" -#include "nsIDOMPaintRequest.h" #include "nsIDOMParser.h" #include "nsIDOMProcessingInstruction.h" #include "nsIDOMRange.h" @@ -132,7 +131,6 @@ #include "mozilla/dom/NotifyPaintEventBinding.h" #include "mozilla/dom/EventBinding.h" #include "mozilla/dom/OfflineResourceListBinding.h" -#include "mozilla/dom/PaintRequestBinding.h" #include "mozilla/dom/PositionErrorBinding.h" #include "mozilla/dom/ProcessingInstructionBinding.h" #include "mozilla/dom/RangeBinding.h" @@ -262,7 +260,6 @@ const ComponentsInterfaceShimEntry kComponentsInterfaceShimMap[] = DEFINE_SHIM(NotifyPaintEvent), DEFINE_SHIM_WITH_CUSTOM_INTERFACE(nsIDOMNSEvent, Event), DEFINE_SHIM(OfflineResourceList), - DEFINE_SHIM(PaintRequest), DEFINE_SHIM_WITH_CUSTOM_INTERFACE(nsIDOMParser, DOMParser), DEFINE_SHIM(ProcessingInstruction), DEFINE_SHIM(Range), From 2d4c080565b67e1ee776320bea71b1e73e364013 Mon Sep 17 00:00:00 2001 From: Csoregi Natalia Date: Fri, 9 Feb 2018 16:56:39 +0200 Subject: [PATCH 18/41] Backed out 2 changesets (bug 1429573) for reftest failures /tests/reftest/tests/editor/reftests/xul/number-3.xul. on a CLOSED TREE Backed out changeset bd6892535d35 (bug 1429573) Backed out changeset 1c398da94994 (bug 1429573) --- accessible/base/Role.h | 2 +- accessible/interfaces/nsIAccessibleRole.idl | 2 +- .../tests/mochitest/tree/test_txtctrl.xul | 8 +- browser/installer/allowed-dupes.mn | 1 + mobile/android/installer/allowed-dupes.mn | 1 + toolkit/content/jar.mn | 1 + .../tests/chrome/test_textbox_number.xul | 88 ++++++++++++++++- toolkit/content/widgets/numberbox.xml | 80 +++++++++++++++- toolkit/content/widgets/spinbuttons.xml | 96 +++++++++++++++++++ toolkit/content/widgets/textbox.xml | 50 ++++------ toolkit/content/xul.css | 10 ++ .../themes/linux/global/in-content/common.css | 4 + toolkit/themes/linux/global/numberbox.css | 11 ++- toolkit/themes/mobile/jar.mn | 1 + .../themes/osx/global/in-content/common.css | 24 ++++- toolkit/themes/osx/global/jar.mn | 1 + toolkit/themes/osx/global/numberbox.css | 6 +- toolkit/themes/osx/global/spinbuttons.css | 31 ++++++ .../themes/shared/in-content/common.inc.css | 45 +++++---- toolkit/themes/shared/non-mac.jar.inc.mn | 3 + toolkit/themes/windows/global/jar.mn | 2 - toolkit/themes/windows/global/numberbox.css | 5 +- toolkit/themes/windows/global/spinbuttons.css | 24 +++++ 23 files changed, 426 insertions(+), 70 deletions(-) create mode 100644 toolkit/content/widgets/spinbuttons.xml create mode 100644 toolkit/themes/osx/global/spinbuttons.css create mode 100644 toolkit/themes/windows/global/spinbuttons.css diff --git a/accessible/base/Role.h b/accessible/base/Role.h index 509de9f392da..2e4a2ff54df9 100644 --- a/accessible/base/Role.h +++ b/accessible/base/Role.h @@ -345,7 +345,7 @@ enum Role { /** * Represents a spin box, which is a control that allows the user to increment * or decrement the value displayed in a separate "buddy" control associated - * with the spin box. It is used for input[type=number] spin buttons. + * with the spin box. It is used for xul:spinbuttons. */ SPINBUTTON = 52, diff --git a/accessible/interfaces/nsIAccessibleRole.idl b/accessible/interfaces/nsIAccessibleRole.idl index ac41b865be48..0cded53abb6a 100644 --- a/accessible/interfaces/nsIAccessibleRole.idl +++ b/accessible/interfaces/nsIAccessibleRole.idl @@ -338,7 +338,7 @@ interface nsIAccessibleRole : nsISupports /** * Represents a spin box, which is a control that allows the user to increment * or decrement the value displayed in a separate "buddy" control associated - * with the spin box. It is used for input[type=number] spin buttons. + * with the spin box. It is used for xul:spinbuttons. */ const unsigned long ROLE_SPINBUTTON = 52; diff --git a/accessible/tests/mochitest/tree/test_txtctrl.xul b/accessible/tests/mochitest/tree/test_txtctrl.xul index d2b9da99a653..9a85d4603a33 100644 --- a/accessible/tests/mochitest/tree/test_txtctrl.xul +++ b/accessible/tests/mochitest/tree/test_txtctrl.xul @@ -75,12 +75,10 @@ accTree = { SECTION: [ - { SPINBUTTON: [ - { ENTRY: [ { TEXT_LEAF: [] } ] }, - { PUSHBUTTON: [ ] }, - { PUSHBUTTON: [ ] } - ] }, + { ENTRY: [ { TEXT_LEAF: [] } ] }, { MENUPOPUP: [] }, + { PUSHBUTTON: [] }, + { PUSHBUTTON: [] } ] }; testAccessibleTree("txc_number", accTree); diff --git a/browser/installer/allowed-dupes.mn b/browser/installer/allowed-dupes.mn index 2a8ebd3afb64..0b67197fbcb4 100644 --- a/browser/installer/allowed-dupes.mn +++ b/browser/installer/allowed-dupes.mn @@ -113,6 +113,7 @@ chrome/toolkit/skin/classic/global/richlistbox.css chrome/toolkit/skin/classic/global/scale.css chrome/toolkit/skin/classic/global/scrollbars.css chrome/toolkit/skin/classic/global/scrollbox.css +chrome/toolkit/skin/classic/global/spinbuttons.css chrome/toolkit/skin/classic/global/splitter.css chrome/toolkit/skin/classic/global/tabbox.css chrome/toolkit/skin/classic/global/textbox.css diff --git a/mobile/android/installer/allowed-dupes.mn b/mobile/android/installer/allowed-dupes.mn index 9959d00e5e27..f8a2210740ee 100644 --- a/mobile/android/installer/allowed-dupes.mn +++ b/mobile/android/installer/allowed-dupes.mn @@ -25,6 +25,7 @@ chrome/toolkit/skin/classic/global/richlistbox.css chrome/toolkit/skin/classic/global/scale.css chrome/toolkit/skin/classic/global/scrollbars.css chrome/toolkit/skin/classic/global/scrollbox.css +chrome/toolkit/skin/classic/global/spinbuttons.css chrome/toolkit/skin/classic/global/splitter.css chrome/toolkit/skin/classic/global/tabbox.css chrome/toolkit/skin/classic/global/textbox.css diff --git a/toolkit/content/jar.mn b/toolkit/content/jar.mn index f13f8fa43bf8..6e52f7577c33 100644 --- a/toolkit/content/jar.mn +++ b/toolkit/content/jar.mn @@ -94,6 +94,7 @@ toolkit.jar: content/global/bindings/scrollbox.xml (widgets/scrollbox.xml) content/global/bindings/spinner.js (widgets/spinner.js) content/global/bindings/splitter.xml (widgets/splitter.xml) + content/global/bindings/spinbuttons.xml (widgets/spinbuttons.xml) content/global/bindings/stringbundle.xml (widgets/stringbundle.xml) * content/global/bindings/tabbox.xml (widgets/tabbox.xml) content/global/bindings/text.xml (widgets/text.xml) diff --git a/toolkit/content/tests/chrome/test_textbox_number.xul b/toolkit/content/tests/chrome/test_textbox_number.xul index 6fc9e0115c67..fba395b864a7 100644 --- a/toolkit/content/tests/chrome/test_textbox_number.xul +++ b/toolkit/content/tests/chrome/test_textbox_number.xul @@ -6,8 +6,8 @@ --> - - + + @@ -48,6 +48,8 @@ function doTests() { testValsMinMax(n5, "initial n5", -10, -10, -3); testValsMinMax(n6, "initial n6", 12, 12, 12); + ok(n1.spinButtons != null && n1.spinButtons.localName == "spinbuttons", "spinButtons set"); + // test changing the value n1.value = "1700"; testVals(n1, "set value,", 1700); @@ -91,19 +93,67 @@ function doTests() { n1.max = 22; testValsMinMax(n1, "set integer max,", 22, 8, 22); + // test increase and decrease via the keyboard and the spinbuttons + testIncreaseDecrease(n1, "integer", 1, 0, 8, 22); + + // UI tests + n1.min = 5; + n1.max = 15; + n1.value = 5; + n1.focus(); + + var sb = n1.spinButtons; + var sbbottom = sb.getBoundingClientRect().bottom - sb.getBoundingClientRect().top - 2; + + synthesizeKey("VK_UP", {}); + testVals(n1, "key up", 6); + + synthesizeKey("VK_DOWN", {}); + testVals(n1, "key down", 5); + + synthesizeMouse(sb, 2, 2, {}); + testVals(n1, "spinbuttons up", 6); + synthesizeMouse(sb, 2, sbbottom, {}); + testVals(n1, "spinbuttons down", 5); + + n1.value = 15; + synthesizeKey("VK_UP", {}); + testVals(n1, "key up at max", 15); + synthesizeMouse(sb, 2, 2, {}); + testVals(n1, "spinbuttons up at max", 15); + + n1.value = 5; + synthesizeKey("VK_DOWN", {}); + testVals(n1, "key down at min", 5); + synthesizeMouse(sb, 2, sbbottom, {}); + testVals(n1, "spinbuttons down at min", 5); + // check read only state n1.readOnly = true; n1.min = -10; n1.max = 15; n1.value = 12; - n1.inputField.focus(); // no events should fire and no changes should occur when the field is read only synthesizeKeyExpectEvent("VK_UP", { }, n1, "!change", "key up read only"); is(n1.value, "12", "key up read only value"); synthesizeKeyExpectEvent("VK_DOWN", { }, n1, "!change", "key down read only"); is(n1.value, "12", "key down read only value"); + synthesizeMouseExpectEvent(sb, 2, 2, { }, n1, "!change", "mouse up read only"); + is(n1.value, "12", "mouse up read only value"); + synthesizeMouseExpectEvent(sb, 2, sbbottom, { }, n1, "!change", "mouse down read only"); + is(n1.value, "12", "mouse down read only value"); + n1.readOnly = false; + n1.disabled = true; + synthesizeMouseExpectEvent(sb, 2, 2, { }, n1, "!change", "mouse up disabled"); + is(n1.value, "12", "mouse up disabled value"); + synthesizeMouseExpectEvent(sb, 2, sbbottom, { }, n1, "!change", "mouse down disabled"); + is(n1.value, "12", "mouse down disabled value"); + + var nsbrect = $("n8").spinButtons.getBoundingClientRect(); + ok(nsbrect.left == 0 && nsbrect.top == 0 && nsbrect.right == 0, nsbrect.bottom == 0, + "hidespinbuttons"); var n9 = $("n9"); is(n9.value, "0", "initial value"); @@ -152,6 +202,38 @@ function testValsMinMax(nb, name, valueNumber, min, max, valueFieldNumber) { SimpleTest.is(nb.max, max, name + " max is " + max); } +function testIncreaseDecrease(nb, testid, increment, fixedCount, min, max) { + testid += " "; + + nb.focus(); + nb.value = min; + + // pressing the cursor up and down keys should adjust the value + synthesizeKeyExpectEvent("VK_UP", { }, nb, "change", testid + "key up"); + is(nb.value, String(min + increment), testid + "key up"); + nb.value = max; + synthesizeKeyExpectEvent("VK_UP", { }, nb, "!change", testid + "key up at max"); + is(nb.value, String(max), testid + "key up at max"); + synthesizeKeyExpectEvent("VK_DOWN", { }, nb, "change", testid + "key down"); + is(nb.value, String(max - increment), testid + "key down"); + nb.value = min; + synthesizeKeyExpectEvent("VK_DOWN", { }, nb, "!change", testid + "key down at min"); + is(nb.value, String(min), testid + "key down at min"); + + // check pressing the spinbutton arrows + var sb = nb.spinButtons; + var sbbottom = sb.getBoundingClientRect().bottom - sb.getBoundingClientRect().top - 2; + nb.value = min; + synthesizeMouseExpectEvent(sb, 2, 2, { }, nb, "change", testid + "mouse up"); + is(nb.value, String(min + increment), testid + "mouse up"); + nb.value = max; + synthesizeMouseExpectEvent(sb, 2, 2, { }, nb, "!change", testid + "mouse up at max"); + synthesizeMouseExpectEvent(sb, 2, sbbottom, { }, nb, "change", testid + "mouse down"); + is(nb.value, String(max - increment), testid + "mouse down"); + nb.value = min; + synthesizeMouseExpectEvent(sb, 2, sbbottom, { }, nb, "!change", testid + "mouse down at min"); +} + SimpleTest.waitForFocus(doTests); ]]> diff --git a/toolkit/content/widgets/numberbox.xml b/toolkit/content/widgets/numberbox.xml index d0bcfab04a23..cc1a8d3d188f 100644 --- a/toolkit/content/widgets/numberbox.xml +++ b/toolkit/content/widgets/numberbox.xml @@ -19,16 +19,28 @@ - + + false + null 0 - + + + + + + @@ -81,6 +93,47 @@ + + + + + + + + + + + + + + = this.max); + } + ]]> + + + @@ -99,6 +152,8 @@ this._value = Number(aValue); this.inputField.value = aValue; + this._enableDisableButtons(); + return aValue; ]]> @@ -139,9 +194,26 @@ ]]> + + this._modifyUp(); + + + + this._modifyDown(); + + + + this._modifyUp(); + + + + this._modifyDown(); + + if (event.originalTarget == this.inputField) { - this._validateValue(this.inputField.value); + var newval = this.inputField.value; + this._validateValue(newval); } diff --git a/toolkit/content/widgets/spinbuttons.xml b/toolkit/content/widgets/spinbuttons.xml new file mode 100644 index 000000000000..3a695beacffb --- /dev/null +++ b/toolkit/content/widgets/spinbuttons.xml @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + return document.getAnonymousElementByAttribute(this, "anonid", "increaseButton"); + + + + + return document.getAnonymousElementByAttribute(this, "anonid", "decreaseButton"); + + + + + + + + + + + + + + this.removeAttribute("state"); + + + this.removeAttribute("state"); + + + + + + + + + + diff --git a/toolkit/content/widgets/textbox.xml b/toolkit/content/widgets/textbox.xml index ed43a20fd4c1..08148d4e22e1 100644 --- a/toolkit/content/widgets/textbox.xml +++ b/toolkit/content/widgets/textbox.xml @@ -127,12 +127,7 @@ - // According to https://html.spec.whatwg.org/#do-not-apply, - // setSelectionRange() is only available on a limited set of input types. - if (this.inputField.type == "text" || - this.inputField.tagName == "html:textarea") { - this.inputField.setSelectionRange( aSelectionStart, aSelectionEnd ); - } + this.inputField.setSelectionRange( aSelectionStart, aSelectionEnd ); @@ -193,29 +188,26 @@ if (this.hasAttribute("focused")) return; - let { originalTarget } = event; - if (originalTarget == this) { - // Forward focus to actual HTML input - this.inputField.focus(); - this.setAttribute("focused", "true"); - return; + switch (event.originalTarget) { + case this: + // Forward focus to actual HTML input + this.inputField.focus(); + break; + case this.inputField: + if (this.mIgnoreFocus) { + this.mIgnoreFocus = false; + } else if (this.clickSelectsAll) { + try { + if (!this.editor || !this.editor.composing) + this.editor.selectAll(); + } catch (e) {} + } + break; + default: + // Allow other children (e.g. URL bar buttons) to get focus + return; } - - // We check for the parent nodes to support input[type=number] where originalTarget may be an - // anonymous child input. - if (originalTarget == this.inputField || - originalTarget.localName == "input" && originalTarget.parentNode.parentNode == this.inputField) { - if (this.mIgnoreFocus) { - this.mIgnoreFocus = false; - } else if (this.clickSelectsAll) { - try { - if (!this.editor || !this.editor.composing) - this.editor.selectAll(); - } catch (e) {} - } - this.setAttribute("focused", "true"); - } - // Otherwise, allow other children (e.g. URL bar buttons) to get focus + this.setAttribute("focused", "true"); ]]> @@ -237,7 +229,7 @@ if (!this.mIgnoreClick) { this.mIgnoreFocus = true; - this.setSelectionRange(0, 0); + this.inputField.setSelectionRange(0, 0); if (event.originalTarget == this || event.originalTarget == this.inputField.parentNode) this.inputField.focus(); diff --git a/toolkit/content/xul.css b/toolkit/content/xul.css index 5d8662b6286a..0831195eb2d6 100644 --- a/toolkit/content/xul.css +++ b/toolkit/content/xul.css @@ -919,6 +919,16 @@ autorepeatbutton { -moz-binding: url("chrome://global/content/bindings/scrollbox.xml#autorepeatbutton"); } +/********** spinbuttons ***********/ + +spinbuttons { + -moz-binding: url("chrome://global/content/bindings/spinbuttons.xml#spinbuttons"); +} + +.spinbuttons-button { + -moz-user-focus: ignore; +} + /********** stringbundle **********/ stringbundleset { diff --git a/toolkit/themes/linux/global/in-content/common.css b/toolkit/themes/linux/global/in-content/common.css index 3f6e10f5500c..c82331c9a2f9 100644 --- a/toolkit/themes/linux/global/in-content/common.css +++ b/toolkit/themes/linux/global/in-content/common.css @@ -81,6 +81,10 @@ html|input[type="checkbox"]:-moz-focusring + html|label:before { outline: 1px dotted; } +xul|spinbuttons { + -moz-appearance: none; +} + xul|treechildren::-moz-tree-row(multicol, odd) { background-color: var(--in-content-box-background-odd); } diff --git a/toolkit/themes/linux/global/numberbox.css b/toolkit/themes/linux/global/numberbox.css index 59f189019405..0b60d952fd1c 100644 --- a/toolkit/themes/linux/global/numberbox.css +++ b/toolkit/themes/linux/global/numberbox.css @@ -21,6 +21,13 @@ html|*.numberbox-input { text-align: right; } -textbox[type="number"][hidespinbuttons="true"] > html|*.numberbox-input { - -moz-appearance: textfield !important; +.numberbox-input-box { + -moz-box-align: center; + -moz-appearance: spinner-textfield; + margin-right: -1px; + padding: 3px; +} + +textbox[hidespinbuttons="true"] > .numberbox-input-box { + -moz-appearance: textfield; } diff --git a/toolkit/themes/mobile/jar.mn b/toolkit/themes/mobile/jar.mn index c3fe3ded869c..1e3c9e1e0a13 100644 --- a/toolkit/themes/mobile/jar.mn +++ b/toolkit/themes/mobile/jar.mn @@ -23,6 +23,7 @@ toolkit.jar: skin/classic/global/richlistbox.css (global/empty.css) skin/classic/global/scale.css (global/empty.css) skin/classic/global/scrollbox.css (global/empty.css) + skin/classic/global/spinbuttons.css (global/empty.css) skin/classic/global/splitter.css (global/empty.css) skin/classic/global/tabbox.css (global/empty.css) skin/classic/global/textbox.css (global/empty.css) diff --git a/toolkit/themes/osx/global/in-content/common.css b/toolkit/themes/osx/global/in-content/common.css index ba1b24208145..99471334c2ce 100644 --- a/toolkit/themes/osx/global/in-content/common.css +++ b/toolkit/themes/osx/global/in-content/common.css @@ -57,6 +57,11 @@ xul|*.radio-icon { margin-inline-end: 0; } +xul|*.numberbox-input-box { + -moz-appearance: none; + border-width: 0; +} + xul|*.text-link:-moz-focusring { color: var(--in-content-link-highlight); text-decoration: underline; @@ -78,14 +83,29 @@ xul|radio[focused="true"] > .radio-check { -moz-outline-radius: 100%; } -html|*.numberbox-input::-moz-number-spin-up { +xul|spinbuttons { + -moz-appearance: none; +} + +xul|*.spinbuttons-up { + margin-top: 0 !important; border-radius: 4px 4px 0 0; } -html|*.numberbox-input::-moz-number-spin-down { +xul|*.spinbuttons-down { + margin-bottom: 0 !important; border-radius: 0 0 4px 4px; } +xul|*.spinbuttons-button > xul|*.button-box { + padding-inline-start: 2px !important; + padding-inline-end: 3px !important; +} + +xul|*.spinbuttons-button > xul|*.button-box > xul|*.button-text { + display: none; +} + xul|textbox[type="search"]:not([searchbutton]) > .textbox-input-box > .textbox-search-sign { list-style-image: url(chrome://global/skin/icons/search-textbox.svg); margin-inline-end: 5px; diff --git a/toolkit/themes/osx/global/jar.mn b/toolkit/themes/osx/global/jar.mn index 0f4e5fd4dac6..8c249332d2d8 100644 --- a/toolkit/themes/osx/global/jar.mn +++ b/toolkit/themes/osx/global/jar.mn @@ -30,6 +30,7 @@ toolkit.jar: skin/classic/global/richlistbox.css skin/classic/global/scrollbars.css (nativescrollbars.css) skin/classic/global/scrollbox.css + skin/classic/global/spinbuttons.css skin/classic/global/splitter.css skin/classic/global/tabprompts.css skin/classic/global/tabbox.css diff --git a/toolkit/themes/osx/global/numberbox.css b/toolkit/themes/osx/global/numberbox.css index f14702aedf1a..73db12495948 100644 --- a/toolkit/themes/osx/global/numberbox.css +++ b/toolkit/themes/osx/global/numberbox.css @@ -7,6 +7,7 @@ textbox[type="number"] { -moz-appearance: none; + -moz-box-align: center; padding: 0 !important; border: none; background-color: transparent; @@ -18,6 +19,7 @@ html|*.numberbox-input { padding: 0 1px !important; } -textbox[type="number"][hidespinbuttons="true"] > html|*.numberbox-input { - -moz-appearance: textfield !important; +.numberbox-input-box { + -moz-appearance: textfield; + margin-right: 4px; } diff --git a/toolkit/themes/osx/global/spinbuttons.css b/toolkit/themes/osx/global/spinbuttons.css new file mode 100644 index 000000000000..bf89520f6812 --- /dev/null +++ b/toolkit/themes/osx/global/spinbuttons.css @@ -0,0 +1,31 @@ +/* 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/. */ + +@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); + +spinbuttons { + height: 24px; + min-height: 24px; + -moz-appearance: spinner; + cursor: default; +} + +.spinbuttons-up { + -moz-appearance: none; + -moz-box-flex: 1; + min-width: 1px; + min-height: 1px; + margin: 0; + padding: 0; +} + +.spinbuttons-down { + -moz-appearance: none; + -moz-box-flex: 1; + min-width: 1px; + min-height: 1px; + margin: 0; + padding: 0; +} + diff --git a/toolkit/themes/shared/in-content/common.inc.css b/toolkit/themes/shared/in-content/common.inc.css index 157cd707014a..081b67c0837b 100644 --- a/toolkit/themes/shared/in-content/common.inc.css +++ b/toolkit/themes/shared/in-content/common.inc.css @@ -165,9 +165,7 @@ html|button { *|button, html|select, xul|colorpicker[type="button"], -xul|menulist, -html|*.numberbox-input::-moz-number-spin-up, -html|*.numberbox-input::-moz-number-spin-down { +xul|menulist { -moz-appearance: none; min-height: 30px; color: var(--in-content-text-color); @@ -203,8 +201,6 @@ html|select:not([size]):not([multiple]):dir(rtl){ html|button:enabled:hover, html|select:not([size]):not([multiple]):enabled:hover, -html|*.numberbox-input::-moz-number-spin-up:hover, -html|*.numberbox-input::-moz-number-spin-down:hover, xul|button:not([disabled="true"]):hover, xul|colorpicker[type="button"]:not([disabled="true"]):hover, xul|menulist:not([disabled="true"]):hover { @@ -213,8 +209,6 @@ xul|menulist:not([disabled="true"]):hover { html|button:enabled:hover:active, html|select:not([size]):not([multiple]):enabled:hover:active, -html|*.numberbox-input::-moz-number-spin-up:hover:active, -html|*.numberbox-input::-moz-number-spin-down:hover:active, xul|button:not([disabled="true"]):hover:active, xul|colorpicker[type="button"]:not([disabled="true"]):hover:active, xul|menulist[open="true"]:not([disabled="true"]) { @@ -223,7 +217,6 @@ xul|menulist[open="true"]:not([disabled="true"]) { html|button:disabled, html|select:disabled, -html|*.numberbox-input:disabled::-moz-number-spin-box, xul|button[disabled="true"], xul|colorpicker[type="button"][disabled="true"], xul|menulist[disabled="true"], @@ -354,22 +347,40 @@ html|*.help-button:hover:active { background-color: var(--in-content-category-background-active); } -html|*.numberbox-input::-moz-number-spin-up, -html|*.numberbox-input::-moz-number-spin-down { - padding: 5px 8px; - margin: 1px; - margin-inline-start: 10px; +xul|*.spinbuttons-button { min-height: initial; + margin-inline-start: 10px !important; + margin-inline-end: 2px !important; } -html|*.numberbox-input::-moz-number-spin-up { +xul|*.spinbuttons-up { + margin-top: 2px !important; border-radius: 1px 1px 0 0; - background-image: url("chrome://global/skin/arrow/arrow-up.gif"); } -html|*.numberbox-input::-moz-number-spin-down { +xul|*.spinbuttons-down { + margin-bottom: 2px !important; border-radius: 0 0 1px 1px; - background-image: url("chrome://global/skin/arrow/arrow-dn.gif"); +} + +xul|*.spinbuttons-button > xul|*.button-box { + padding: 1px 5px 2px !important; +} + +xul|*.spinbuttons-up > xul|*.button-box > xul|*.button-icon { + list-style-image: url("chrome://global/skin/arrow/arrow-up.gif"); +} + +xul|*.spinbuttons-up[disabled="true"] > xul|*.button-box > xul|*.button-icon { + list-style-image: url("chrome://global/skin/arrow/arrow-up-dis.gif"); +} + +xul|*.spinbuttons-down > xul|*.button-box > xul|*.button-icon { + list-style-image: url("chrome://global/skin/arrow/arrow-dn.gif"); +} + +xul|*.spinbuttons-down[disabled="true"] > xul|*.button-box > xul|*.button-icon { + list-style-image: url("chrome://global/skin/arrow/arrow-dn-dis.gif"); } xul|menulist:not([editable="true"]) > xul|*.menulist-dropmarker { diff --git a/toolkit/themes/shared/non-mac.jar.inc.mn b/toolkit/themes/shared/non-mac.jar.inc.mn index 4fc04384e6e1..584b7ef9c992 100644 --- a/toolkit/themes/shared/non-mac.jar.inc.mn +++ b/toolkit/themes/shared/non-mac.jar.inc.mn @@ -16,11 +16,14 @@ skin/classic/global/resizer.css (../../windows/global/resizer.css) skin/classic/global/richlistbox.css (../../windows/global/richlistbox.css) skin/classic/global/scrollbars.css (../../windows/global/xulscrollbars.css) + skin/classic/global/spinbuttons.css (../../windows/global/spinbuttons.css) skin/classic/global/tabprompts.css (../../windows/global/tabprompts.css) skin/classic/global/wizard.css (../../windows/global/wizard.css) skin/classic/global/arrow/arrow-dn.gif (../../windows/global/arrow/arrow-dn.gif) + skin/classic/global/arrow/arrow-dn-dis.gif (../../windows/global/arrow/arrow-dn-dis.gif) skin/classic/global/arrow/arrow-up.gif (../../windows/global/arrow/arrow-up.gif) + skin/classic/global/arrow/arrow-up-dis.gif (../../windows/global/arrow/arrow-up-dis.gif) skin/classic/global/arrow/panelarrow-horizontal.svg (../../windows/global/arrow/panelarrow-horizontal.svg) skin/classic/global/arrow/panelarrow-vertical.svg (../../windows/global/arrow/panelarrow-vertical.svg) diff --git a/toolkit/themes/windows/global/jar.mn b/toolkit/themes/windows/global/jar.mn index 52d30807f2c0..317332cfcf4b 100644 --- a/toolkit/themes/windows/global/jar.mn +++ b/toolkit/themes/windows/global/jar.mn @@ -36,8 +36,6 @@ toolkit.jar: skin/classic/global/arrow/arrow-lft-dis.gif (arrow/arrow-lft-dis.gif) skin/classic/global/arrow/arrow-rit.gif (arrow/arrow-rit.gif) skin/classic/global/arrow/arrow-rit-dis.gif (arrow/arrow-rit-dis.gif) - skin/classic/global/arrow/arrow-up-dis.gif (arrow/arrow-up-dis.gif) - skin/classic/global/arrow/arrow-dn-dis.gif (arrow/arrow-dn-dis.gif) skin/classic/global/dirListing/folder.png (dirListing/folder.png) skin/classic/global/dirListing/up.png (dirListing/up.png) skin/classic/global/icons/blacklist_favicon.png (icons/blacklist_favicon.png) diff --git a/toolkit/themes/windows/global/numberbox.css b/toolkit/themes/windows/global/numberbox.css index b3f3c455b6a4..b5289c4d8237 100644 --- a/toolkit/themes/windows/global/numberbox.css +++ b/toolkit/themes/windows/global/numberbox.css @@ -18,6 +18,7 @@ html|*.numberbox-input { text-align: right; } -textbox[type="number"][hidespinbuttons="true"] > html|*.numberbox-input { - -moz-appearance: textfield !important; +.numberbox-input-box { + -moz-box-align: center; } + diff --git a/toolkit/themes/windows/global/spinbuttons.css b/toolkit/themes/windows/global/spinbuttons.css new file mode 100644 index 000000000000..3e333bb47480 --- /dev/null +++ b/toolkit/themes/windows/global/spinbuttons.css @@ -0,0 +1,24 @@ +/* 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/. */ + +@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); + +spinbuttons { + -moz-appearance: spinner; + cursor: default; +} + +.spinbuttons-button { + min-width: 13px; + min-height: 11px; + margin: 0 !important; +} + +.spinbuttons-up { + -moz-appearance: spinner-upbutton; +} + +.spinbuttons-down { + -moz-appearance: spinner-downbutton; +} From 7f21ecd2bfba1326f03963eeabb7136c72f9f0cf Mon Sep 17 00:00:00 2001 From: Csoregi Natalia Date: Fri, 9 Feb 2018 17:20:53 +0200 Subject: [PATCH 19/41] Backed out 4 changesets (bug 1435296) for for failing devtools' browser_webconsole_check_stubs_console_api.js and mochitest's dom/smil/test/test_smilTimeEvents.xhtml. CLOSED TREE Backed out changeset 1f07c08daa41 (bug 1435296) Backed out changeset 89c121b45b30 (bug 1435296) Backed out changeset be9496eff7b8 (bug 1435296) Backed out changeset 2f94f155318e (bug 1435296) --- .../test/mochitest/file_animation_api.html | 26 +++++-------------- devtools/client/canvasdebugger/test/head.js | 4 --- .../server/tests/mochitest/memory-helpers.js | 3 --- docshell/test/chrome/test_bug453650.xul | 4 +-- dom/animation/AnimationUtils.h | 2 +- dom/events/test/test_eventTimeStamp.html | 13 +++------- modules/libpref/init/all.js | 2 +- ...seline_requirements_subject_common_name.js | 3 --- .../manager/ssl/tests/unit/test_cert_eku.js | 6 ----- ...diasource-getvideoplaybackquality.html.ini | 1 - .../performance-timeline.https.html.ini | 1 - .../resistfingerprinting/nsRFPService.cpp | 20 ++++++-------- .../resistfingerprinting/nsRFPService.h | 19 +++----------- 13 files changed, 27 insertions(+), 77 deletions(-) diff --git a/browser/components/resistfingerprinting/test/mochitest/file_animation_api.html b/browser/components/resistfingerprinting/test/mochitest/file_animation_api.html index 789afecbe94f..7b1cbad80d82 100644 --- a/browser/components/resistfingerprinting/test/mochitest/file_animation_api.html +++ b/browser/components/resistfingerprinting/test/mochitest/file_animation_api.html @@ -52,11 +52,9 @@ } } - // We are temporarily disabling this extra debugging failure because we expect to return false in some instances - // When we correct things we will re-enable it for debugging assistance - // opener.ok(false, "Looming Test Failure, Additional Debugging Info: Expected Precision: " + expectedPrecision + " Measured Value: " + x + - // " Rounded Vaue: " + rounded + " Fuzzy1: " + Math.abs(rounded - x + expectedPrecision) + - // " Fuzzy 2: " + Math.abs(rounded - x)); + ok(false, "Looming Test Failure, Additional Debugging Info: Expected Precision: " + expectedPrecision + " Measured Value: " + x + + " Rounded Vaue: " + rounded + " Fuzzy1: " + Math.abs(rounded - x + expectedPrecision) + + " Fuzzy 2: " + Math.abs(rounded - x)); return false; }; @@ -67,24 +65,14 @@ waitForCondition( () => animation.currentTime > 100, () => { - - // We have disabled Time Precision Reduction for CSS Animations, so we expect those tests to fail. - // If we are testing that preference, turn failures into successes and successes into failures - var maybeInvert = function(value) { - if (opener.prefName.includes("privacy.reduceTimerPrecision") && - !opener.prefName.includes("privacy.resistFingerprinting")) - return !value; - return value; - }; - - opener.ok(maybeInvert(isRounded(animation.startTime)), + opener.ok(isRounded(animation.startTime), "pref: " + opener.prefName + " - animation.startTime with precision " + expectedPrecision + " is not rounded: " + animation.startTime); - opener.ok(maybeInvert(isRounded(animation.currentTime)), + opener.ok(isRounded(animation.currentTime), "pref: " + opener.prefName + " - animation.currentTime with precision " + expectedPrecision + " is not rounded: " + animation.currentTime); - opener.ok(maybeInvert(isRounded(animation.timeline.currentTime)), + opener.ok(isRounded(animation.timeline.currentTime), "pref: " + opener.prefName + " - animation.timeline.currentTime with precision " + expectedPrecision + " is not rounded: " + animation.timeline.currentTime); if (document.timeline) { - opener.ok(maybeInvert(isRounded(document.timeline.currentTime)), + opener.ok(isRounded(document.timeline.currentTime), "pref: " + opener.prefName + " - document.timeline.currentTime with precision " + expectedPrecision + " is not rounded: " + document.timeline.currentTime); } opener.done(); diff --git a/devtools/client/canvasdebugger/test/head.js b/devtools/client/canvasdebugger/test/head.js index 203e87caf10a..afe2e3a0376f 100644 --- a/devtools/client/canvasdebugger/test/head.js +++ b/devtools/client/canvasdebugger/test/head.js @@ -40,9 +40,6 @@ const RAF_BEGIN_URL = EXAMPLE_URL + "doc_raf-begin.html"; var gEnableLogging = Services.prefs.getBoolPref("devtools.debugger.log"); Services.prefs.setBoolPref("devtools.debugger.log", false); -var gReduceTimePrecision = Services.prefs.getBoolPref("privacy.reduceTimerPrecision"); -Services.prefs.setBoolPref("privacy.reduceTimerPrecision", false); - // All tests are asynchronous. waitForExplicitFinish(); @@ -55,7 +52,6 @@ registerCleanupFunction(() => { flags.testing = false; Services.prefs.setBoolPref("devtools.debugger.log", gEnableLogging); Services.prefs.setBoolPref("devtools.canvasdebugger.enabled", gToolEnabled); - Services.prefs.setBoolPref("privacy.reduceTimerPrecision", gReduceTimePrecision); // Some of yhese tests use a lot of memory due to GL contexts, so force a GC // to help fragmentation. diff --git a/devtools/server/tests/mochitest/memory-helpers.js b/devtools/server/tests/mochitest/memory-helpers.js index ae04f80b3535..86057bdf57df 100644 --- a/devtools/server/tests/mochitest/memory-helpers.js +++ b/devtools/server/tests/mochitest/memory-helpers.js @@ -12,11 +12,8 @@ const { MemoryFront } = require("devtools/shared/fronts/memory"); // Always log packets when running tests. Services.prefs.setBoolPref("devtools.debugger.log", true); -var gReduceTimePrecision = Services.prefs.getBoolPref("privacy.reduceTimerPrecision"); -Services.prefs.setBoolPref("privacy.reduceTimerPrecision", false); SimpleTest.registerCleanupFunction(function () { Services.prefs.clearUserPref("devtools.debugger.log"); - Services.prefs.setBoolPref("privacy.reduceTimerPrecision", gReduceTimePrecision); }); function startServerAndGetSelectedTabMemory() { diff --git a/docshell/test/chrome/test_bug453650.xul b/docshell/test/chrome/test_bug453650.xul index 4dec60a6112e..32e3ea1df720 100644 --- a/docshell/test/chrome/test_bug453650.xul +++ b/docshell/test/chrome/test_bug453650.xul @@ -60,7 +60,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=453650 } info("times: " + start + ", " + end); - ok(start <= end, "reflow start time lower than end time"); + ok(start < end, "reflow start time lower than end time"); done(); }, @@ -72,7 +72,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=453650 } info("times: " + start + ", " + end); - ok(start <= end, "reflow start time lower than end time"); + ok(start < end, "reflow start time lower than end time"); done(); }, diff --git a/dom/animation/AnimationUtils.h b/dom/animation/AnimationUtils.h index f19e94182ca0..04b5f98812bb 100644 --- a/dom/animation/AnimationUtils.h +++ b/dom/animation/AnimationUtils.h @@ -33,7 +33,7 @@ public: if (!aTime.IsNull()) { result.SetValue( - nsRFPService::ReduceTimePrecisionAsMSecs(aTime.Value().ToMilliseconds(), TimerPrecisionType::RFPOnly) + nsRFPService::ReduceTimePrecisionAsMSecs(aTime.Value().ToMilliseconds()) ); } diff --git a/dom/events/test/test_eventTimeStamp.html b/dom/events/test/test_eventTimeStamp.html index 7141562ec1cb..fe9b10fa0add 100644 --- a/dom/events/test/test_eventTimeStamp.html +++ b/dom/events/test/test_eventTimeStamp.html @@ -38,13 +38,9 @@ SimpleTest.requestFlakyTimeout("untriaged"); // We don't use SpecialPowers.pushPrefEnv since it can delay the test // function until after the load event has fired which means we can't // test the timestamp of the load event. -const kHighResTimestampsPrefName = "dom.event.highrestimestamp.enabled"; -var highRestimerPrevPrefValue = SpecialPowers.getBoolPref(kHighResTimestampsPrefName); -SpecialPowers.setBoolPref(kHighResTimestampsPrefName, true); - -const kReduceTimePrecisionPrefName = "privacy.reduceTimerPrecision"; -var reduceTimePrecisionPrevPrefValue = SpecialPowers.getBoolPref(kReduceTimePrecisionPrefName); -SpecialPowers.setBoolPref(kReduceTimePrecisionPrefName, false); +const kPrefName = "dom.event.highrestimestamp.enabled"; +var prevPrefValue = SpecialPowers.getBoolPref(kPrefName); +SpecialPowers.setBoolPref(kPrefName, true); testRegularEvents(); // Event.timeStamp should be relative to the time origin which is: @@ -115,8 +111,7 @@ function testSharedWorkerEvents() { } var finishTests = function() { - SpecialPowers.setBoolPref(kHighResTimestampsPrefName, highRestimerPrevPrefValue); - SpecialPowers.setBoolPref(kReduceTimePrecisionPrefName, reduceTimePrecisionPrevPrefValue); + SpecialPowers.setBoolPref(kPrefName, prevPrefValue); SimpleTest.finish(); }; diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 4d0e6ed7bf3f..e06bc5f61fbd 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -1409,7 +1409,7 @@ pref("privacy.resistFingerprinting", false); // File.lastModified, audioContext.currentTime, canvas.captureStream.currentTime pref("privacy.reduceTimerPrecision", true); // Dynamically tune the resolution of the timer reduction for both of the two above prefs -pref("privacy.resistFingerprinting.reduceTimerPrecision.microseconds", 2000); +pref("privacy.resistFingerprinting.reduceTimerPrecision.microseconds", 20); // Lower the priority of network loads for resources on the tracking protection list. // Note that this requires the privacy.trackingprotection.annotate_channels pref to be on in order to have any effect. #ifdef NIGHTLY_BUILD diff --git a/security/manager/ssl/tests/unit/test_baseline_requirements_subject_common_name.js b/security/manager/ssl/tests/unit/test_baseline_requirements_subject_common_name.js index 26580890f902..291f1cf50d1c 100644 --- a/security/manager/ssl/tests/unit/test_baseline_requirements_subject_common_name.js +++ b/security/manager/ssl/tests/unit/test_baseline_requirements_subject_common_name.js @@ -40,11 +40,8 @@ function run_test() { registerCleanupFunction(() => { Services.prefs.clearUserPref("security.pki.name_matching_mode"); Services.prefs.clearUserPref("security.test.built_in_root_hash"); - Services.prefs.clearUserPref("privacy.reduceTimerPrecision"); }); - Services.prefs.setBoolPref("privacy.reduceTimerPrecision", false); - loadCertWithTrust("ca", "CTu,,"); // When verifying a certificate, if the trust anchor is not a built-in root, diff --git a/security/manager/ssl/tests/unit/test_cert_eku.js b/security/manager/ssl/tests/unit/test_cert_eku.js index c91df26ba20a..65bf584cf9fc 100644 --- a/security/manager/ssl/tests/unit/test_cert_eku.js +++ b/security/manager/ssl/tests/unit/test_cert_eku.js @@ -33,13 +33,7 @@ function checkCertOn25August2016(cert, expectedResult) { certificateUsageSSLServer, VALIDATION_TIME); } - function run_test() { - registerCleanupFunction(() => { - Services.prefs.clearUserPref("privacy.reduceTimerPrecision"); - }); - Services.prefs.setBoolPref("privacy.reduceTimerPrecision", false); - loadCertWithTrust("ca", "CTu,,"); // end-entity has id-kp-serverAuth => success checkEndEntity(certFromFile("ee-SA"), PRErrorCodeSuccess); diff --git a/testing/web-platform/meta/media-source/mediasource-getvideoplaybackquality.html.ini b/testing/web-platform/meta/media-source/mediasource-getvideoplaybackquality.html.ini index caa5317f627f..79384c3d0ed3 100644 --- a/testing/web-platform/meta/media-source/mediasource-getvideoplaybackquality.html.ini +++ b/testing/web-platform/meta/media-source/mediasource-getvideoplaybackquality.html.ini @@ -1,4 +1,3 @@ -prefs: [privacy.reduceTimerPrecision:false] [mediasource-getvideoplaybackquality.html] [Test the totalFrameDelay attribute of HTMLVideoElement.getVideoPlaybackQuality() with MediaSource API] expected: FAIL diff --git a/testing/web-platform/meta/service-workers/service-worker/performance-timeline.https.html.ini b/testing/web-platform/meta/service-workers/service-worker/performance-timeline.https.html.ini index d7cc3b02a95f..5ad18e9a06ff 100644 --- a/testing/web-platform/meta/service-workers/service-worker/performance-timeline.https.html.ini +++ b/testing/web-platform/meta/service-workers/service-worker/performance-timeline.https.html.ini @@ -1,4 +1,3 @@ -prefs: [privacy.reduceTimerPrecision:false] [performance-timeline.https.html] expected: TIMEOUT [Resource Timing] diff --git a/toolkit/components/resistfingerprinting/nsRFPService.cpp b/toolkit/components/resistfingerprinting/nsRFPService.cpp index eaf90ab26244..6c6d50de2f96 100644 --- a/toolkit/components/resistfingerprinting/nsRFPService.cpp +++ b/toolkit/components/resistfingerprinting/nsRFPService.cpp @@ -43,7 +43,7 @@ static mozilla::LazyLogModule gResistFingerprintingLog("nsResistFingerprinting") #define RESIST_FINGERPRINTING_PREF "privacy.resistFingerprinting" #define RFP_TIMER_PREF "privacy.reduceTimerPrecision" #define RFP_TIMER_VALUE_PREF "privacy.resistFingerprinting.reduceTimerPrecision.microseconds" -#define RFP_TIMER_VALUE_DEFAULT 2000 +#define RFP_TIMER_VALUE_DEFAULT 20 #define RFP_SPOOFED_FRAMES_PER_SEC_PREF "privacy.resistFingerprinting.video_frames_per_sec" #define RFP_SPOOFED_DROPPED_RATIO_PREF "privacy.resistFingerprinting.video_dropped_ratio" #define RFP_TARGET_VIDEO_RES_PREF "privacy.resistFingerprinting.target_video_res" @@ -107,21 +107,17 @@ nsRFPService::IsResistFingerprintingEnabled() /* static */ bool -nsRFPService::IsTimerPrecisionReductionEnabled(TimerPrecisionType aType) +nsRFPService::IsTimerPrecisionReductionEnabled() { - if (aType == TimerPrecisionType::RFPOnly) { - return IsResistFingerprintingEnabled(); - } - return (sPrivacyTimerPrecisionReduction || IsResistFingerprintingEnabled()) && TimerResolution() != 0; } /* static */ double -nsRFPService::ReduceTimePrecisionAsMSecs(double aTime, TimerPrecisionType aType /* = TimerPrecisionType::All */) +nsRFPService::ReduceTimePrecisionAsMSecs(double aTime) { - if (!IsTimerPrecisionReductionEnabled(aType)) { + if (!IsTimerPrecisionReductionEnabled()) { return aTime; } const double resolutionMSec = TimerResolution() / 1000.0; @@ -136,9 +132,9 @@ nsRFPService::ReduceTimePrecisionAsMSecs(double aTime, TimerPrecisionType aType /* static */ double -nsRFPService::ReduceTimePrecisionAsUSecs(double aTime, TimerPrecisionType aType /* = TimerPrecisionType::All */) +nsRFPService::ReduceTimePrecisionAsUSecs(double aTime) { - if (!IsTimerPrecisionReductionEnabled(aType)) { + if (!IsTimerPrecisionReductionEnabled()) { return aTime; } double resolutionUSec = TimerResolution(); @@ -161,9 +157,9 @@ nsRFPService::CalculateTargetVideoResolution(uint32_t aVideoQuality) /* static */ double -nsRFPService::ReduceTimePrecisionAsSecs(double aTime, TimerPrecisionType aType /* = TimerPrecisionType::All */) +nsRFPService::ReduceTimePrecisionAsSecs(double aTime) { - if (!IsTimerPrecisionReductionEnabled(aType)) { + if (!IsTimerPrecisionReductionEnabled()) { return aTime; } double resolutionUSec = TimerResolution(); diff --git a/toolkit/components/resistfingerprinting/nsRFPService.h b/toolkit/components/resistfingerprinting/nsRFPService.h index b491ebe854f3..cf17c46ac51c 100644 --- a/toolkit/components/resistfingerprinting/nsRFPService.h +++ b/toolkit/components/resistfingerprinting/nsRFPService.h @@ -148,11 +148,6 @@ public: nsString mKey; }; -enum TimerPrecisionType { - All = 1, - RFPOnly = 2 -}; - class nsRFPService final : public nsIObserver { public: @@ -161,18 +156,12 @@ public: static nsRFPService* GetOrCreate(); static bool IsResistFingerprintingEnabled(); - static bool IsTimerPrecisionReductionEnabled(TimerPrecisionType aType); + static bool IsTimerPrecisionReductionEnabled(); // The following Reduce methods can be called off main thread. - static double ReduceTimePrecisionAsMSecs( - double aTime, - TimerPrecisionType aType = TimerPrecisionType::All); - static double ReduceTimePrecisionAsUSecs( - double aTime, - TimerPrecisionType aType = TimerPrecisionType::All); - static double ReduceTimePrecisionAsSecs( - double aTime, - TimerPrecisionType aType = TimerPrecisionType::All); + static double ReduceTimePrecisionAsMSecs(double aTime); + static double ReduceTimePrecisionAsUSecs(double aTime); + static double ReduceTimePrecisionAsSecs(double aTime); // This method calculates the video resolution (i.e. height x width) based // on the video quality (480p, 720p, etc). From a4e2f783c16ba25ff4c2d5f9355710a7de92049d Mon Sep 17 00:00:00 2001 From: Julian Descottes Date: Fri, 9 Feb 2018 13:28:11 +0100 Subject: [PATCH 20/41] Bug 1406022 - remove browser_webconsole_reflow.js;r=nchevobbe MozReview-Commit-ID: GO2jdUugR58 --HG-- extra : rebase_source : 2c36a08c2c1b910a2849dce7634200d87dcc8bf8 --- .../test/mochitest/browser.ini | 2 -- .../mochitest/browser_webconsole_reflow.js | 33 ------------------- 2 files changed, 35 deletions(-) delete mode 100644 devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_reflow.js diff --git a/devtools/client/webconsole/new-console-output/test/mochitest/browser.ini b/devtools/client/webconsole/new-console-output/test/mochitest/browser.ini index 4c79cab11234..f2fed3f85ecb 100644 --- a/devtools/client/webconsole/new-console-output/test/mochitest/browser.ini +++ b/devtools/client/webconsole/new-console-output/test/mochitest/browser.ini @@ -330,8 +330,6 @@ skip-if = true # Bug 1405641 [browser_webconsole_persist.js] [browser_webconsole_prune_scroll.js] skip-if = true # Bug 1404832 -[browser_webconsole_reflow.js] -skip-if = true # Bug 1406022 [browser_webconsole_reopen_closed_tab.js] [browser_webconsole_repeat_different_objects.js] [browser_webconsole_repeated_messages_accuracy.js] diff --git a/devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_reflow.js b/devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_reflow.js deleted file mode 100644 index 86caa10e050f..000000000000 --- a/devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_reflow.js +++ /dev/null @@ -1,33 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -const TEST_URI = "data:text/html;charset=utf-8,Web Console test for " + - "reflow activity"; - -add_task(function* () { - let { browser } = yield loadTab(TEST_URI); - - let hud = yield openConsole(); - - function onReflowListenersReady() { - browser.contentDocument.body.style.display = "none"; - browser.contentDocument.body.clientTop; - } - - Services.prefs.setBoolPref("devtools.webconsole.filter.csslog", true); - hud.ui._updateReflowActivityListener(onReflowListenersReady); - Services.prefs.clearUserPref("devtools.webconsole.filter.csslog"); - - yield waitForMessages({ - webconsole: hud, - messages: [{ - text: /reflow: /, - category: CATEGORY_CSS, - severity: SEVERITY_LOG, - }], - }); -}); From da3597c3bbaad0cb0c11989a476e9fe0b9ee477d Mon Sep 17 00:00:00 2001 From: Gijs Kruitbosch Date: Wed, 7 Feb 2018 22:07:08 +0000 Subject: [PATCH 21/41] Bug 1436559 - stop doing busy-work in setOverLink and make textToSubURI available on Services.jsm, r=florian MozReview-Commit-ID: F63kE4GE67B --HG-- extra : rebase_source : e1dbae3f45b532e2f498c5e815a98531398143ea --- browser/base/content/browser.js | 18 +++++++++--------- browser/base/content/nsContextMenu.js | 6 ++---- browser/base/content/tabbrowser.xml | 7 +++---- .../components/search/test/browser_426329.js | 4 +--- toolkit/components/places/UnifiedComplete.js | 8 ++------ toolkit/components/search/nsSearchService.js | 11 +++++------ toolkit/content/contentAreaUtils.js | 4 +--- .../file_autocomplete_with_composition.js | 2 ++ .../tests/chrome/test_autocomplete2.xul | 2 ++ .../tests/chrome/test_autocomplete3.xul | 2 ++ .../tests/chrome/test_autocomplete4.xul | 2 ++ .../tests/chrome/test_autocomplete5.xul | 2 ++ .../chrome/test_autocomplete_delayOnPaste.xul | 1 + .../chrome/test_autocomplete_emphasis.xul | 2 ++ ...st_autocomplete_placehold_last_complete.xul | 1 + toolkit/content/widgets/autocomplete.xml | 8 +------- toolkit/modules/Finder.jsm | 5 +---- toolkit/modules/Services.jsm | 1 + 18 files changed, 40 insertions(+), 46 deletions(-) diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index ef9a020e8f5e..cd1b4ef3754c 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -4334,17 +4334,17 @@ var XULBrowserWindow = { }, setOverLink(url, anchorElt) { - const textToSubURI = Cc["@mozilla.org/intl/texttosuburi;1"]. - getService(Ci.nsITextToSubURI); - url = textToSubURI.unEscapeURIForUI("UTF-8", url); + if (url) { + url = Services.textToSubURI.unEscapeURIForUI("UTF-8", url); - // Encode bidirectional formatting characters. - // (RFC 3987 sections 3.2 and 4.1 paragraph 6) - url = url.replace(/[\u200e\u200f\u202a\u202b\u202c\u202d\u202e]/g, - encodeURIComponent); + // Encode bidirectional formatting characters. + // (RFC 3987 sections 3.2 and 4.1 paragraph 6) + url = url.replace(/[\u200e\u200f\u202a\u202b\u202c\u202d\u202e]/g, + encodeURIComponent); - if (gURLBar && gURLBar._mayTrimURLs /* corresponds to browser.urlbar.trimURLs */) - url = trimURL(url); + if (gURLBar && gURLBar._mayTrimURLs /* corresponds to browser.urlbar.trimURLs */) + url = trimURL(url); + } this.overLink = url; LinkTargetDisplay.update(); diff --git a/browser/base/content/nsContextMenu.js b/browser/base/content/nsContextMenu.js index f6e3ba768ae8..f8d633de15df 100644 --- a/browser/base/content/nsContextMenu.js +++ b/browser/base/content/nsContextMenu.js @@ -1275,10 +1275,8 @@ nsContextMenu.prototype = { // Let's try to unescape it using a character set // in case the address is not ASCII. try { - const textToSubURI = Cc["@mozilla.org/intl/texttosuburi;1"]. - getService(Ci.nsITextToSubURI); - addresses = textToSubURI.unEscapeURIForUI(gContextMenuContentData.charSet, - addresses); + addresses = Services.textToSubURI.unEscapeURIForUI(gContextMenuContentData.charSet, + addresses); } catch (ex) { // Do nothing. } diff --git a/browser/base/content/tabbrowser.xml b/browser/base/content/tabbrowser.xml index 155811a27a7b..315d164ae8fd 100644 --- a/browser/base/content/tabbrowser.xml +++ b/browser/base/content/tabbrowser.xml @@ -1646,10 +1646,6 @@ // Let's try to unescape it using a character set // in case the URI is not ASCII. try { - var characterSet = browser.characterSet; - const textToSubURI = Components.classes["@mozilla.org/intl/texttosuburi;1"] - .getService(Components.interfaces.nsITextToSubURI); - title = textToSubURI.unEscapeNonAsciiURI(characterSet, title); // If it's a long data: URI that uses base64 encoding, truncate to // a reasonable length rather than trying to display the entire thing. // We can't shorten arbitrary URIs like this, as bidi etc might mean @@ -1658,6 +1654,9 @@ // (See bug 1408854.) if (title.length > 500 && title.match(/^data:[^,]+;base64,/)) { title = title.substring(0, 500) + "\u2026"; + } else { + var characterSet = browser.characterSet; + title = Services.textToSubURI.unEscapeNonAsciiURI(characterSet, title); } } catch (ex) { /* Do nothing. */ } } else { diff --git a/browser/components/search/test/browser_426329.js b/browser/components/search/test/browser_426329.js index 7914bbeb8498..d03f94eda15d 100644 --- a/browser/components/search/test/browser_426329.js +++ b/browser/components/search/test/browser_426329.js @@ -4,9 +4,7 @@ ChromeUtils.defineModuleGetter(this, "FormHistory", function expectedURL(aSearchTerms) { const ENGINE_HTML_BASE = "http://mochi.test:8888/browser/browser/components/search/test/test.html"; - var textToSubURI = Cc["@mozilla.org/intl/texttosuburi;1"]. - getService(Ci.nsITextToSubURI); - var searchArg = textToSubURI.ConvertAndEscape("utf-8", aSearchTerms); + var searchArg = Services.textToSubURI.ConvertAndEscape("utf-8", aSearchTerms); return ENGINE_HTML_BASE + "?test=" + searchArg; } diff --git a/toolkit/components/places/UnifiedComplete.js b/toolkit/components/places/UnifiedComplete.js index 621c3f6c2560..c8ad2ff016df 100644 --- a/toolkit/components/places/UnifiedComplete.js +++ b/toolkit/components/places/UnifiedComplete.js @@ -324,10 +324,6 @@ XPCOMUtils.defineLazyModuleGetters(this, { ProfileAge: "resource://gre/modules/ProfileAge.jsm", }); -XPCOMUtils.defineLazyServiceGetter(this, "textURIService", - "@mozilla.org/intl/texttosuburi;1", - "nsITextToSubURI"); - XPCOMUtils.defineLazyPreferenceGetter(this, "syncUsernamePref", "services.sync.username"); @@ -800,7 +796,7 @@ function Search(searchString, searchParam, autocompleteListener, let strippedOriginalSearchString = stripPrefix(this._trimmedOriginalSearchString.toLowerCase()); this._searchString = - textURIService.unEscapeURIForUI("UTF-8", strippedOriginalSearchString); + Services.textToSubURI.unEscapeURIForUI("UTF-8", strippedOriginalSearchString); // The protocol and the host are lowercased by nsIURI, so it's fine to // lowercase the typed prefix, to add it back to the results later. @@ -1753,7 +1749,7 @@ Search.prototype = { // to be displayed to the user, and in any case the front-end should not // rely on it being canonical. let escapedURL = uri.displaySpec; - let displayURL = textURIService.unEscapeURIForUI("UTF-8", uri.displaySpec); + let displayURL = Services.textToSubURI.unEscapeURIForUI("UTF-8", escapedURL); let value = PlacesUtils.mozActionURI("visiturl", { url: escapedURL, diff --git a/toolkit/components/search/nsSearchService.js b/toolkit/components/search/nsSearchService.js index 6f2bdcaa4d6d..0e487231313e 100644 --- a/toolkit/components/search/nsSearchService.js +++ b/toolkit/components/search/nsSearchService.js @@ -22,7 +22,6 @@ XPCOMUtils.defineLazyModuleGetters(this, { }); XPCOMUtils.defineLazyServiceGetters(this, { - gTextToSubURI: ["@mozilla.org/intl/texttosuburi;1", "nsITextToSubURI"], gEnvironment: ["@mozilla.org/process/environment;1", "nsIEnvironment"], gChromeReg: ["@mozilla.org/chrome/chrome-registry;1", "nsIChromeRegistry"], }); @@ -2420,10 +2419,10 @@ Engine.prototype = { LOG("getSubmission: In data: \"" + aData + "\"; Purpose: \"" + aPurpose + "\""); var data = ""; try { - data = gTextToSubURI.ConvertAndEscape(this.queryCharset, aData); + data = Services.textToSubURI.ConvertAndEscape(this.queryCharset, aData); } catch (ex) { LOG("getSubmission: Falling back to default queryCharset!"); - data = gTextToSubURI.ConvertAndEscape(DEFAULT_QUERY_CHARSET, aData); + data = Services.textToSubURI.ConvertAndEscape(DEFAULT_QUERY_CHARSET, aData); } LOG("getSubmission: Out data: \"" + data + "\""); return url.getSubmission(data, this, aPurpose); @@ -4441,9 +4440,9 @@ SearchService.prototype = { // Decode the terms using the charset defined in the search engine. let terms; try { - terms = gTextToSubURI.UnEscapeAndConvert( - mapEntry.engine.queryCharset, - encodedTerms.replace(/\+/g, " ")); + terms = Services.textToSubURI.UnEscapeAndConvert( + mapEntry.engine.queryCharset, + encodedTerms.replace(/\+/g, " ")); } catch (ex) { // Decoding errors will cause this match to be ignored. LOG("Parameter decoding failed. Charset: " + diff --git a/toolkit/content/contentAreaUtils.js b/toolkit/content/contentAreaUtils.js index ca6192af5c24..230a4f3b0d4a 100644 --- a/toolkit/content/contentAreaUtils.js +++ b/toolkit/content/contentAreaUtils.js @@ -1005,9 +1005,7 @@ function getDefaultFileName(aDefaultFileName, aURI, aDocument, var url = aURI.QueryInterface(Components.interfaces.nsIURL); if (url.fileName != "") { // 3) Use the actual file name, if present - var textToSubURI = Components.classes["@mozilla.org/intl/texttosuburi;1"] - .getService(Components.interfaces.nsITextToSubURI); - return validateFileName(textToSubURI.unEscapeURIForUI("UTF-8", url.fileName)); + return validateFileName(Services.textToSubURI.unEscapeURIForUI("UTF-8", url.fileName)); } } catch (e) { // This is something like a data: and so forth URI... no filename here. diff --git a/toolkit/content/tests/chrome/file_autocomplete_with_composition.js b/toolkit/content/tests/chrome/file_autocomplete_with_composition.js index b499fc21755c..0d05c945c836 100644 --- a/toolkit/content/tests/chrome/file_autocomplete_with_composition.js +++ b/toolkit/content/tests/chrome/file_autocomplete_with_composition.js @@ -1,6 +1,8 @@ // nsDoTestsForAutoCompleteWithComposition tests autocomplete with composition. // Users must include SimpleTest.js and EventUtils.js. +ChromeUtils.import("resource://gre/modules/Services.jsm"); + function waitForCondition(condition, nextTest) { var tries = 0; var interval = setInterval(function() { diff --git a/toolkit/content/tests/chrome/test_autocomplete2.xul b/toolkit/content/tests/chrome/test_autocomplete2.xul index 7ac32d421e47..f2accb5ab040 100644 --- a/toolkit/content/tests/chrome/test_autocomplete2.xul +++ b/toolkit/content/tests/chrome/test_autocomplete2.xul @@ -17,6 +17,8 @@ + diff --git a/gfx/layers/apz/test/mochitest/test_bug1151663.html b/gfx/layers/apz/test/mochitest/test_bug1151663.html index 10810c6caf6b..3b081fdb53f9 100644 --- a/gfx/layers/apz/test/mochitest/test_bug1151663.html +++ b/gfx/layers/apz/test/mochitest/test_bug1151663.html @@ -8,6 +8,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1151663 Test for Bug 1151663 +