diff --git a/.taskcluster.yml b/.taskcluster.yml index 1759d3806b7b..95d250d5b699 100644 --- a/.taskcluster.yml +++ b/.taskcluster.yml @@ -45,6 +45,7 @@ # taskGroupId, // targetted taskGroupId # action: {name, title, description, taskGroupId, symbol, repo_scope, cb_name} # ownTaskId: // taskId of the task that will be created +# clientId: // clientId that triggered this hook # } version: 1 @@ -58,6 +59,11 @@ tasks: ownerEmail: {$if: '"@" in push.owner', then: '${push.owner}', else: '${push.owner}@noreply.mozilla.org'} # ensure there's no trailing `/` on the repo URL repoUrl: {$if: 'repository.url[-1] == "/"', then: {$eval: 'repository.url[:-1]'}, else: {$eval: 'repository.url'}} + # expire try earlier than other branches + expires: + $if: 'repository.project == "try"' + then: {$fromNow: '28 days'} + else: {$fromNow: '1 year'} in: taskId: {$if: 'tasks_for != "action"', then: '${ownTaskId}'} taskGroupId: @@ -70,7 +76,7 @@ tasks: created: {$fromNow: ''} deadline: {$fromNow: '1 day'} - expires: {$fromNow: '1 year 1 second'} # 1 second so artifacts expire first, despite rounding errors + expires: {$eval: 'expires'} metadata: $merge: - owner: "${ownerEmail}" @@ -254,7 +260,7 @@ tasks: 'public': type: 'directory' path: '/builds/worker/artifacts' - expires: {$fromNow: '1 year'} + expires: {$eval: expires} extra: $merge: diff --git a/browser/actors/NetErrorChild.jsm b/browser/actors/NetErrorChild.jsm index b0b9cd80abd0..f6aa0742b96f 100644 --- a/browser/actors/NetErrorChild.jsm +++ b/browser/actors/NetErrorChild.jsm @@ -483,16 +483,6 @@ class NetErrorChild extends ActorChild { if (Math.abs(difference) > 60 * 60 * 24 && (now - lastFetched) <= 60 * 60 * 24 * 5 && certRange.notBefore < approximateDate && certRange.notAfter > approximateDate) { clockSkew = true; - let systemDate = formatter.format(new Date()); - // negative difference means local time is behind server time - approximateDate = formatter.format(new Date(approximateDate)); - - doc.getElementById("wrongSystemTime_URL").textContent = doc.location.hostname; - doc.getElementById("wrongSystemTime_systemDate").textContent = systemDate; - doc.getElementById("wrongSystemTime_actualDate").textContent = approximateDate; - - doc.getElementById("errorShortDesc").style.display = "none"; - doc.getElementById("wrongSystemTimePanel").style.display = "block"; // If there is no clock skew with Kinto servers, check against the build date. // (The Kinto ping could have happened when the time was still right, or not at all) @@ -512,11 +502,6 @@ class NetErrorChild extends ActorChild { // since the build date. if (buildDate > systemDate && new Date(certRange.notAfter) > buildDate) { clockSkew = true; - - doc.getElementById("wrongSystemTimeWithoutReference_URL") - .textContent = doc.location.hostname; - doc.getElementById("wrongSystemTimeWithoutReference_systemDate") - .textContent = formatter.format(systemDate); } } @@ -530,7 +515,6 @@ class NetErrorChild extends ActorChild { doc.querySelector(".title-text").textContent = clockErrTitle.textContent; let desc = doc.getElementById("errorShortDescText"); doc.getElementById("errorShortDesc").style.display = "block"; - doc.getElementById("wrongSystemTimePanel").style.display = "none"; doc.getElementById("certificateErrorReporting").style.display = "none"; if (desc) { // eslint-disable-next-line no-unsanitized/property diff --git a/browser/base/content/aboutNetError.xhtml b/browser/base/content/aboutNetError.xhtml index 72a4e2db6cc3..1e703c5b0c07 100644 --- a/browser/base/content/aboutNetError.xhtml +++ b/browser/base/content/aboutNetError.xhtml @@ -170,14 +170,6 @@ -
- &certerror.wrongSystemTime2; -
- -
- &certerror.wrongSystemTimeWithoutReference; -
-
diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index 48b26696ddf6..83e146e63c94 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -3726,10 +3726,8 @@ var browserDragAndDrop = { return Services.droppedLinkHandler.getCSP(aEvent); }, - validateURIsForDrop(aEvent, aURIsCount, aURIs) { - return Services.droppedLinkHandler.validateURIsForDrop(aEvent, - aURIsCount, - aURIs); + validateURIsForDrop(aEvent, aURIs) { + return Services.droppedLinkHandler.validateURIsForDrop(aEvent, aURIs); }, dropLinks(aEvent, aDisallowInherit) { @@ -3752,7 +3750,7 @@ var homeButtonObserver = { } try { - browserDragAndDrop.validateURIsForDrop(aEvent, urls.length, urls); + browserDragAndDrop.validateURIsForDrop(aEvent, urls); } catch (e) { return; } diff --git a/browser/base/content/nsContextMenu.js b/browser/base/content/nsContextMenu.js index 2e698612a23b..1c7baa01c9b6 100644 --- a/browser/base/content/nsContextMenu.js +++ b/browser/base/content/nsContextMenu.js @@ -781,7 +781,10 @@ nsContextMenu.prototype = { }, openPasswordManager() { - LoginHelper.openPasswordManager(window, gContextMenuContentData.documentURIObject.host); + LoginHelper.openPasswordManager(window, { + filterString: gContextMenuContentData.documentURIObject.host, + entryPoint: "contextmenu", + }); }, inspectNode() { diff --git a/browser/base/content/pageinfo/security.js b/browser/base/content/pageinfo/security.js index 49c47244d211..a992c0b30e9b 100644 --- a/browser/base/content/pageinfo/security.js +++ b/browser/base/content/pageinfo/security.js @@ -180,7 +180,10 @@ var security = { * Open the login manager window */ viewPasswords() { - LoginHelper.openPasswordManager(window, this._getSecurityInfo().hostName); + LoginHelper.openPasswordManager(window, { + filterString: this._getSecurityInfo().hostName, + entryPoint: "pageinfo", + }); }, _cert: null, diff --git a/browser/base/content/test/siteIdentity/browser.ini b/browser/base/content/test/siteIdentity/browser.ini index 45f8b1f389a9..e2be05580426 100644 --- a/browser/base/content/test/siteIdentity/browser.ini +++ b/browser/base/content/test/siteIdentity/browser.ini @@ -114,3 +114,4 @@ support-files = support-files = file_mixedPassiveContent.html file_bug1045809_1.html +[browser_deprecatedTLSVersions.js] diff --git a/browser/base/content/test/siteIdentity/browser_deprecatedTLSVersions.js b/browser/base/content/test/siteIdentity/browser_deprecatedTLSVersions.js new file mode 100644 index 000000000000..561856584bf8 --- /dev/null +++ b/browser/base/content/test/siteIdentity/browser_deprecatedTLSVersions.js @@ -0,0 +1,61 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + * + * Tests for Bug 1535210 - Set SSL STATE_IS_BROKEN flag for TLS1.0 and TLS 1.1 connections + */ + +const HTTPS_TLS1_0 = "https://tls1.example.com"; +const HTTPS_TLS1_1 = "https://tls11.example.com"; +const HTTPS_TLS1_2 = "https://tls12.example.com"; +const HTTPS_TLS1_3 = "https://tls13.example.com"; + + +function getIdentityMode(aWindow = window) { + return aWindow.document.getElementById("identity-box").className; +} + +function getConnectionState() { + // Prevents items that are being lazy loaded causing issues + document.getElementById("identity-box").click(); + gIdentityHandler.refreshIdentityPopup(); + return document.getElementById("identity-popup").getAttribute("connection"); +} + +add_task(async function() { + await BrowserTestUtils.withNewTab("about:blank", async function(browser) { + // Try deprecated versions + await BrowserTestUtils.loadURI(browser, HTTPS_TLS1_0); + await BrowserTestUtils.browserLoaded(browser); + isSecurityState(browser, "broken"); + is(getIdentityMode(), "unknownIdentity weakCipher", "Identity should be unknownIdentity"); + is(getConnectionState(), "not-secure", "connectionState should be not-secure"); + + await BrowserTestUtils.loadURI(browser, HTTPS_TLS1_1); + await BrowserTestUtils.browserLoaded(browser); + isSecurityState(browser, "broken"); + is(getIdentityMode(), "unknownIdentity weakCipher", "Identity should be unknownIdentity"); + is(getConnectionState(), "not-secure", "connectionState should be not-secure"); + + // Transition to secure + await BrowserTestUtils.loadURI(browser, HTTPS_TLS1_2); + await BrowserTestUtils.browserLoaded(browser); + isSecurityState(browser, "secure"); + is(getIdentityMode(), "verifiedDomain", "Identity should be verified"); + is(getConnectionState(), "secure", "connectionState should be secure"); + + // Transition back to broken + await BrowserTestUtils.loadURI(browser, HTTPS_TLS1_1); + await BrowserTestUtils.browserLoaded(browser); + isSecurityState(browser, "broken"); + is(getIdentityMode(), "unknownIdentity weakCipher", "Identity should be unknownIdentity"); + is(getConnectionState(), "not-secure", "connectionState should be not-secure"); + + // TLS1.3 for completeness + await BrowserTestUtils.loadURI(browser, HTTPS_TLS1_3); + await BrowserTestUtils.browserLoaded(browser); + isSecurityState(browser, "secure"); + is(getIdentityMode(), "verifiedDomain", "Identity should be verified"); + is(getConnectionState(), "secure", "connectionState should be secure"); + }); +}); diff --git a/browser/base/content/test/static/browser_misused_characters_in_strings.js b/browser/base/content/test/static/browser_misused_characters_in_strings.js index c9aaef613897..9bd46b1b6719 100644 --- a/browser/base/content/test/static/browser_misused_characters_in_strings.js +++ b/browser/base/content/test/static/browser_misused_characters_in_strings.js @@ -32,14 +32,6 @@ let gWhitelist = [{ file: "netError.dtd", key: "inadequateSecurityError.longDesc", type: "single-quote", - }, { - file: "netError.dtd", - key: "certerror.wrongSystemTime2", - type: "single-quote", - }, { - file: "netError.dtd", - key: "certerror.wrongSystemTimeWithoutReference", - type: "single-quote", }, { file: "netError.dtd", key: "clockSkewError.longDesc", diff --git a/browser/components/customizableui/content/panelUI.inc.xul b/browser/components/customizableui/content/panelUI.inc.xul index fafa026c2125..62c73ee363ad 100644 --- a/browser/components/customizableui/content/panelUI.inc.xul +++ b/browser/components/customizableui/content/panelUI.inc.xul @@ -336,7 +336,7 @@ Meet the rest of { -brand-product-name }. onboarding-welcome-learn-more = Learn more about the benefits. onboarding-join-form-header = Join { -brand-product-name } -onboarding-join-form-body = Enter your email address to get started. +onboarding-join-form-body = Enter your email address to get started. onboarding-join-form-email = .placeholder = Enter email onboarding-join-form-email-error = Valid email required -onboarding-join-form-legal = By proceeding, you agree to the Terms of Service and Privacy Notice. +onboarding-join-form-legal = By proceeding, you agree to the Terms of Service and Privacy Notice. onboarding-join-form-continue = Continue onboarding-start-browsing-button-label = Start Browsing @@ -29,7 +37,7 @@ onboarding-benefit-products-title = Useful Products onboarding-benefit-products-text = Get things done with a family of tools that respects your privacy across your devices. onboarding-benefit-knowledge-title = Practical Knowledge -onboarding-benefit-knowledge-text = Learn everything you need to know to stay smarter and safer online. +onboarding-benefit-knowledge-text = Learn everything you need to know to stay smarter and safer online. onboarding-benefit-privacy-title = True Privacy # "Personal Data Promise" is a concept that should be translated consistently @@ -65,12 +73,12 @@ onboarding-tracking-protection-title2 = Protection From Tracking onboarding-tracking-protection-text2 = { -brand-short-name } helps stop websites from tracking you online, making it harder for ads to follow you around the web. onboarding-tracking-protection-button2 = How it Works -onboarding-data-sync-title = Take Your Settings with You +onboarding-data-sync-title = Take Your Settings with You # "Sync" is short for synchronize. onboarding-data-sync-text2 = Sync your bookmarks, passwords, and more everywhere you use { -brand-product-name }. onboarding-data-sync-button2 = Sign in to { -sync-brand-short-name } -onboarding-firefox-monitor-title = Stay Alert to Data Breaches +onboarding-firefox-monitor-title = Stay Alert to Data Breaches onboarding-firefox-monitor-text = { -monitor-brand-name } monitors if your email has appeared in a data breach and alerts you if it appears in a new breach. onboarding-firefox-monitor-button = Sign up for Alerts @@ -78,7 +86,7 @@ onboarding-browse-privately-title = Browse Privately onboarding-browse-privately-text = Private Browsing clears your search and browsing history to keep it secret from anyone who uses your computer. onboarding-browse-privately-button = Open a Private Window -onboarding-firefox-send-title = Keep Your Shared Files Private +onboarding-firefox-send-title = Keep Your Shared Files Private onboarding-firefox-send-text2 = Upload your files to { -send-brand-name } to share them with end-to-end encryption and a link that automatically expires. onboarding-firefox-send-button = Try { -send-brand-name } @@ -88,21 +96,21 @@ onboarding-mobile-phone-text = Download { -brand-product-name } for iOS or Andro # browser. onboarding-mobile-phone-button = Download Mobile Browser -onboarding-send-tabs-title = Instantly Send Yourself Tabs +onboarding-send-tabs-title = Instantly Send Yourself Tabs # "Send Tabs" refers to "Send Tab to Device" feature that appears when opening a # tab's context menu. onboarding-send-tabs-text = Send Tabs instantly shares pages between your devices without having to copy, paste, or leave the browser. onboarding-send-tabs-button = Start Using Send Tabs onboarding-pocket-anywhere-title = Read and Listen Anywhere -onboarding-pocket-anywhere-text2 = Save your favorite content offline with the { -pocket-brand-name } App and read, listen, and watch whenever it’s convenient for you. +onboarding-pocket-anywhere-text2 = Save your favorite content offline with the { -pocket-brand-name } App and read, listen, and watch whenever it’s convenient for you. onboarding-pocket-anywhere-button = Try { -pocket-brand-name } -onboarding-lockwise-passwords-title = Take Your Passwords Everywhere +onboarding-lockwise-passwords-title = Take Your Passwords Everywhere onboarding-lockwise-passwords-text2 = Keep the passwords you save secure and easily log in to your accounts with { -lockwise-brand-name }. onboarding-lockwise-passwords-button2 = Get the App -onboarding-facebook-container-title = Set Boundaries with Facebook +onboarding-facebook-container-title = Set Boundaries with Facebook onboarding-facebook-container-text2 = { -facebook-container-brand-name } keeps your profile separate from everything else, making it harder for Facebook to target you with ads. onboarding-facebook-container-button = Add the Extension diff --git a/browser/locales/en-US/chrome/overrides/netError.dtd b/browser/locales/en-US/chrome/overrides/netError.dtd index 29e34c518fb1..e0b0ce9b5bc4 100644 --- a/browser/locales/en-US/chrome/overrides/netError.dtd +++ b/browser/locales/en-US/chrome/overrides/netError.dtd @@ -205,12 +205,6 @@ was trying to connect. --> "SSL_ERROR_UNSUPPORTED_VERSION". --> - - &brandShortName; did not connect to because your computer’s clock appears to show the wrong time and this is preventing a secure connection.

Your computer is set to , when it should be . To fix this problem, change your date and time settings to match the correct time.

"> -&brandShortName; did not connect to because your computer’s clock appears to show the wrong time and this is preventing a secure connection.

Your computer is set to . To fix this problem, change your date and time settings to match the correct time.

"> -
has a security policy called HTTP Strict Transport Security (HSTS), which means that &brandShortName; can only connect to it securely. You can’t add an exception to visit this site."> diff --git a/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/Tabs.jsm b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/Tabs.jsm index 243d06a8f80c..1f90daeca329 100644 --- a/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/Tabs.jsm +++ b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/Tabs.jsm @@ -149,16 +149,17 @@ async function allTabTitlesDisplayed(browserWindow) { let tabTitlePromises = []; for (let tab of browserWindow.gBrowser.tabs) { - function tabTitleLoaded(spec) { - return () => { - return spec ? tab.label == specToTitleMap[spec] : false; - }; + function getSpec() { + return tab.linkedBrowser && + tab.linkedBrowser.documentURI && + tab.linkedBrowser.documentURI.spec; + } + function tabTitleLoaded() { + let spec = getSpec(); + return spec ? tab.label == specToTitleMap[spec] : false; } - let spec = tab.linkedBrowser && - tab.linkedBrowser.documentURI && - tab.linkedBrowser.documentURI.spec; let promise = - TestUtils.waitForCondition(tabTitleLoaded(spec), `Tab (${spec}) should be showing "${specToTitleMap[spec]}". Got "${tab.label}"`); + TestUtils.waitForCondition(tabTitleLoaded, `Tab (${getSpec()}) should be showing "${specToTitleMap[getSpec()]}". Got "${tab.label}"`); tabTitlePromises.push(promise); } diff --git a/build/pgo/certs/cert9.db b/build/pgo/certs/cert9.db index 449e713dd95d..5a3baaf54bbb 100644 Binary files a/build/pgo/certs/cert9.db and b/build/pgo/certs/cert9.db differ diff --git a/build/pgo/certs/key4.db b/build/pgo/certs/key4.db index 33da46fa1c9d..c0de19d70781 100644 Binary files a/build/pgo/certs/key4.db and b/build/pgo/certs/key4.db differ diff --git a/build/pgo/certs/mochitest.client b/build/pgo/certs/mochitest.client index c7a408b7a6cb..43c8c200fb5a 100644 Binary files a/build/pgo/certs/mochitest.client and b/build/pgo/certs/mochitest.client differ diff --git a/build/pgo/server-locations.txt b/build/pgo/server-locations.txt index dc51a21cb160..a762420899cb 100644 --- a/build/pgo/server-locations.txt +++ b/build/pgo/server-locations.txt @@ -286,11 +286,14 @@ https://sha256ee.example.com:443 privileged,cer # Hosts for imminent distrust warning tests https://imminently-distrusted.example.com:443 privileged,cert=imminently_distrusted -# Hosts for ssl3/rc4 console warning tests -https://ssl3.example.com:443 privileged,ssl3 -https://rc4.example.com:443 privileged,rc4 -https://ssl3rc4.example.com:443 privileged,ssl3,rc4 -https://tls1.example.com:443 privileged,tls1 +# Hosts for ssl3/rc4/tls1 warning tests +https://ssl3.example.com:443 privileged,ssl3 +https://rc4.example.com:443 privileged,rc4 +https://ssl3rc4.example.com:443 privileged,ssl3,rc4 +https://tls1.example.com:443 privileged,tls1 +https://tls11.example.com:443 privileged,tls1_1 +https://tls12.example.com:443 privileged,tls1_2 +https://tls13.example.com:443 privileged,tls1,tls1_3 # Hosts for youtube rewrite tests https://mochitest.youtube.com:443 diff --git a/devtools/client/debugger/dist/parser-worker.js b/devtools/client/debugger/dist/parser-worker.js index 262138025be2..96b824b141a0 100644 --- a/devtools/client/debugger/dist/parser-worker.js +++ b/devtools/client/debugger/dist/parser-worker.js @@ -17945,18 +17945,22 @@ const { workerHandler } = _devtoolsUtils.workerUtils; /* This Source Code Form i * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at . */ +function clearState() { + (0, _ast.clearASTs)(); + (0, _getScopes.clearScopes)(); + (0, _sources.clearSources)(); + (0, _getSymbols.clearSymbols)(); +} + self.onmessage = workerHandler({ findOutOfScopeLocations: _findOutOfScopeLocations2.default, getSymbols: _getSymbols.getSymbols, getScopes: _getScopes2.default, - clearSymbols: _getSymbols.clearSymbols, - clearScopes: _getScopes.clearScopes, - clearASTs: _ast.clearASTs, - setSource: _sources.setSource, - clearSources: _sources.clearSources, + clearState, getNextStep: _steps.getNextStep, hasSyntaxError: _validate.hasSyntaxError, - mapExpression: _mapExpression2.default + mapExpression: _mapExpression2.default, + setSource: _sources.setSource }); /***/ }), diff --git a/devtools/client/debugger/panel.js b/devtools/client/debugger/panel.js index 8b9f901edc27..8f2dd1e4a6eb 100644 --- a/devtools/client/debugger/panel.js +++ b/devtools/client/debugger/panel.js @@ -33,7 +33,10 @@ DebuggerPanel.prototype = { threadClient: this.toolbox.threadClient, tabTarget: this.toolbox.target, debuggerClient: this.toolbox.target.client, - sourceMaps: this.toolbox.sourceMapService, + workers: { + sourceMaps: this.toolbox.sourceMapService, + evaluationsParser: this.toolbox.parserService + }, panel: this }); diff --git a/devtools/client/debugger/src/actions/ast.js b/devtools/client/debugger/src/actions/ast.js index ae934576ae66..e7aeb71d598f 100644 --- a/devtools/client/debugger/src/actions/ast.js +++ b/devtools/client/debugger/src/actions/ast.js @@ -8,13 +8,11 @@ import { getSourceWithContent, getSelectedLocation } from "../selectors"; import { setInScopeLines } from "./ast/setInScopeLines"; -import * as parser from "../workers/parser"; - import type { Context } from "../types"; import type { ThunkArgs, Action } from "./types"; export function setOutOfScopeLocations(cx: Context) { - return async ({ dispatch, getState }: ThunkArgs) => { + return async ({ dispatch, getState, parser }: ThunkArgs) => { const location = getSelectedLocation(getState()); if (!location) { return; diff --git a/devtools/client/debugger/src/actions/breakpoints/breakpointPositions.js b/devtools/client/debugger/src/actions/breakpoints/breakpointPositions.js index 4503eff9abfc..b524a7dfb8ef 100644 --- a/devtools/client/debugger/src/actions/breakpoints/breakpointPositions.js +++ b/devtools/client/debugger/src/actions/breakpoints/breakpointPositions.js @@ -44,6 +44,7 @@ async function mapLocations( } const { sourceId } = generatedLocations[0]; + const originalLocations = await sourceMaps.getOriginalLocations( sourceId, generatedLocations diff --git a/devtools/client/debugger/src/actions/expressions.js b/devtools/client/debugger/src/actions/expressions.js index 4ebd5c28c2a2..9185c6de33b1 100644 --- a/devtools/client/debugger/src/actions/expressions.js +++ b/devtools/client/debugger/src/actions/expressions.js @@ -22,7 +22,6 @@ import { wrapExpression } from "../utils/expressions"; import { features } from "../utils/prefs"; import { isOriginal } from "../utils/source"; -import * as parser from "../workers/parser"; import type { Expression, ThreadContext } from "../types"; import type { ThunkArgs } from "./types"; @@ -35,12 +34,12 @@ import type { ThunkArgs } from "./types"; * @static */ export function addExpression(cx: ThreadContext, input: string) { - return async ({ dispatch, getState }: ThunkArgs) => { + return async ({ dispatch, getState, evaluationsParser }: ThunkArgs) => { if (!input) { return; } - const expressionError = await parser.hasSyntaxError(input); + const expressionError = await evaluationsParser.hasSyntaxError(input); const expression = getExpression(getState(), input); if (expression) { @@ -80,7 +79,7 @@ export function updateExpression( input: string, expression: Expression ) { - return async ({ dispatch, getState }: ThunkArgs) => { + return async ({ dispatch, getState, parser }: ThunkArgs) => { if (!input) { return; } @@ -177,14 +176,20 @@ function evaluateExpression(cx: ThreadContext, expression: Expression) { * and replaces all posible generated names. */ export function getMappedExpression(expression: string) { - return async function({ dispatch, getState, client, sourceMaps }: ThunkArgs) { + return async function({ + dispatch, + getState, + client, + sourceMaps, + evaluationsParser + }: ThunkArgs) { const thread = getCurrentThread(getState()); const mappings = getSelectedScopeMappings(getState(), thread); const bindings = getSelectedFrameBindings(getState(), thread); // We bail early if we do not need to map the expression. This is important - // because mapping an expression can be slow if the parser worker is - // busy doing other work. + // because mapping an expression can be slow if the evaluationsParser + // worker is busy doing other work. // // 1. there are no mappings - we do not need to map original expressions // 2. does not contain `await` - we do not need to map top level awaits @@ -194,7 +199,7 @@ export function getMappedExpression(expression: string) { return null; } - return parser.mapExpression( + return evaluationsParser.mapExpression( expression, mappings, bindings || [], diff --git a/devtools/client/debugger/src/actions/navigation.js b/devtools/client/debugger/src/actions/navigation.js index 1a066e727074..1f8a0eb2e423 100644 --- a/devtools/client/debugger/src/actions/navigation.js +++ b/devtools/client/debugger/src/actions/navigation.js @@ -12,13 +12,6 @@ import { waitForMs } from "../utils/utils"; import { newGeneratedSources } from "./sources"; import { updateWorkers } from "./debuggee"; -import { - clearASTs, - clearSymbols, - clearScopes, - clearSources -} from "../workers/parser"; - import { clearWasmStates } from "../utils/wasm"; import { getMainThread } from "../selectors"; import type { Action, ThunkArgs } from "./types"; @@ -33,15 +26,18 @@ import type { Action, ThunkArgs } from "./types"; * @static */ export function willNavigate(event: Object) { - return function({ dispatch, getState, client, sourceMaps }: ThunkArgs) { + return async function({ + dispatch, + getState, + client, + sourceMaps, + parser + }: ThunkArgs) { sourceQueue.clear(); sourceMaps.clearSourceMaps(); clearWasmStates(); clearDocuments(); - clearSymbols(); - clearASTs(); - clearScopes(); - clearSources(); + parser.clear(); client.detachWorkers(); const thread = getMainThread(getState()); diff --git a/devtools/client/debugger/src/actions/pause/commands.js b/devtools/client/debugger/src/actions/pause/commands.js index 9bf9e70773a8..c98993e9a767 100644 --- a/devtools/client/debugger/src/actions/pause/commands.js +++ b/devtools/client/debugger/src/actions/pause/commands.js @@ -13,7 +13,6 @@ import { getThreadContext } from "../../selectors"; import { PROMISE } from "../utils/middleware/promise"; -import { getNextStep } from "../../workers/parser"; import { addHiddenBreakpoint } from "../breakpoints"; import { evaluateExpressions } from "../expressions"; import { selectLocation } from "../sources"; @@ -213,7 +212,7 @@ function hasAwait(content: AsyncValue | null, pauseLocation) { * @returns {function(ThunkArgs)} */ export function astCommand(cx: ThreadContext, stepType: Command) { - return async ({ dispatch, getState, sourceMaps }: ThunkArgs) => { + return async ({ dispatch, getState, sourceMaps, parser }: ThunkArgs) => { if (!features.asyncStepping) { return dispatch(command(cx, stepType)); } @@ -225,7 +224,10 @@ export function astCommand(cx: ThreadContext, stepType: Command) { const content = source ? getSourceContent(getState(), source.id) : null; if (source && hasAwait(content, frame.location)) { - const nextLocation = await getNextStep(source.id, frame.location); + const nextLocation = await parser.getNextStep( + source.id, + frame.location + ); if (nextLocation) { await dispatch(addHiddenBreakpoint(cx, nextLocation)); return dispatch(command(cx, "resume")); diff --git a/devtools/client/debugger/src/actions/pause/mapScopes.js b/devtools/client/debugger/src/actions/pause/mapScopes.js index 6245a05b50c3..850fffb20af2 100644 --- a/devtools/client/debugger/src/actions/pause/mapScopes.js +++ b/devtools/client/debugger/src/actions/pause/mapScopes.js @@ -55,7 +55,8 @@ export function mapScopes( scopes: Promise, frame: Frame ) { - return async function({ dispatch, getState, client, sourceMaps }: ThunkArgs) { + return async function(thunkArgs: ThunkArgs) { + const { dispatch, getState } = thunkArgs; assert(cx.thread == frame.thread, "Thread mismatch"); const generatedSource = getSource( @@ -99,8 +100,7 @@ export function mapScopes( : { type: "text", value: "", contentType: undefined }, frame, await scopes, - sourceMaps, - client + thunkArgs ); } catch (e) { log(e); diff --git a/devtools/client/debugger/src/actions/sources/loadSourceText.js b/devtools/client/debugger/src/actions/sources/loadSourceText.js index a3c20ea1c985..2dea3282abaa 100644 --- a/devtools/client/debugger/src/actions/sources/loadSourceText.js +++ b/devtools/client/debugger/src/actions/sources/loadSourceText.js @@ -21,7 +21,6 @@ import { prettyPrintSource } from "./prettyPrint"; import { setBreakableLines } from "./breakableLines"; import { isFulfilled } from "../../utils/async-value"; -import * as parser from "../../workers/parser"; import { isOriginal, isPretty } from "../../utils/source"; import { memoizeableAction, @@ -93,7 +92,7 @@ async function loadSource( async function loadSourceTextPromise( cx: Context, source: Source, - { dispatch, getState, client, sourceMaps }: ThunkArgs + { dispatch, getState, client, sourceMaps, parser }: ThunkArgs ): Promise { const epoch = getSourcesEpoch(getState()); await dispatch({ diff --git a/devtools/client/debugger/src/actions/sources/symbols.js b/devtools/client/debugger/src/actions/sources/symbols.js index fd3f8ea31a09..a544435fbb2e 100644 --- a/devtools/client/debugger/src/actions/sources/symbols.js +++ b/devtools/client/debugger/src/actions/sources/symbols.js @@ -10,8 +10,6 @@ import { PROMISE } from "../utils/middleware/promise"; import { updateTab } from "../tabs"; import { loadSourceText } from "./loadSourceText"; -import * as parser from "../../workers/parser"; - import { memoizeableAction, type MemoizedAction @@ -20,7 +18,7 @@ import { import type { Source, Context } from "../../types"; import type { Symbols } from "../../reducers/types"; -async function doSetSymbols(cx, source, { dispatch, getState }) { +async function doSetSymbols(cx, source, { dispatch, getState, parser }) { const sourceId = source.id; await dispatch(loadSourceText({ cx, source })); diff --git a/devtools/client/debugger/src/actions/tests/__snapshots__/project-text-search.spec.js.snap b/devtools/client/debugger/src/actions/tests/__snapshots__/project-text-search.spec.js.snap index e7f0e40d64be..c75282e0e421 100644 --- a/devtools/client/debugger/src/actions/tests/__snapshots__/project-text-search.spec.js.snap +++ b/devtools/client/debugger/src/actions/tests/__snapshots__/project-text-search.spec.js.snap @@ -124,6 +124,27 @@ Array [ ] `; +exports[`project text search should search a specific source 2`] = ` +Array [ + Object { + "filepath": "http://localhost:8000/examples/bar", + "matches": Array [ + Object { + "column": 9, + "line": 1, + "match": "bla", + "matchIndex": 9, + "sourceId": "bar", + "type": "MATCH", + "value": "function bla(x, y) {", + }, + ], + "sourceId": "bar", + "type": "RESULT", + }, +] +`; + exports[`project text search should search all the loaded sources based on the query 1`] = ` Array [ Object { diff --git a/devtools/client/debugger/src/actions/types/index.js b/devtools/client/debugger/src/actions/types/index.js index 6d6f13c6ffcc..27ab60d55694 100644 --- a/devtools/client/debugger/src/actions/types/index.js +++ b/devtools/client/debugger/src/actions/types/index.js @@ -19,6 +19,7 @@ import type { PauseAction } from "./PauseAction"; import type { ASTAction } from "./ASTAction"; import { clientCommands } from "../../client/firefox"; import type { Panel } from "../../client/firefox/types"; +import type { ParserDispatcher } from "../../workers/parser"; /** * Flow types @@ -38,6 +39,8 @@ export type ThunkArgs = { getState: () => State, client: typeof clientCommands, sourceMaps: SourceMaps, + parser: ParserDispatcher, + evaluationsParser: ParserDispatcher, panel: Panel }; diff --git a/devtools/client/debugger/src/actions/utils/middleware/log.js b/devtools/client/debugger/src/actions/utils/middleware/log.js index 17005ad569a6..d44be560b7b1 100644 --- a/devtools/client/debugger/src/actions/utils/middleware/log.js +++ b/devtools/client/debugger/src/actions/utils/middleware/log.js @@ -20,7 +20,8 @@ const blacklist = [ "REMOVE_BREAKPOINT", "NODE_PROPERTIES_LOADED", "SET_FOCUSED_SOURCE_ITEM", - "NODE_EXPAND" + "NODE_EXPAND", + "IN_SCOPE_LINES" ]; function cloneAction(action: any) { diff --git a/devtools/client/debugger/src/client/index.js b/devtools/client/debugger/src/client/index.js index d18a23dd4280..6c0f21558bb4 100644 --- a/devtools/client/debugger/src/client/index.js +++ b/devtools/client/debugger/src/client/index.js @@ -59,7 +59,7 @@ function getClient(connection: any) { export async function onConnect( connection: Object, - sourceMaps: Object, + panelWorkers: Object, panel: Panel ) { // NOTE: the landing page does not connect to a JS process @@ -73,15 +73,15 @@ export async function onConnect( const commands = client.clientCommands; const initialState = await loadInitialState(); + const workers = bootstrapWorkers(panelWorkers); const { store, actions, selectors } = bootstrapStore( commands, - sourceMaps, + workers, panel, initialState ); - const workers = bootstrapWorkers(); await client.onConnect(connection, actions); await syncBreakpoints(); @@ -90,7 +90,7 @@ export async function onConnect( store, actions, selectors, - workers: { ...workers, sourceMaps }, + workers, connection, client: client.clientCommands }); diff --git a/devtools/client/debugger/src/main.js b/devtools/client/debugger/src/main.js index d19b0dde604d..2da9f777c9c1 100644 --- a/devtools/client/debugger/src/main.js +++ b/devtools/client/debugger/src/main.js @@ -19,7 +19,7 @@ module.exports = { threadClient, tabTarget, debuggerClient, - sourceMaps, + workers, panel }: any) => onConnect( @@ -31,7 +31,7 @@ module.exports = { debuggerClient } }, - sourceMaps, + workers, panel ), destroy: () => { diff --git a/devtools/client/debugger/src/test/tests-setup.js b/devtools/client/debugger/src/test/tests-setup.js index 0564674062a8..f920027452ea 100644 --- a/devtools/client/debugger/src/test/tests-setup.js +++ b/devtools/client/debugger/src/test/tests-setup.js @@ -23,12 +23,7 @@ import { stop as stopPrettyPrintWorker } from "../workers/pretty-print"; -import { - start as startParserWorker, - stop as stopParserWorker, - clearSymbols, - clearASTs -} from "../workers/parser"; +import { ParserDispatcher } from "../workers/parser"; import { start as startSearchWorker, stop as stopSearchWorker @@ -68,6 +63,8 @@ function formatException(reason, p) { console && console.log("Unhandled Rejection at:", p, "reason:", reason); } +export const parserWorker = new ParserDispatcher(); + beforeAll(() => { startSourceMapWorker( path.join(rootPath, "node_modules/devtools-source-map/src/worker.js"), @@ -76,7 +73,7 @@ beforeAll(() => { startPrettyPrintWorker( path.join(rootPath, "src/workers/pretty-print/worker.js") ); - startParserWorker(path.join(rootPath, "src/workers/parser/worker.js")); + parserWorker.start(path.join(rootPath, "src/workers/parser/worker.js")); startSearchWorker(path.join(rootPath, "src/workers/search/worker.js")); process.on("unhandledRejection", formatException); }); @@ -84,7 +81,7 @@ beforeAll(() => { afterAll(() => { stopSourceMapWorker(); stopPrettyPrintWorker(); - stopParserWorker(); + parserWorker.stop(); stopSearchWorker(); process.removeListener("unhandledRejection", formatException); }); @@ -92,8 +89,7 @@ afterAll(() => { afterEach(() => {}); beforeEach(async () => { - clearASTs(); - await clearSymbols(); + parserWorker.clear(); clearHistory(); clearDocuments(); prefs.projectDirectoryRoot = ""; diff --git a/devtools/client/debugger/src/utils/bootstrap.js b/devtools/client/debugger/src/utils/bootstrap.js index 3fd75b37a9d4..5f587e5c3a38 100644 --- a/devtools/client/debugger/src/utils/bootstrap.js +++ b/devtools/client/debugger/src/utils/bootstrap.js @@ -16,7 +16,7 @@ import SourceMaps, { } from "devtools-source-map"; import * as search from "../workers/search"; import * as prettyPrint from "../workers/pretty-print"; -import * as parser from "../workers/parser"; +import { ParserDispatcher } from "../workers/parser"; import configureStore from "../actions/utils/create-store"; import reducers from "../reducers"; @@ -26,6 +26,8 @@ import { asyncStore, prefs } from "./prefs"; import type { Panel } from "../client/firefox/types"; +let parser; + function renderPanel(component, store) { const root = document.createElement("div"); root.className = "launchpad-root theme-body"; @@ -42,9 +44,14 @@ function renderPanel(component, store) { ); } +type Workers = { + sourceMaps: typeof SourceMaps, + evaluationsParser: typeof ParserDispatcher +}; + export function bootstrapStore( client: any, - sourceMaps: typeof SourceMaps, + workers: Workers, panel: Panel, initialState: Object ) { @@ -52,7 +59,7 @@ export function bootstrapStore( log: prefs.logging || isTesting(), timing: isDevelopment(), makeThunkArgs: (args, state) => { - return { ...args, client, sourceMaps, panel }; + return { ...args, client, ...workers, panel }; } }); @@ -67,7 +74,7 @@ export function bootstrapStore( return { store, actions, selectors }; } -export function bootstrapWorkers() { +export function bootstrapWorkers(panelWorkers: Workers) { const workerPath = isDevelopment() ? "assets/build" : "resource://devtools/client/debugger/dist"; @@ -82,9 +89,11 @@ export function bootstrapWorkers() { } prettyPrint.start(`${workerPath}/pretty-print-worker.js`); + parser = new ParserDispatcher(); + parser.start(`${workerPath}/parser-worker.js`); search.start(`${workerPath}/search-worker.js`); - return { prettyPrint, parser, search }; + return { ...panelWorkers, prettyPrint, parser, search }; } export function teardownWorkers() { diff --git a/devtools/client/debugger/src/utils/pause/mapScopes/index.js b/devtools/client/debugger/src/utils/pause/mapScopes/index.js index d59dda90631a..075dc7dc8119 100644 --- a/devtools/client/debugger/src/utils/pause/mapScopes/index.js +++ b/devtools/client/debugger/src/utils/pause/mapScopes/index.js @@ -7,7 +7,6 @@ import typeof SourceMaps from "devtools-source-map"; import { - getScopes, type SourceScope, type BindingData, type BindingLocation @@ -37,6 +36,8 @@ import { } from "./getApplicableBindingsForOriginalPosition"; import { log } from "../../log"; +import type { ThunkArgs } from "../../../actions/types"; + import type { PartialPosition, Frame, @@ -54,16 +55,15 @@ export async function buildMappedScopes( content: SourceContent, frame: Frame, scopes: Scope, - sourceMaps: any, - client: any + { client, parser, sourceMaps }: ThunkArgs ): Promise { - const originalAstScopes = await getScopes(frame.location); - const generatedAstScopes = await getScopes(frame.generatedLocation); + const originalAstScopes = await parser.getScopes(frame.location); + const generatedAstScopes = await parser.getScopes(frame.generatedLocation); if (!originalAstScopes || !generatedAstScopes) { return null; diff --git a/devtools/client/debugger/src/utils/test-head.js b/devtools/client/debugger/src/utils/test-head.js index eca2dcd5373f..cc1814a159fb 100644 --- a/devtools/client/debugger/src/utils/test-head.js +++ b/devtools/client/debugger/src/utils/test-head.js @@ -15,6 +15,7 @@ import reducers from "../reducers"; import actions from "../actions"; import * as selectors from "../selectors"; import { getHistory } from "../test/utils/history"; +import { parserWorker } from "../test/tests-setup"; import configureStore from "../actions/utils/create-store"; import sourceQueue from "../utils/source-queue"; import type { Source, OriginalSourceData, GeneratedSourceData } from "../types"; @@ -41,7 +42,8 @@ function createStore(client: any, initialState: any = {}, sourceMapsMock: any) { return { ...args, client, - sourceMaps: sourceMapsMock !== undefined ? sourceMapsMock : sourceMaps + sourceMaps: sourceMapsMock !== undefined ? sourceMapsMock : sourceMaps, + parser: parserWorker }; } })(combineReducers(reducers), initialState); diff --git a/devtools/client/debugger/src/workers/parser/index.js b/devtools/client/debugger/src/workers/parser/index.js index f4936d09bdb8..f7706977330d 100644 --- a/devtools/client/debugger/src/workers/parser/index.js +++ b/devtools/client/debugger/src/workers/parser/index.js @@ -12,77 +12,71 @@ import type { SourceLocation, SourceId, SourceContent } from "../../types"; import type { SourceScope } from "./getScopes/visitor"; import type { SymbolDeclarations } from "./getSymbols"; -const dispatcher = new WorkerDispatcher(); -export const start = (url: string, win: any = window) => - dispatcher.start(url, win); -export const stop = () => dispatcher.stop(); +export class ParserDispatcher extends WorkerDispatcher { + async findOutOfScopeLocations( + sourceId: string, + position: AstPosition + ): Promise { + return this.invoke("findOutOfScopeLocations", sourceId, position); + } -export const findOutOfScopeLocations = async ( - sourceId: string, - position: AstPosition -): Promise => - dispatcher.invoke("findOutOfScopeLocations", sourceId, position); + async getNextStep( + sourceId: SourceId, + pausedPosition: AstPosition + ): Promise { + return this.invoke("getNextStep", sourceId, pausedPosition); + } -export const getNextStep = async ( - sourceId: SourceId, - pausedPosition: AstPosition -): Promise => - dispatcher.invoke("getNextStep", sourceId, pausedPosition); + async clearState(): Promise { + return this.invoke("clearState"); + } -export const clearASTs = async (): Promise => - dispatcher.invoke("clearASTs"); + async getScopes(location: SourceLocation): Promise { + return this.invoke("getScopes", location); + } -export const getScopes = async ( - location: SourceLocation -): Promise => dispatcher.invoke("getScopes", location); + async getSymbols(sourceId: string): Promise { + return this.invoke("getSymbols", sourceId); + } -export const clearScopes = async (): Promise => - dispatcher.invoke("clearScopes"); + async setSource(sourceId: SourceId, content: SourceContent): Promise { + const astSource: AstSource = { + id: sourceId, + text: content.type === "wasm" ? "" : content.value, + contentType: content.contentType || null, + isWasm: content.type === "wasm" + }; -export const clearSymbols = async (): Promise => - dispatcher.invoke("clearSymbols"); + return this.invoke("setSource", astSource); + } -export const getSymbols = async ( - sourceId: string -): Promise => dispatcher.invoke("getSymbols", sourceId); + async hasSyntaxError(input: string): Promise { + return this.invoke("hasSyntaxError", input); + } -export const setSource = async ( - sourceId: SourceId, - content: SourceContent -): Promise => { - const astSource: AstSource = { - id: sourceId, - text: content.type === "wasm" ? "" : content.value, - contentType: content.contentType || null, - isWasm: content.type === "wasm" - }; + async mapExpression( + expression: string, + mappings: { + [string]: string | null + } | null, + bindings: string[], + shouldMapBindings?: boolean, + shouldMapAwait?: boolean + ): Promise<{ expression: string }> { + return this.invoke( + "mapExpression", + expression, + mappings, + bindings, + shouldMapBindings, + shouldMapAwait + ); + } - await dispatcher.invoke("setSource", astSource); -}; - -export const clearSources = async (): Promise => - dispatcher.invoke("clearSources"); - -export const hasSyntaxError = async (input: string): Promise => - dispatcher.invoke("hasSyntaxError", input); - -export const mapExpression = async ( - expression: string, - mappings: { - [string]: string | null - } | null, - bindings: string[], - shouldMapBindings?: boolean, - shouldMapAwait?: boolean -): Promise<{ expression: string }> => - dispatcher.invoke( - "mapExpression", - expression, - mappings, - bindings, - shouldMapBindings, - shouldMapAwait - ); + async clear() { + await this.clearState(); + } +} export type { SourceScope, diff --git a/devtools/client/debugger/src/workers/parser/worker.js b/devtools/client/debugger/src/workers/parser/worker.js index 3144c1413185..c13b33a8439e 100644 --- a/devtools/client/debugger/src/workers/parser/worker.js +++ b/devtools/client/debugger/src/workers/parser/worker.js @@ -16,16 +16,20 @@ import mapExpression from "./mapExpression"; import { workerUtils } from "devtools-utils"; const { workerHandler } = workerUtils; +function clearState() { + clearASTs(); + clearScopes(); + clearSources(); + clearSymbols(); +} + self.onmessage = workerHandler({ findOutOfScopeLocations, getSymbols, getScopes, - clearSymbols, - clearScopes, - clearASTs, - setSource, - clearSources, + clearState, getNextStep, hasSyntaxError, - mapExpression + mapExpression, + setSource }); diff --git a/devtools/client/debugger/test/mochitest/helpers.js b/devtools/client/debugger/test/mochitest/helpers.js index 40dd62c43474..3c36f1355d19 100644 --- a/devtools/client/debugger/test/mochitest/helpers.js +++ b/devtools/client/debugger/test/mochitest/helpers.js @@ -1060,8 +1060,8 @@ const keyMappings = { fileSearchPrev: { code: "g", modifiers: cmdShift }, Enter: { code: "VK_RETURN" }, ShiftEnter: { code: "VK_RETURN", modifiers: shiftOrAlt }, - AltEnter: { - code: "VK_RETURN", + AltEnter: { + code: "VK_RETURN", modifiers: { altKey: true } }, Up: { code: "VK_UP" }, diff --git a/devtools/client/framework/toolbox.js b/devtools/client/framework/toolbox.js index a6dc58716d08..764b66b15bda 100644 --- a/devtools/client/framework/toolbox.js +++ b/devtools/client/framework/toolbox.js @@ -937,6 +937,24 @@ Toolbox.prototype = { return this._createSourceMapService(); }, + /** + * A common access point for the client-side parser service that any panel can use. + */ + get parserService() { + if (this._parserService) { + return this._parserService; + } + + const { ParserDispatcher } = + require("devtools/client/debugger/src/workers/parser/index"); + + this._parserService = new ParserDispatcher(); + this._parserService.start( + "resource://devtools/client/debugger/dist/parser-worker.js", + this.win); + return this._parserService; + }, + /** * Clients wishing to use source maps but that want the toolbox to * track the source and style sheet actor mapping can use this @@ -3074,11 +3092,17 @@ Toolbox.prototype = { this._sourceMapURLService.destroy(); this._sourceMapURLService = null; } + if (this._sourceMapService) { this._sourceMapService.stopSourceMapWorker(); this._sourceMapService = null; } + if (this._parserService) { + this._parserService.stop(); + this._parserService = null; + } + if (this.webconsolePanel) { this._saveSplitConsoleHeight(); this.webconsolePanel.removeEventListener("resize", diff --git a/devtools/client/webconsole/webconsole.js b/devtools/client/webconsole/webconsole.js index 979335aad1f4..883d13dd2967 100644 --- a/devtools/client/webconsole/webconsole.js +++ b/devtools/client/webconsole/webconsole.js @@ -301,17 +301,15 @@ class WebConsole { return null; } - /** - * A common access point for the client-side parser service that any panel can use. - */ get parserService() { if (this._parserService) { return this._parserService; } - this._parserService = + const { ParserDispatcher } = require("devtools/client/debugger/src/workers/parser/index"); + this._parserService = new ParserDispatcher(); this._parserService.start( "resource://devtools/client/debugger/dist/parser-worker.js", this.chromeUtilsWindow); diff --git a/devtools/server/actors/animation-type-longhand.js b/devtools/server/actors/animation-type-longhand.js index 60c40195f0b6..d9b8dd703ca0 100644 --- a/devtools/server/actors/animation-type-longhand.js +++ b/devtools/server/actors/animation-type-longhand.js @@ -293,6 +293,8 @@ exports.ANIMATION_TYPE_FOR_LONGHANDS = [ "bottom", "column-gap", "column-width", + "cx", + "cy", "flex-basis", "height", "left", @@ -315,6 +317,9 @@ exports.ANIMATION_TYPE_FOR_LONGHANDS = [ "padding-right", "padding-top", "perspective", + "r", + "rx", + "ry", "right", "row-gap", "scroll-padding-block-start", @@ -342,6 +347,8 @@ exports.ANIMATION_TYPE_FOR_LONGHANDS = [ "vertical-align", "width", "word-spacing", + "x", + "y", "z-index", ])], ["float", new Set([ diff --git a/devtools/shared/css/generated/properties-db.js b/devtools/shared/css/generated/properties-db.js index abeac8eba0f0..b057e8b53571 100644 --- a/devtools/shared/css/generated/properties-db.js +++ b/devtools/shared/css/generated/properties-db.js @@ -3315,6 +3315,13 @@ exports.CSS_PROPERTIES = { "mask-size", "mask-composite", "mask-image", + "x", + "y", + "cx", + "cy", + "rx", + "ry", + "r", "-moz-box-align", "-moz-box-direction", "-moz-box-flex", @@ -5832,6 +5839,32 @@ exports.CSS_PROPERTIES = { "zoom-out" ] }, + "cx": { + "isInherited": false, + "subproperties": [ + "cx" + ], + "supports": [], + "values": [ + "inherit", + "initial", + "revert", + "unset" + ] + }, + "cy": { + "isInherited": false, + "subproperties": [ + "cy" + ], + "supports": [], + "values": [ + "inherit", + "initial", + "revert", + "unset" + ] + }, "direction": { "isInherited": true, "subproperties": [ @@ -8915,6 +8948,19 @@ exports.CSS_PROPERTIES = { "unset" ] }, + "r": { + "isInherited": false, + "subproperties": [ + "r" + ], + "supports": [], + "values": [ + "inherit", + "initial", + "revert", + "unset" + ] + }, "resize": { "isInherited": false, "subproperties": [ @@ -8994,6 +9040,34 @@ exports.CSS_PROPERTIES = { "unset" ] }, + "rx": { + "isInherited": false, + "subproperties": [ + "rx" + ], + "supports": [], + "values": [ + "auto", + "inherit", + "initial", + "revert", + "unset" + ] + }, + "ry": { + "isInherited": false, + "subproperties": [ + "ry" + ], + "supports": [], + "values": [ + "auto", + "inherit", + "initial", + "revert", + "unset" + ] + }, "scroll-behavior": { "isInherited": false, "subproperties": [ @@ -10444,6 +10518,32 @@ exports.CSS_PROPERTIES = { "vertical-rl" ] }, + "x": { + "isInherited": false, + "subproperties": [ + "x" + ], + "supports": [], + "values": [ + "inherit", + "initial", + "revert", + "unset" + ] + }, + "y": { + "isInherited": false, + "subproperties": [ + "y" + ], + "supports": [], + "values": [ + "inherit", + "initial", + "revert", + "unset" + ] + }, "z-index": { "isInherited": false, "subproperties": [ @@ -10596,38 +10696,6 @@ exports.PREFERENCES = [ "-moz-binding", "layout.css.moz-binding.content.enabled" ], - [ - "scroll-padding-block-end", - "layout.css.scroll-snap-v1.enabled" - ], - [ - "scroll-padding-block-start", - "layout.css.scroll-snap-v1.enabled" - ], - [ - "scroll-padding-bottom", - "layout.css.scroll-snap-v1.enabled" - ], - [ - "scroll-padding-inline-end", - "layout.css.scroll-snap-v1.enabled" - ], - [ - "scroll-padding-inline-start", - "layout.css.scroll-snap-v1.enabled" - ], - [ - "scroll-padding-left", - "layout.css.scroll-snap-v1.enabled" - ], - [ - "scroll-padding-right", - "layout.css.scroll-snap-v1.enabled" - ], - [ - "scroll-padding-top", - "layout.css.scroll-snap-v1.enabled" - ], [ "scroll-margin-block-end", "layout.css.scroll-snap-v1.enabled" @@ -10660,6 +10728,38 @@ exports.PREFERENCES = [ "scroll-margin-top", "layout.css.scroll-snap-v1.enabled" ], + [ + "scroll-padding-block-end", + "layout.css.scroll-snap-v1.enabled" + ], + [ + "scroll-padding-block-start", + "layout.css.scroll-snap-v1.enabled" + ], + [ + "scroll-padding-bottom", + "layout.css.scroll-snap-v1.enabled" + ], + [ + "scroll-padding-inline-end", + "layout.css.scroll-snap-v1.enabled" + ], + [ + "scroll-padding-inline-start", + "layout.css.scroll-snap-v1.enabled" + ], + [ + "scroll-padding-left", + "layout.css.scroll-snap-v1.enabled" + ], + [ + "scroll-padding-right", + "layout.css.scroll-snap-v1.enabled" + ], + [ + "scroll-padding-top", + "layout.css.scroll-snap-v1.enabled" + ], [ "-webkit-text-stroke-width", "layout.css.prefixes.webkit" diff --git a/docshell/base/nsDocShellTreeOwner.cpp b/docshell/base/nsDocShellTreeOwner.cpp index eb9a7b5e3575..a80424ce4268 100644 --- a/docshell/base/nsDocShellTreeOwner.cpp +++ b/docshell/base/nsDocShellTreeOwner.cpp @@ -873,11 +873,9 @@ nsDocShellTreeOwner::HandleEvent(Event* aEvent) { } else if (eventType.EqualsLiteral("drop")) { nsIWebNavigation* webnav = static_cast(mWebBrowser); - uint32_t linksCount; - nsIDroppedLinkItem** links; - if (webnav && NS_SUCCEEDED(handler->DropLinks(dragEvent, true, &linksCount, - &links))) { - if (linksCount >= 1) { + nsTArray> links; + if (webnav && NS_SUCCEEDED(handler->DropLinks(dragEvent, true, links))) { + if (links.Length() >= 1) { nsCOMPtr triggeringPrincipal; handler->GetTriggeringPrincipal(dragEvent, getter_AddRefs(triggeringPrincipal)); @@ -888,11 +886,7 @@ nsDocShellTreeOwner::HandleEvent(Event* aEvent) { nsCOMPtr browserChild = do_QueryInterface(webBrowserChrome); if (browserChild) { - nsresult rv = browserChild->RemoteDropLinks(linksCount, links); - for (uint32_t i = 0; i < linksCount; i++) { - NS_RELEASE(links[i]); - } - free(links); + nsresult rv = browserChild->RemoteDropLinks(links); return rv; } } @@ -912,11 +906,6 @@ nsDocShellTreeOwner::HandleEvent(Event* aEvent) { webnav->LoadURI(url, loadURIOptions); } } - - for (uint32_t i = 0; i < linksCount; i++) { - NS_RELEASE(links[i]); - } - free(links); } } } else { diff --git a/dom/base/ContentAreaDropListener.jsm b/dom/base/ContentAreaDropListener.jsm index 7cbb7f659475..03b4f5841fe9 100644 --- a/dom/base/ContentAreaDropListener.jsm +++ b/dom/base/ContentAreaDropListener.jsm @@ -276,7 +276,7 @@ ContentAreaDropListener.prototype = return url; }, - dropLinks: function(aEvent, aDisallowInherit, aCount) + dropLinks: function(aEvent, aDisallowInherit) { if (aEvent && this._eventTargetIsDisabled(aEvent)) return []; @@ -297,13 +297,11 @@ ContentAreaDropListener.prototype = throw ex; } } - if (aCount) - aCount.value = links.length; return links; }, - validateURIsForDrop: function(aEvent, aURIsCount, aURIs, aDisallowInherit) + validateURIsForDrop: function(aEvent, aURIs, aDisallowInherit) { let dataTransfer = aEvent.dataTransfer; let triggeringPrincipal = this._getTriggeringPrincipalFromDataTransfer(dataTransfer, false); @@ -314,13 +312,9 @@ ContentAreaDropListener.prototype = } }, - queryLinks: function(aDataTransfer, aCount) + queryLinks: function(aDataTransfer) { - let links = this._getDropLinks(aDataTransfer); - if (aCount) { - aCount.value = links.length; - } - return links; + return this._getDropLinks(aDataTransfer); }, _eventTargetIsDisabled: function(aEvent) diff --git a/dom/base/DOMIntersectionObserver.cpp b/dom/base/DOMIntersectionObserver.cpp index d5108bc1ceba..a5e6dfbc35b4 100644 --- a/dom/base/DOMIntersectionObserver.cpp +++ b/dom/base/DOMIntersectionObserver.cpp @@ -293,6 +293,7 @@ void DOMIntersectionObserver::Update(Document* aDocument, for (size_t i = 0; i < mObservationTargets.Length(); ++i) { Element* target = mObservationTargets.ElementAt(i); nsIFrame* targetFrame = target->GetPrimaryFrame(); + nsIFrame* originalTargetFrame = targetFrame; nsRect targetRect; Maybe intersectionRect; bool isSameDoc = root && root->GetComposedDoc() == target->GetComposedDoc(); @@ -374,7 +375,7 @@ void DOMIntersectionObserver::Update(Document* aDocument, intersectionRectRelativeToRoot, rootIntersectionRect); if (intersectionRect.isSome() && !isSameDoc) { nsRect rect = intersectionRect.value(); - nsPresContext* presContext = targetFrame->PresContext(); + nsPresContext* presContext = originalTargetFrame->PresContext(); nsIFrame* rootScrollFrame = presContext->PresShell()->GetRootScrollFrame(); if (rootScrollFrame) { diff --git a/dom/base/nsIDroppedLinkHandler.idl b/dom/base/nsIDroppedLinkHandler.idl index 3dbfcbb296fb..4967894e821d 100644 --- a/dom/base/nsIDroppedLinkHandler.idl +++ b/dom/base/nsIDroppedLinkHandler.idl @@ -65,7 +65,7 @@ interface nsIDroppedLinkHandler : nsISupports /** * Given a drop event aEvent, determines links being dragged and returns * them. If links are returned the caller can, for instance, load them. If - * the count of links is 0, there is no valid link to be dropped. + * the returned array is empty, there is no valid link to be dropped. * * A NS_ERROR_DOM_SECURITY_ERR error will be thrown and the event cancelled if * the receiving target should not load the uri for security reasons. This @@ -76,10 +76,8 @@ interface nsIDroppedLinkHandler : nsISupports * - aDisallowInherit is true, and the URI being dropped would inherit the * current document's security context (URI_INHERITS_SECURITY_CONTEXT). */ - void dropLinks(in DragEvent aEvent, - [optional] in boolean aDisallowInherit, - [optional] out unsigned long aCount, - [retval, array, size_is(aCount)] out nsIDroppedLinkItem aLinks); + Array dropLinks(in DragEvent aEvent, + [optional] in boolean aDisallowInherit); /** * Given a drop event aEvent, validate the extra URIs for the event, @@ -87,8 +85,7 @@ interface nsIDroppedLinkHandler : nsISupports * text, like home button that splits the text with "|". */ void validateURIsForDrop(in DragEvent aEvent, - in unsigned long aURIsCount, - [array, size_is(aURIsCount)] in wstring aURIs, + in Array aURIs, [optional] in boolean aDisallowInherit); /** @@ -97,9 +94,7 @@ interface nsIDroppedLinkHandler : nsISupports * it allows the parent to verify that the child did not modify links * being dropped. */ - void queryLinks(in DataTransfer aDataTransfer, - [optional] out unsigned long aCount, - [retval, array, size_is(aCount)] out nsIDroppedLinkItem aLinks); + Array queryLinks(in DataTransfer aDataTransfer); /** * Given a drop event aEvent, determines the triggering principal for the diff --git a/dom/credentialmanagement/tests/mochitest/test_credman_iframes.html b/dom/credentialmanagement/tests/mochitest/test_credman_iframes.html index 3c5a3a01262f..e5d3fccc5516 100644 --- a/dom/credentialmanagement/tests/mochitest/test_credman_iframes.html +++ b/dom/credentialmanagement/tests/mochitest/test_credman_iframes.html @@ -45,7 +45,8 @@ function handleEventMessage(event) { window.addEventListener("message", handleEventMessage); SpecialPowers.pushPrefEnv({"set": [["security.webauth.webauthn", true], ["security.webauth.webauthn_enable_softtoken", true], - ["security.webauth.webauthn_enable_usbtoken", false]]}, + ["security.webauth.webauthn_enable_usbtoken", false], + ["security.webauth.webauthn_enable_android_fido2", false]]}, function() { document.getElementById("frame_top").src = "https://example.com/tests/dom/credentialmanagement/tests/mochitest/frame_credman_iframes.html"; diff --git a/dom/interfaces/base/nsIBrowser.idl b/dom/interfaces/base/nsIBrowser.idl index 7137ca8fde53..85b161f9b7de 100644 --- a/dom/interfaces/base/nsIBrowser.idl +++ b/dom/interfaces/base/nsIBrowser.idl @@ -25,14 +25,12 @@ interface nsIBrowser : nsISupports * Called by the child to inform the parent that links are dropped into * content area. * - * @param linksCount length of links * @param links a flat array of url, name, and type for each link * @param triggeringPrincipal a principal that initiated loading * of the dropped links */ - void dropLinks(in unsigned long linksCount, - [array, size_is(linksCount)] in wstring links, - in nsIPrincipal aTriggeringPrincipal); + void dropLinks(in Array links, + in nsIPrincipal triggeringPrincipal); /** * Swapping of frameloaders are usually initiated from a frameloader owner @@ -73,16 +71,12 @@ interface nsIBrowser : nsISupports * and the supplied set of commands are now enabled and disabled. * * @param action command updater action - * @param enabledLength length of enabledCommands array * @param enabledCommands commands to enable - * @param disabledLength length of disabledCommands array * @param disabledCommand commands to disable */ void enableDisableCommandsRemoteOnly(in AString action, - in unsigned long enabledLength, - [array, size_is(enabledLength)] in string enabledCommands, - in unsigned long disabledLength, - [array, size_is(disabledLength)] in string disabledCommands); + in Array enabledCommands, + in Array disabledCommands); readonly attribute nsIPrincipal contentPrincipal; readonly attribute nsIContentSecurityPolicy csp; diff --git a/dom/interfaces/base/nsIBrowserChild.idl b/dom/interfaces/base/nsIBrowserChild.idl index f886af7da10f..278898ced863 100644 --- a/dom/interfaces/base/nsIBrowserChild.idl +++ b/dom/interfaces/base/nsIBrowserChild.idl @@ -29,8 +29,7 @@ interface nsIBrowserChild : nsISupports [noscript] void remoteSizeShellTo(in int32_t width, in int32_t height, in int32_t shellItemWidth, in int32_t shellItemHeight); - [noscript] void remoteDropLinks(in unsigned long linksCount, - [array, size_is(linksCount)] in nsIDroppedLinkItem links); + void remoteDropLinks(in Array links); readonly attribute uint64_t tabId; diff --git a/dom/ipc/BrowserChild.cpp b/dom/ipc/BrowserChild.cpp index a97ae84febbf..1c16e7be4a6b 100644 --- a/dom/ipc/BrowserChild.cpp +++ b/dom/ipc/BrowserChild.cpp @@ -735,25 +735,25 @@ BrowserChild::RemoteSizeShellTo(int32_t aWidth, int32_t aHeight, } NS_IMETHODIMP -BrowserChild::RemoteDropLinks(uint32_t aLinksCount, - nsIDroppedLinkItem** aLinks) { +BrowserChild::RemoteDropLinks( + const nsTArray>& aLinks) { nsTArray linksArray; nsresult rv = NS_OK; - for (uint32_t i = 0; i < aLinksCount; i++) { + for (nsIDroppedLinkItem* link : aLinks) { nsString tmp; - rv = aLinks[i]->GetUrl(tmp); + rv = link->GetUrl(tmp); if (NS_FAILED(rv)) { return rv; } linksArray.AppendElement(tmp); - rv = aLinks[i]->GetName(tmp); + rv = link->GetName(tmp); if (NS_FAILED(rv)) { return rv; } linksArray.AppendElement(tmp); - rv = aLinks[i]->GetType(tmp); + rv = link->GetType(tmp); if (NS_FAILED(rv)) { return rv; } @@ -1816,7 +1816,8 @@ mozilla::ipc::IPCResult BrowserChild::RecvRealTouchEvent( } UniquePtr postLayerization = APZCCallbackHelper::SendSetTargetAPZCNotification( - mPuppetWidget, document, localEvent, aGuid.mLayersId, aInputBlockId); + mPuppetWidget, document, localEvent, aGuid.mLayersId, + aInputBlockId); if (postLayerization && postLayerization->Register()) { Unused << postLayerization.release(); } diff --git a/dom/ipc/BrowserParent.cpp b/dom/ipc/BrowserParent.cpp index 3df0d4fde821..843a690a01cc 100644 --- a/dom/ipc/BrowserParent.cpp +++ b/dom/ipc/BrowserParent.cpp @@ -809,15 +809,12 @@ mozilla::ipc::IPCResult BrowserParent::RecvDropLinks( if (aLinks.Length() != mVerifyDropLinks.Length()) { loadUsingSystemPrincipal = false; } - UniquePtr links; - links = MakeUnique(aLinks.Length()); for (uint32_t i = 0; i < aLinks.Length(); i++) { if (loadUsingSystemPrincipal) { if (!aLinks[i].Equals(mVerifyDropLinks[i])) { loadUsingSystemPrincipal = false; } } - links[i] = aLinks[i].get(); } mVerifyDropLinks.Clear(); nsCOMPtr triggeringPrincipal; @@ -826,7 +823,7 @@ mozilla::ipc::IPCResult BrowserParent::RecvDropLinks( } else { triggeringPrincipal = NullPrincipal::CreateWithoutOriginAttributes(); } - browser->DropLinks(aLinks.Length(), links.get(), triggeringPrincipal); + browser->DropLinks(aLinks, triggeringPrincipal); } return IPC_OK(); } @@ -1394,42 +1391,36 @@ bool BrowserParent::QueryDropLinksForVerification() { // verification array and store all links that are being dragged. mVerifyDropLinks.Clear(); - uint32_t linksCount = 0; - nsIDroppedLinkItem** droppedLinkedItems = nullptr; - dropHandler->QueryLinks(initialDataTransfer, &linksCount, - &droppedLinkedItems); + nsTArray> droppedLinkItems; + dropHandler->QueryLinks(initialDataTransfer, droppedLinkItems); // Since the entire event is cancelled if one of the links is invalid, // we can store all links on the parent side without any prior // validation checks. nsresult rv = NS_OK; - for (uint32_t i = 0; i < linksCount; i++) { + for (nsIDroppedLinkItem* item : droppedLinkItems) { nsString tmp; - rv = droppedLinkedItems[i]->GetUrl(tmp); + rv = item->GetUrl(tmp); if (NS_FAILED(rv)) { NS_WARNING("Failed to query url for verification"); break; } mVerifyDropLinks.AppendElement(tmp); - rv = droppedLinkedItems[i]->GetName(tmp); + rv = item->GetName(tmp); if (NS_FAILED(rv)) { NS_WARNING("Failed to query name for verification"); break; } mVerifyDropLinks.AppendElement(tmp); - rv = droppedLinkedItems[i]->GetType(tmp); + rv = item->GetType(tmp); if (NS_FAILED(rv)) { NS_WARNING("Failed to query type for verification"); break; } mVerifyDropLinks.AppendElement(tmp); } - for (uint32_t i = 0; i < linksCount; i++) { - NS_IF_RELEASE(droppedLinkedItems[i]); - } - free(droppedLinkedItems); if (NS_FAILED(rv)) { mVerifyDropLinks.Clear(); return false; @@ -2163,25 +2154,8 @@ mozilla::ipc::IPCResult BrowserParent::RecvEnableDisableCommands( browser->GetIsRemoteBrowser(&isRemoteBrowser); } if (isRemoteBrowser) { - UniquePtr enabledCommands, disabledCommands; - - if (aEnabledCommands.Length()) { - enabledCommands = MakeUnique(aEnabledCommands.Length()); - for (uint32_t c = 0; c < aEnabledCommands.Length(); c++) { - enabledCommands[c] = aEnabledCommands[c].get(); - } - } - - if (aDisabledCommands.Length()) { - disabledCommands = MakeUnique(aDisabledCommands.Length()); - for (uint32_t c = 0; c < aDisabledCommands.Length(); c++) { - disabledCommands[c] = aDisabledCommands[c].get(); - } - } - - browser->EnableDisableCommandsRemoteOnly( - aAction, aEnabledCommands.Length(), enabledCommands.get(), - aDisabledCommands.Length(), disabledCommands.get()); + browser->EnableDisableCommandsRemoteOnly(aAction, aEnabledCommands, + aDisabledCommands); } return IPC_OK(); diff --git a/dom/smil/SMILCompositor.cpp b/dom/smil/SMILCompositor.cpp index 17363a5ddf92..bd1bae189852 100644 --- a/dom/smil/SMILCompositor.cpp +++ b/dom/smil/SMILCompositor.cpp @@ -6,6 +6,7 @@ #include "SMILCompositor.h" +#include "mozilla/dom/SVGSVGElement.h" #include "nsComputedDOMStyle.h" #include "nsCSSProps.h" #include "nsHashKeys.h" @@ -147,19 +148,21 @@ nsCSSPropertyID SMILCompositor::GetCSSPropertyToAnimate() const { // If we are animating the 'width' or 'height' of an outer SVG // element we should animate it as a CSS property, but for other elements - // (e.g. ) we should animate it as a length attribute. - // The easiest way to test for an outer SVG element, is to see if it is an - // SVG-namespace element mapping its width/height attribute to style. - // - // If we have animation of 'width' or 'height' on an SVG element that is - // NOT mapping that attributes to style then it must not be an outermost SVG - // element so we should return eCSSProperty_UNKNOWN to indicate that we - // should animate as an attribute instead. + // in SVG namespace (e.g. ) we should animate it as a length attribute. if ((mKey.mAttributeName == nsGkAtoms::width || mKey.mAttributeName == nsGkAtoms::height) && - mKey.mElement->GetNameSpaceID() == kNameSpaceID_SVG && - !mKey.mElement->IsAttributeMapped(mKey.mAttributeName)) { - return eCSSProperty_UNKNOWN; + mKey.mElement->GetNameSpaceID() == kNameSpaceID_SVG) { + // Not an element. + if (!mKey.mElement->IsSVGElement(nsGkAtoms::svg)) { + return eCSSProperty_UNKNOWN; + } + + // An inner element + if (static_cast(*mKey.mElement).IsInner()) { + return eCSSProperty_UNKNOWN; + } + + // Indeed an outer element, fall through. } return propID; diff --git a/dom/svg/SVGCircleElement.cpp b/dom/svg/SVGCircleElement.cpp index 014de7545b6f..d8dc354b2bbd 100644 --- a/dom/svg/SVGCircleElement.cpp +++ b/dom/svg/SVGCircleElement.cpp @@ -4,11 +4,13 @@ * 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 "ComputedStyle.h" #include "mozilla/dom/SVGCircleElement.h" #include "mozilla/gfx/2D.h" #include "nsGkAtoms.h" #include "mozilla/dom/SVGCircleElementBinding.h" #include "mozilla/dom/SVGLengthBinding.h" +#include "SVGGeometryProperty.h" NS_IMPL_NS_NEW_SVG_ELEMENT(Circle) @@ -37,6 +39,13 @@ SVGCircleElement::SVGCircleElement( already_AddRefed&& aNodeInfo) : SVGCircleElementBase(std::move(aNodeInfo)) {} +bool SVGCircleElement::IsAttributeMapped(const nsAtom* aAttribute) const { + return IsInLengthInfo(aAttribute, sLengthInfo) || + SVGCircleElementBase::IsAttributeMapped(aAttribute); +} + +namespace SVGT = SVGGeometryProperty::Tags; + //---------------------------------------------------------------------- // nsINode methods @@ -61,8 +70,11 @@ already_AddRefed SVGCircleElement::R() { /* virtual */ bool SVGCircleElement::HasValidDimensions() const { - return mLengthAttributes[ATTR_R].IsExplicitlySet() && - mLengthAttributes[ATTR_R].GetAnimValInSpecifiedUnits() > 0; + float r; + + MOZ_ASSERT(GetPrimaryFrame()); + SVGGeometryProperty::ResolveAll(this, &r); + return r > 0; } SVGElement::LengthAttributesInfo SVGCircleElement::GetLengthInfo() { @@ -77,7 +89,10 @@ bool SVGCircleElement::GetGeometryBounds( Rect* aBounds, const StrokeOptions& aStrokeOptions, const Matrix& aToBoundsSpace, const Matrix* aToNonScalingStrokeSpace) { float x, y, r; - GetAnimatedLengthValues(&x, &y, &r, nullptr); + + MOZ_ASSERT(GetPrimaryFrame()); + SVGGeometryProperty::ResolveAll(this, &x, &y, + &r); if (r <= 0.f) { // Rendering of the element is disabled @@ -112,7 +127,9 @@ bool SVGCircleElement::GetGeometryBounds( already_AddRefed SVGCircleElement::BuildPath(PathBuilder* aBuilder) { float x, y, r; - GetAnimatedLengthValues(&x, &y, &r, nullptr); + MOZ_ASSERT(GetPrimaryFrame()); + SVGGeometryProperty::ResolveAll(this, &x, &y, + &r); if (r <= 0.0f) { return nullptr; @@ -123,5 +140,30 @@ already_AddRefed SVGCircleElement::BuildPath(PathBuilder* aBuilder) { return aBuilder->Finish(); } +bool SVGCircleElement::IsLengthChangedViaCSS(const ComputedStyle& aNewStyle, + const ComputedStyle& aOldStyle) { + auto *newSVGReset = aNewStyle.StyleSVGReset(), + *oldSVGReset = aOldStyle.StyleSVGReset(); + + return newSVGReset->mCx != oldSVGReset->mCx || + newSVGReset->mCy != oldSVGReset->mCy || + newSVGReset->mR != oldSVGReset->mR; +} + +nsCSSPropertyID SVGCircleElement::GetCSSPropertyIdForAttrEnum( + uint8_t aAttrEnum) { + switch (aAttrEnum) { + case ATTR_CX: + return eCSSProperty_cx; + case ATTR_CY: + return eCSSProperty_cy; + case ATTR_R: + return eCSSProperty_r; + default: + MOZ_ASSERT_UNREACHABLE("Unknown attr enum"); + return eCSSProperty_UNKNOWN; + } +} + } // namespace dom } // namespace mozilla diff --git a/dom/svg/SVGCircleElement.h b/dom/svg/SVGCircleElement.h index b0be1f8e021d..efd82e5d7f53 100644 --- a/dom/svg/SVGCircleElement.h +++ b/dom/svg/SVGCircleElement.h @@ -7,6 +7,7 @@ #ifndef mozilla_dom_SVGCircleElement_h #define mozilla_dom_SVGCircleElement_h +#include "nsCSSPropertyID.h" #include "SVGGeometryElement.h" #include "SVGAnimatedLength.h" @@ -14,6 +15,8 @@ nsresult NS_NewSVGCircleElement( nsIContent** aResult, already_AddRefed&& aNodeInfo); namespace mozilla { +class ComputedStyle; + namespace dom { typedef SVGGeometryElement SVGCircleElementBase; @@ -29,6 +32,8 @@ class SVGCircleElement final : public SVGCircleElementBase { already_AddRefed&& aNodeInfo)); public: + NS_IMETHOD_(bool) IsAttributeMapped(const nsAtom* aAttribute) const override; + // nsSVGSVGElement methods: virtual bool HasValidDimensions() const override; @@ -41,6 +46,10 @@ class SVGCircleElement final : public SVGCircleElementBase { virtual nsresult Clone(dom::NodeInfo*, nsINode** aResult) const override; + static bool IsLengthChangedViaCSS(const ComputedStyle& aNewStyle, + const ComputedStyle& aOldStyle); + static nsCSSPropertyID GetCSSPropertyIdForAttrEnum(uint8_t aAttrEnum); + // WebIDL already_AddRefed Cx(); already_AddRefed Cy(); diff --git a/dom/svg/SVGElement.cpp b/dom/svg/SVGElement.cpp index 9c023336f356..7635ff0e6c22 100644 --- a/dom/svg/SVGElement.cpp +++ b/dom/svg/SVGElement.cpp @@ -30,6 +30,7 @@ #include "nsAttrValueOrString.h" #include "nsCSSProps.h" #include "nsContentUtils.h" +#include "nsDOMCSSAttrDeclaration.h" #include "nsICSSDeclaration.h" #include "nsIContentInlines.h" #include "mozilla/dom/Document.h" @@ -53,6 +54,7 @@ #include "SVGAnimatedOrient.h" #include "SVGAnimatedString.h" #include "SVGAnimatedViewBox.h" +#include "SVGGeometryProperty.h" #include "SVGMotionSMILAttr.h" #include @@ -1020,6 +1022,41 @@ already_AddRefed SVGElement::ClassName() { return mClassAttribute.ToDOMAnimatedString(this); } +/* static */ +bool SVGElement::UpdateDeclarationBlockFromLength( + DeclarationBlock& aBlock, nsCSSPropertyID aPropId, + const SVGAnimatedLength& aLength, ValToUse aValToUse) { + aBlock.AssertMutable(); + + float value; + if (aValToUse == ValToUse::Anim) { + value = aLength.GetAnimValInSpecifiedUnits(); + } else { + MOZ_ASSERT(aValToUse == ValToUse::Base); + value = aLength.GetBaseValInSpecifiedUnits(); + } + + // SVG parser doesn't check non-negativity of some parsed value, + // we should not pass those to CSS side. + if (value < 0 && + SVGGeometryProperty::IsNonNegativeGeometryProperty(aPropId)) { + return false; + } + + nsCSSUnit cssUnit = SVGGeometryProperty::SpecifiedUnitTypeToCSSUnit( + aLength.GetSpecifiedUnitType()); + + if (cssUnit == eCSSUnit_Percent) { + Servo_DeclarationBlock_SetPercentValue(aBlock.Raw(), aPropId, + value / 100.f); + } else { + Servo_DeclarationBlock_SetLengthValue(aBlock.Raw(), aPropId, value, + cssUnit); + } + + return true; +} + //------------------------------------------------------------------------ // Helper class: MappedAttrParser, for parsing values of mapped attributes @@ -1035,6 +1072,9 @@ class MOZ_STACK_CLASS MappedAttrParser { void ParseMappedAttrValue(nsAtom* aMappedAttrName, const nsAString& aMappedAttrValue); + void TellStyleAlreadyParsedResult(nsAtom const* aAtom, + SVGAnimatedLength const& aLength); + // If we've parsed any values for mapped attributes, this method returns the // already_AddRefed css::Declaration that incorporates the parsed // values. Otherwise, this method returns null. @@ -1122,6 +1162,18 @@ void MappedAttrParser::ParseMappedAttrValue(nsAtom* aMappedAttrName, } } +void MappedAttrParser::TellStyleAlreadyParsedResult( + nsAtom const* aAtom, SVGAnimatedLength const& aLength) { + if (!mDecl) { + mDecl = new DeclarationBlock(); + } + nsCSSPropertyID propertyID = + nsCSSProps::LookupProperty(nsDependentAtomString(aAtom)); + + SVGElement::UpdateDeclarationBlockFromLength(*mDecl, propertyID, aLength, + SVGElement::ValToUse::Base); +} + already_AddRefed MappedAttrParser::GetDeclarationBlock() { return mDecl.forget(); } @@ -1145,6 +1197,9 @@ void SVGElement::UpdateContentDeclarationBlock() { MappedAttrParser mappedAttrParser(doc->CSSLoader(), doc->GetDocumentURI(), GetBaseURI(), this); + bool lengthAffectsStyle = + SVGGeometryProperty::ElementMapsLengthsToStyle(this); + for (uint32_t i = 0; i < attrCount; ++i) { const nsAttrName* attrName = mAttrs.AttrNameAt(i); if (!attrName->IsAtom() || !IsAttributeMapped(attrName->Atom())) continue; @@ -1177,6 +1232,20 @@ void SVGElement::UpdateContentDeclarationBlock() { } } + if (lengthAffectsStyle) { + auto const* length = GetAnimatedLength(attrName->Atom()); + + if (length && length->HasBaseVal()) { + // This is an element with geometry property set via SVG attribute, + // and the attribute is already successfully parsed. We want to go + // through the optimized path to tell the style system the result + // directly, rather than let it parse the same thing again. + mappedAttrParser.TellStyleAlreadyParsedResult(attrName->Atom(), + *length); + continue; + } + } + nsAutoString value; mAttrs.AttrAt(i)->ToString(value); mappedAttrParser.ParseMappedAttrValue(attrName->Atom(), value); @@ -1391,6 +1460,15 @@ void SVGElement::DidChangeLength(uint8_t aAttrEnum, } void SVGElement::DidAnimateLength(uint8_t aAttrEnum) { + if (SVGGeometryProperty::ElementMapsLengthsToStyle(this)) { + nsCSSPropertyID propId = + SVGGeometryProperty::AttrEnumToCSSPropId(this, aAttrEnum); + + SMILOverrideStyle()->SetSMILValue(propId, + GetLengthInfo().mLengths[aAttrEnum]); + return; + } + ClearAnyCachedPath(); nsIFrame* frame = GetPrimaryFrame(); @@ -1411,7 +1489,6 @@ SVGAnimatedLength* SVGElement::GetAnimatedLength(const nsAtom* aAttrName) { return &lengthInfo.mLengths[i]; } } - MOZ_ASSERT(false, "no matching length found"); return nullptr; } diff --git a/dom/svg/SVGElement.h b/dom/svg/SVGElement.h index 0a745ecc1fdc..e43546f9af30 100644 --- a/dom/svg/SVGElement.h +++ b/dom/svg/SVGElement.h @@ -165,6 +165,12 @@ class SVGElement : public SVGElementBase // nsIContent virtual bool HasValidDimensions() const { return true; } void SetLength(nsAtom* aName, const SVGAnimatedLength& aLength); + enum class ValToUse { Base, Anim }; + static bool UpdateDeclarationBlockFromLength(DeclarationBlock& aBlock, + nsCSSPropertyID aPropId, + const SVGAnimatedLength& aLength, + ValToUse aValToUse); + nsAttrValue WillChangeLength(uint8_t aAttrEnum); nsAttrValue WillChangeNumberPair(uint8_t aAttrEnum); nsAttrValue WillChangeIntegerPair(uint8_t aAttrEnum); diff --git a/dom/svg/SVGEllipseElement.cpp b/dom/svg/SVGEllipseElement.cpp index ef88e78566c0..e29b6b08606f 100644 --- a/dom/svg/SVGEllipseElement.cpp +++ b/dom/svg/SVGEllipseElement.cpp @@ -4,12 +4,14 @@ * 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 "ComputedStyle.h" #include "mozilla/dom/SVGEllipseElement.h" #include "mozilla/dom/SVGEllipseElementBinding.h" #include "mozilla/dom/SVGLengthBinding.h" #include "mozilla/gfx/2D.h" #include "mozilla/gfx/PathHelpers.h" #include "mozilla/RefPtr.h" +#include "SVGGeometryProperty.h" NS_IMPL_NS_NEW_SVG_ELEMENT(Ellipse) @@ -41,6 +43,13 @@ SVGEllipseElement::SVGEllipseElement( already_AddRefed&& aNodeInfo) : SVGEllipseElementBase(std::move(aNodeInfo)) {} +bool SVGEllipseElement::IsAttributeMapped(const nsAtom* aAttribute) const { + return IsInLengthInfo(aAttribute, sLengthInfo) || + SVGEllipseElementBase::IsAttributeMapped(aAttribute); +} + +namespace SVGT = SVGGeometryProperty::Tags; + //---------------------------------------------------------------------- // nsINode methods @@ -70,10 +79,12 @@ already_AddRefed SVGEllipseElement::Ry() { /* virtual */ bool SVGEllipseElement::HasValidDimensions() const { - return mLengthAttributes[RX].IsExplicitlySet() && - mLengthAttributes[RX].GetAnimValInSpecifiedUnits() > 0 && - mLengthAttributes[RY].IsExplicitlySet() && - mLengthAttributes[RY].GetAnimValInSpecifiedUnits() > 0; + float rx, ry; + + MOZ_ASSERT(GetPrimaryFrame()); + SVGGeometryProperty::ResolveAll(this, &rx, &ry); + + return rx > 0 && ry > 0; } SVGElement::LengthAttributesInfo SVGEllipseElement::GetLengthInfo() { @@ -88,7 +99,10 @@ bool SVGEllipseElement::GetGeometryBounds( Rect* aBounds, const StrokeOptions& aStrokeOptions, const Matrix& aToBoundsSpace, const Matrix* aToNonScalingStrokeSpace) { float x, y, rx, ry; - GetAnimatedLengthValues(&x, &y, &rx, &ry, nullptr); + + MOZ_ASSERT(GetPrimaryFrame()); + SVGGeometryProperty::ResolveAll( + this, &x, &y, &rx, &ry); if (rx <= 0.f || ry <= 0.f) { // Rendering of the element is disabled @@ -124,7 +138,10 @@ bool SVGEllipseElement::GetGeometryBounds( already_AddRefed SVGEllipseElement::BuildPath(PathBuilder* aBuilder) { float x, y, rx, ry; - GetAnimatedLengthValues(&x, &y, &rx, &ry, nullptr); + + MOZ_ASSERT(GetPrimaryFrame()); + SVGGeometryProperty::ResolveAll( + this, &x, &y, &rx, &ry); if (rx <= 0.0f || ry <= 0.0f) { return nullptr; @@ -135,5 +152,33 @@ already_AddRefed SVGEllipseElement::BuildPath(PathBuilder* aBuilder) { return aBuilder->Finish(); } +bool SVGEllipseElement::IsLengthChangedViaCSS(const ComputedStyle& aNewStyle, + const ComputedStyle& aOldStyle) { + auto *newSVGReset = aNewStyle.StyleSVGReset(), + *oldSVGReset = aOldStyle.StyleSVGReset(); + + return newSVGReset->mCx != oldSVGReset->mCx || + newSVGReset->mCy != oldSVGReset->mCy || + newSVGReset->mRx != oldSVGReset->mRx || + newSVGReset->mRy != oldSVGReset->mRy; +} + +nsCSSPropertyID SVGEllipseElement::GetCSSPropertyIdForAttrEnum( + uint8_t aAttrEnum) { + switch (aAttrEnum) { + case CX: + return eCSSProperty_cx; + case CY: + return eCSSProperty_cy; + case RX: + return eCSSProperty_rx; + case RY: + return eCSSProperty_ry; + default: + MOZ_ASSERT_UNREACHABLE("Unknown attr enum"); + return eCSSProperty_UNKNOWN; + } +} + } // namespace dom } // namespace mozilla diff --git a/dom/svg/SVGEllipseElement.h b/dom/svg/SVGEllipseElement.h index 26601919c29b..3e91c83c4afd 100644 --- a/dom/svg/SVGEllipseElement.h +++ b/dom/svg/SVGEllipseElement.h @@ -7,6 +7,7 @@ #ifndef mozilla_dom_SVGEllipseElement_h #define mozilla_dom_SVGEllipseElement_h +#include "nsCSSPropertyID.h" #include "SVGAnimatedLength.h" #include "SVGGeometryElement.h" @@ -14,6 +15,8 @@ nsresult NS_NewSVGEllipseElement( nsIContent** aResult, already_AddRefed&& aNodeInfo); namespace mozilla { +class ComputedStyle; + namespace dom { typedef SVGGeometryElement SVGEllipseElementBase; @@ -29,6 +32,8 @@ class SVGEllipseElement final : public SVGEllipseElementBase { already_AddRefed&& aNodeInfo)); public: + NS_IMETHOD_(bool) IsAttributeMapped(const nsAtom* aAttribute) const override; + // nsSVGSVGElement methods: virtual bool HasValidDimensions() const override; @@ -41,6 +46,10 @@ class SVGEllipseElement final : public SVGEllipseElementBase { virtual nsresult Clone(dom::NodeInfo*, nsINode** aResult) const override; + static bool IsLengthChangedViaCSS(const ComputedStyle& aNewStyle, + const ComputedStyle& aOldStyle); + static nsCSSPropertyID GetCSSPropertyIdForAttrEnum(uint8_t aAttrEnum); + // WebIDL already_AddRefed Cx(); already_AddRefed Cy(); diff --git a/dom/svg/SVGForeignObjectElement.cpp b/dom/svg/SVGForeignObjectElement.cpp index d52fb5f318da..cc9b800fb81c 100644 --- a/dom/svg/SVGForeignObjectElement.cpp +++ b/dom/svg/SVGForeignObjectElement.cpp @@ -11,6 +11,7 @@ #include "mozilla/dom/SVGDocument.h" #include "mozilla/dom/SVGForeignObjectElementBinding.h" #include "mozilla/dom/SVGLengthBinding.h" +#include "SVGGeometryProperty.h" NS_IMPL_NS_NEW_SVG_ELEMENT(ForeignObject) @@ -40,6 +41,8 @@ SVGForeignObjectElement::SVGForeignObjectElement( already_AddRefed&& aNodeInfo) : SVGGraphicsElement(std::move(aNodeInfo)) {} +namespace SVGT = SVGGeometryProperty::Tags; + //---------------------------------------------------------------------- // nsINode methods @@ -77,8 +80,16 @@ gfxMatrix SVGForeignObjectElement::PrependLocalTransformsTo( } // our 'x' and 'y' attributes: float x, y; - const_cast(this)->GetAnimatedLengthValues(&x, &y, - nullptr); + + if (GetPrimaryFrame()) { + SVGGeometryProperty::ResolveAll(this, &x, &y); + } else { + // This function might be called for element in display:none subtree + // (e.g. getScreenCTM), we fall back to use SVG attributes. + const_cast(this)->GetAnimatedLengthValues( + &x, &y, nullptr); + } + gfxMatrix toUserSpace = gfxMatrix::Translation(x, y); if (aWhich == eChildToUserSpace) { return toUserSpace * aMatrix; @@ -89,10 +100,12 @@ gfxMatrix SVGForeignObjectElement::PrependLocalTransformsTo( /* virtual */ bool SVGForeignObjectElement::HasValidDimensions() const { - return mLengthAttributes[ATTR_WIDTH].IsExplicitlySet() && - mLengthAttributes[ATTR_WIDTH].GetAnimValInSpecifiedUnits() > 0 && - mLengthAttributes[ATTR_HEIGHT].IsExplicitlySet() && - mLengthAttributes[ATTR_HEIGHT].GetAnimValInSpecifiedUnits() > 0; + float width, height; + + MOZ_ASSERT(GetPrimaryFrame()); + SVGGeometryProperty::ResolveAll( + const_cast(this), &width, &height); + return width > 0 && height > 0; } //---------------------------------------------------------------------- @@ -109,7 +122,8 @@ SVGForeignObjectElement::IsAttributeMapped(const nsAtom* name) const { sTextContentElementsMap, sViewportsMap}; - return FindAttributeDependence(name, map) || + return IsInLengthInfo(name, sLengthInfo) || + FindAttributeDependence(name, map) || SVGGraphicsElement::IsAttributeMapped(name); } @@ -121,5 +135,22 @@ SVGElement::LengthAttributesInfo SVGForeignObjectElement::GetLengthInfo() { ArrayLength(sLengthInfo)); } +nsCSSPropertyID SVGForeignObjectElement::GetCSSPropertyIdForAttrEnum( + uint8_t aAttrEnum) { + switch (aAttrEnum) { + case ATTR_X: + return eCSSProperty_x; + case ATTR_Y: + return eCSSProperty_y; + case ATTR_WIDTH: + return eCSSProperty_width; + case ATTR_HEIGHT: + return eCSSProperty_height; + default: + MOZ_ASSERT_UNREACHABLE("Unknown attr enum"); + return eCSSProperty_UNKNOWN; + } +} + } // namespace dom } // namespace mozilla diff --git a/dom/svg/SVGForeignObjectElement.h b/dom/svg/SVGForeignObjectElement.h index 8077d783ef46..1e9d1428e6e8 100644 --- a/dom/svg/SVGForeignObjectElement.h +++ b/dom/svg/SVGForeignObjectElement.h @@ -8,6 +8,7 @@ #define mozilla_dom_SVGForeignObjectElement_h #include "mozilla/dom/SVGGraphicsElement.h" +#include "nsCSSPropertyID.h" #include "SVGAnimatedLength.h" nsresult NS_NewSVGForeignObjectElement( @@ -42,6 +43,8 @@ class SVGForeignObjectElement final : public SVGGraphicsElement { virtual nsresult Clone(dom::NodeInfo*, nsINode** aResult) const override; + static nsCSSPropertyID GetCSSPropertyIdForAttrEnum(uint8_t aAttrEnum); + // WebIDL already_AddRefed X(); already_AddRefed Y(); diff --git a/dom/svg/SVGGeometryElement.cpp b/dom/svg/SVGGeometryElement.cpp index a86f18846dea..5b211bc95570 100644 --- a/dom/svg/SVGGeometryElement.cpp +++ b/dom/svg/SVGGeometryElement.cpp @@ -10,8 +10,11 @@ #include "gfxPlatform.h" #include "nsCOMPtr.h" #include "nsComputedDOMStyle.h" -#include "SVGAnimatedLength.h" #include "nsSVGUtils.h" +#include "SVGAnimatedLength.h" +#include "SVGCircleElement.h" +#include "SVGEllipseElement.h" +#include "SVGRectElement.h" #include "mozilla/dom/SVGLengthBinding.h" #include "mozilla/gfx/2D.h" #include "mozilla/RefPtr.h" @@ -111,6 +114,22 @@ already_AddRefed SVGGeometryElement::GetOrBuildPathForMeasuring() { return GetOrBuildPath(drawTarget, fillRule); } +bool SVGGeometryElement::IsGeometryChangedViaCSS( + ComputedStyle const& aNewStyle, ComputedStyle const& aOldStyle) const { + if (IsSVGElement(nsGkAtoms::rect)) { + return SVGRectElement::IsLengthChangedViaCSS(aNewStyle, aOldStyle); + } + + if (IsSVGElement(nsGkAtoms::circle)) { + return SVGCircleElement::IsLengthChangedViaCSS(aNewStyle, aOldStyle); + } + + if (IsSVGElement(nsGkAtoms::ellipse)) { + return SVGEllipseElement::IsLengthChangedViaCSS(aNewStyle, aOldStyle); + } + return false; +} + FillRule SVGGeometryElement::GetFillRule() { FillRule fillRule = FillRule::FILL_WINDING; // Equivalent to StyleFillRule::Nonzero diff --git a/dom/svg/SVGGeometryElement.h b/dom/svg/SVGGeometryElement.h index cc35e6264c5d..d7aa0a048e9b 100644 --- a/dom/svg/SVGGeometryElement.h +++ b/dom/svg/SVGGeometryElement.h @@ -191,6 +191,13 @@ class SVGGeometryElement : public SVGGeometryElementBase { */ virtual already_AddRefed GetOrBuildPathForMeasuring(); + /** + * Return |true| if some geometry properties (|x|, |y|, etc) are changed + * because of CSS change. + */ + bool IsGeometryChangedViaCSS(ComputedStyle const& aNewStyle, + ComputedStyle const& aOldStyle) const; + /** * Returns the current computed value of the CSS property 'fill-rule' for * this element. diff --git a/dom/svg/SVGGeometryProperty.cpp b/dom/svg/SVGGeometryProperty.cpp new file mode 100644 index 000000000000..62e1e87006b6 --- /dev/null +++ b/dom/svg/SVGGeometryProperty.cpp @@ -0,0 +1,87 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=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/. */ + +#include "SVGGeometryProperty.h" +#include "SVGCircleElement.h" +#include "SVGEllipseElement.h" +#include "SVGForeignObjectElement.h" +#include "SVGRectElement.h" + +namespace mozilla { +namespace dom { +namespace SVGGeometryProperty { + +nsCSSUnit SpecifiedUnitTypeToCSSUnit(uint8_t aSpecifiedUnit) { + switch (aSpecifiedUnit) { + case SVGLength_Binding::SVG_LENGTHTYPE_NUMBER: + case SVGLength_Binding::SVG_LENGTHTYPE_PX: + return nsCSSUnit::eCSSUnit_Pixel; + + case SVGLength_Binding::SVG_LENGTHTYPE_MM: + return nsCSSUnit::eCSSUnit_Millimeter; + + case SVGLength_Binding::SVG_LENGTHTYPE_CM: + return nsCSSUnit::eCSSUnit_Centimeter; + + case SVGLength_Binding::SVG_LENGTHTYPE_IN: + return nsCSSUnit::eCSSUnit_Inch; + + case SVGLength_Binding::SVG_LENGTHTYPE_PT: + return nsCSSUnit::eCSSUnit_Point; + + case SVGLength_Binding::SVG_LENGTHTYPE_PC: + return nsCSSUnit::eCSSUnit_Pica; + + case SVGLength_Binding::SVG_LENGTHTYPE_PERCENTAGE: + return nsCSSUnit::eCSSUnit_Percent; + + case SVGLength_Binding::SVG_LENGTHTYPE_EMS: + return nsCSSUnit::eCSSUnit_EM; + + case SVGLength_Binding::SVG_LENGTHTYPE_EXS: + return nsCSSUnit::eCSSUnit_XHeight; + + default: + MOZ_ASSERT_UNREACHABLE("Unknown unit type"); + return nsCSSUnit::eCSSUnit_Pixel; + } +} + +nsCSSPropertyID AttrEnumToCSSPropId(const SVGElement* aElement, + uint8_t aAttrEnum) { + // This is a very trivial function only applied to a few elements, + // so we want to avoid making it virtual. + if (aElement->IsSVGElement(nsGkAtoms::rect)) { + return SVGRectElement::GetCSSPropertyIdForAttrEnum(aAttrEnum); + } + if (aElement->IsSVGElement(nsGkAtoms::circle)) { + return SVGCircleElement::GetCSSPropertyIdForAttrEnum(aAttrEnum); + } + if (aElement->IsSVGElement(nsGkAtoms::ellipse)) { + return SVGEllipseElement::GetCSSPropertyIdForAttrEnum(aAttrEnum); + } + if (aElement->IsSVGElement(nsGkAtoms::foreignObject)) { + return SVGForeignObjectElement::GetCSSPropertyIdForAttrEnum(aAttrEnum); + } + return eCSSProperty_UNKNOWN; +} + +bool IsNonNegativeGeometryProperty(nsCSSPropertyID aProp) { + return aProp == eCSSProperty_r || aProp == eCSSProperty_rx || + aProp == eCSSProperty_ry || aProp == eCSSProperty_width || + aProp == eCSSProperty_height; +} + +bool ElementMapsLengthsToStyle(SVGElement const* aElement) { + return aElement->IsSVGElement(nsGkAtoms::rect) || + aElement->IsSVGElement(nsGkAtoms::circle) || + aElement->IsSVGElement(nsGkAtoms::ellipse) || + aElement->IsSVGElement(nsGkAtoms::foreignObject); +} + +} // namespace SVGGeometryProperty +} // namespace dom +} // namespace mozilla diff --git a/dom/svg/SVGGeometryProperty.h b/dom/svg/SVGGeometryProperty.h new file mode 100644 index 000000000000..b28ec64335fe --- /dev/null +++ b/dom/svg/SVGGeometryProperty.h @@ -0,0 +1,162 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=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/. */ + +#ifndef mozilla_dom_SVGGeometryProperty_SVGGeometryProperty_h +#define mozilla_dom_SVGGeometryProperty_SVGGeometryProperty_h + +#include "mozilla/dom/SVGElement.h" +#include "SVGAnimatedLength.h" +#include "ComputedStyle.h" +#include "nsIFrame.h" +#include + +namespace mozilla { +namespace dom { + +namespace SVGGeometryProperty { +namespace ResolverTypes { +struct LengthPercentNoAuto {}; +struct LengthPercentRXY {}; +struct LengthPercentWidthHeight {}; +} // namespace ResolverTypes + +namespace Tags { + +#define SVGGEOMETRYPROPERTY_GENERATETAG(tagName, resolver, direction, \ + styleStruct) \ + struct tagName { \ + using ResolverType = ResolverTypes::resolver; \ + constexpr static auto CtxDirection = SVGContentUtils::direction; \ + constexpr static auto Getter = &styleStruct::m##tagName; \ + } + +SVGGEOMETRYPROPERTY_GENERATETAG(X, LengthPercentNoAuto, X, nsStyleSVGReset); +SVGGEOMETRYPROPERTY_GENERATETAG(Y, LengthPercentNoAuto, Y, nsStyleSVGReset); +SVGGEOMETRYPROPERTY_GENERATETAG(Cx, LengthPercentNoAuto, X, nsStyleSVGReset); +SVGGEOMETRYPROPERTY_GENERATETAG(Cy, LengthPercentNoAuto, Y, nsStyleSVGReset); +SVGGEOMETRYPROPERTY_GENERATETAG(R, LengthPercentNoAuto, XY, nsStyleSVGReset); +SVGGEOMETRYPROPERTY_GENERATETAG(Width, LengthPercentWidthHeight, X, + nsStylePosition); +SVGGEOMETRYPROPERTY_GENERATETAG(Height, LengthPercentWidthHeight, Y, + nsStylePosition); + +#undef SVGGEOMETRYPROPERTY_GENERATETAG + +struct Ry; +struct Rx { + using ResolverType = ResolverTypes::LengthPercentRXY; + constexpr static auto CtxDirection = SVGContentUtils::X; + constexpr static auto Getter = &nsStyleSVGReset::mRx; + using CounterPart = Ry; +}; +struct Ry { + using ResolverType = ResolverTypes::LengthPercentRXY; + constexpr static auto CtxDirection = SVGContentUtils::Y; + constexpr static auto Getter = &nsStyleSVGReset::mRy; + using CounterPart = Rx; +}; + +} // namespace Tags + +namespace details { +template +using AlwaysFloat = float; + +using CtxDirectionType = decltype(SVGContentUtils::X); + +template +float ResolvePureLengthPercentage(SVGElement* aElement, + const LengthPercentage& aLP) { + return aLP.ResolveToCSSPixelsWith( + [&] { return CSSCoord{SVGElementMetrics(aElement).GetAxisLength(CTD)}; }); +} + +template +float ResolveImpl(ComputedStyle const& aStyle, SVGElement* aElement, + ResolverTypes::LengthPercentNoAuto) { + auto const& value = aStyle.StyleSVGReset()->*Tag::Getter; + return ResolvePureLengthPercentage(aElement, value); +} + +template +float ResolveImpl(ComputedStyle const& aStyle, SVGElement* aElement, + ResolverTypes::LengthPercentWidthHeight) { + static_assert( + std::is_same{} || std::is_same{}, + "Wrong tag"); + + auto const& value = aStyle.StylePosition()->*Tag::Getter; + if (value.IsLengthPercentage()) { + return ResolvePureLengthPercentage( + aElement, value.AsLengthPercentage()); + } + + // |auto| and |max-content| etc. are treated as 0. + return 0.f; +} + +template +float ResolveImpl(ComputedStyle const& aStyle, SVGElement* aElement, + ResolverTypes::LengthPercentRXY) { + static_assert(std::is_same{} || std::is_same{}, + "Wrong tag"); + + auto const& value = aStyle.StyleSVGReset()->*Tag::Getter; + if (value.IsLengthPercentage()) { + return ResolvePureLengthPercentage( + aElement, value.AsLengthPercentage()); + } + + MOZ_ASSERT(value.IsAuto()); + using Rother = typename Tag::CounterPart; + auto const& valueOther = aStyle.StyleSVGReset()->*Rother::Getter; + + if (valueOther.IsAuto()) { + // Per SVG2, |Rx|, |Ry| resolve to 0 if both are |auto| + return 0.f; + } + + // If |Rx| is auto while |Ry| not, |Rx| gets the value of |Ry|. + return ResolvePureLengthPercentage( + aElement, valueOther.AsLengthPercentage()); +} + +} // namespace details + +template +float ResolveWith(const ComputedStyle& aStyle, const SVGElement* aElement) { + // TODO: There are a lot of utilities lacking const-ness in dom/svg. + // We should fix that problem and remove this `const_cast`. + return details::ResolveImpl(aStyle, const_cast(aElement), + typename Tag::ResolverType{}); +} + +// To add support for new properties, or to handle special cases for +// existing properties, you can add a new tag in |Tags| and |ResolverTypes| +// namespace, then implement the behavior in |details::ResolveImpl|. +template +bool ResolveAll(const SVGElement* aElement, + details::AlwaysFloat*... aRes) { + if (nsIFrame const* f = aElement->GetPrimaryFrame()) { + using dummy = int[]; + (void)dummy{0, (*aRes = ResolveWith(*f->Style(), aElement), 0)...}; + return true; + } + return false; +} + +nsCSSUnit SpecifiedUnitTypeToCSSUnit(uint8_t aSpecifiedUnit); +nsCSSPropertyID AttrEnumToCSSPropId(const SVGElement* aElement, + uint8_t aAttrEnum); + +bool IsNonNegativeGeometryProperty(nsCSSPropertyID aProp); +bool ElementMapsLengthsToStyle(SVGElement const* aElement); + +} // namespace SVGGeometryProperty +} // namespace dom +} // namespace mozilla + +#endif diff --git a/dom/svg/SVGGraphicsElement.h b/dom/svg/SVGGraphicsElement.h index 19399e8ef6a6..4ff220a702a3 100644 --- a/dom/svg/SVGGraphicsElement.h +++ b/dom/svg/SVGGraphicsElement.h @@ -32,6 +32,16 @@ class SVGGraphicsElement : public SVGGraphicsElementBase, public SVGTests { // returns true if focusability has been definitively determined otherwise // false bool IsSVGFocusable(bool* aIsFocusable, int32_t* aTabIndex); + + template + bool IsInLengthInfo(const nsAtom* aAttribute, const T& aLengthInfos) const { + for (auto const& e : aLengthInfos) { + if (e.mName == aAttribute) { + return true; + } + } + return false; + } }; } // namespace dom diff --git a/dom/svg/SVGImageElement.cpp b/dom/svg/SVGImageElement.cpp index 0bbab6cb3049..9c939c337e1f 100644 --- a/dom/svg/SVGImageElement.cpp +++ b/dom/svg/SVGImageElement.cpp @@ -218,7 +218,8 @@ SVGImageElement::IsAttributeMapped(const nsAtom* name) const { sViewportsMap, }; - return FindAttributeDependence(name, map) || + return IsInLengthInfo(name, sLengthInfo) || + FindAttributeDependence(name, map) || SVGImageElementBase::IsAttributeMapped(name); } diff --git a/dom/svg/SVGRectElement.cpp b/dom/svg/SVGRectElement.cpp index 3f1da44b66df..37309e8d7aaa 100644 --- a/dom/svg/SVGRectElement.cpp +++ b/dom/svg/SVGRectElement.cpp @@ -5,13 +5,14 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/dom/SVGRectElement.h" -#include "nsGkAtoms.h" #include "mozilla/dom/SVGLengthBinding.h" #include "mozilla/dom/SVGRectElementBinding.h" #include "mozilla/gfx/2D.h" #include "mozilla/gfx/Matrix.h" #include "mozilla/gfx/Rect.h" #include "mozilla/gfx/PathHelpers.h" +#include "nsGkAtoms.h" +#include "SVGGeometryProperty.h" #include NS_IMPL_NS_NEW_SVG_ELEMENT(Rect) @@ -49,6 +50,13 @@ SVGRectElement::SVGRectElement( already_AddRefed&& aNodeInfo) : SVGRectElementBase(std::move(aNodeInfo)) {} +bool SVGRectElement::IsAttributeMapped(const nsAtom* aAttribute) const { + return IsInLengthInfo(aAttribute, sLengthInfo) || + SVGRectElementBase::IsAttributeMapped(aAttribute); +} + +namespace SVGT = SVGGeometryProperty::Tags; + //---------------------------------------------------------------------- // nsINode methods @@ -85,10 +93,13 @@ already_AddRefed SVGRectElement::Ry() { /* virtual */ bool SVGRectElement::HasValidDimensions() const { - return mLengthAttributes[ATTR_WIDTH].IsExplicitlySet() && - mLengthAttributes[ATTR_WIDTH].GetAnimValInSpecifiedUnits() > 0 && - mLengthAttributes[ATTR_HEIGHT].IsExplicitlySet() && - mLengthAttributes[ATTR_HEIGHT].GetAnimValInSpecifiedUnits() > 0; + float width, height; + + MOZ_ASSERT(GetPrimaryFrame()); + SVGGeometryProperty::ResolveAll(this, &width, + &height); + + return width > 0 && height > 0; } SVGElement::LengthAttributesInfo SVGRectElement::GetLengthInfo() { @@ -105,8 +116,11 @@ bool SVGRectElement::GetGeometryBounds(Rect* aBounds, const Matrix* aToNonScalingStrokeSpace) { Rect rect; Float rx, ry; - GetAnimatedLengthValues(&rect.x, &rect.y, &rect.width, &rect.height, &rx, &ry, - nullptr); + + MOZ_ASSERT(GetPrimaryFrame()); + SVGGeometryProperty::ResolveAll( + this, &rect.x, &rect.y, &rect.width, &rect.height, &rx, &ry); if (rect.IsEmpty()) { // Rendering of the element disabled @@ -155,7 +169,11 @@ bool SVGRectElement::GetGeometryBounds(Rect* aBounds, void SVGRectElement::GetAsSimplePath(SimplePath* aSimplePath) { float x, y, width, height, rx, ry; - GetAnimatedLengthValues(&x, &y, &width, &height, &rx, &ry, nullptr); + + MOZ_ASSERT(GetPrimaryFrame()); + SVGGeometryProperty::ResolveAll(this, &x, &y, &width, + &height, &rx, &ry); if (width <= 0 || height <= 0) { aSimplePath->Reset(); @@ -175,7 +193,11 @@ void SVGRectElement::GetAsSimplePath(SimplePath* aSimplePath) { already_AddRefed SVGRectElement::BuildPath(PathBuilder* aBuilder) { float x, y, width, height, rx, ry; - GetAnimatedLengthValues(&x, &y, &width, &height, &rx, &ry, nullptr); + + MOZ_ASSERT(GetPrimaryFrame()); + SVGGeometryProperty::ResolveAll(this, &x, &y, &width, + &height, &rx, &ry); if (width <= 0 || height <= 0) { return nullptr; @@ -193,18 +215,6 @@ already_AddRefed SVGRectElement::BuildPath(PathBuilder* aBuilder) { aBuilder->LineTo(r.BottomLeft()); aBuilder->Close(); } else { - // If either the 'rx' or the 'ry' attribute isn't set, then we have to - // set it to the value of the other: - bool hasRx = mLengthAttributes[ATTR_RX].IsExplicitlySet(); - bool hasRy = mLengthAttributes[ATTR_RY].IsExplicitlySet(); - MOZ_ASSERT(hasRx || hasRy); - - if (hasRx && !hasRy) { - ry = rx; - } else if (hasRy && !hasRx) { - rx = ry; - } - // Clamp rx and ry to half the rect's width and height respectively: rx = std::min(rx, width / 2); ry = std::min(ry, height / 2); @@ -216,5 +226,40 @@ already_AddRefed SVGRectElement::BuildPath(PathBuilder* aBuilder) { return aBuilder->Finish(); } +bool SVGRectElement::IsLengthChangedViaCSS(const ComputedStyle& aNewStyle, + const ComputedStyle& aOldStyle) { + auto *newSVGReset = aNewStyle.StyleSVGReset(), + *oldSVGReset = aOldStyle.StyleSVGReset(); + auto *newPosition = aNewStyle.StylePosition(), + *oldPosition = aOldStyle.StylePosition(); + + return newSVGReset->mX != oldSVGReset->mX || + newSVGReset->mY != oldSVGReset->mY || + newPosition->mWidth != oldPosition->mWidth || + newPosition->mHeight != oldPosition->mHeight || + newSVGReset->mRx != oldSVGReset->mRx || + newSVGReset->mRy != oldSVGReset->mRy; +} + +nsCSSPropertyID SVGRectElement::GetCSSPropertyIdForAttrEnum(uint8_t aAttrEnum) { + switch (aAttrEnum) { + case ATTR_X: + return eCSSProperty_x; + case ATTR_Y: + return eCSSProperty_y; + case ATTR_WIDTH: + return eCSSProperty_width; + case ATTR_HEIGHT: + return eCSSProperty_height; + case ATTR_RX: + return eCSSProperty_rx; + case ATTR_RY: + return eCSSProperty_ry; + default: + MOZ_ASSERT_UNREACHABLE("Unknown attr enum"); + return eCSSProperty_UNKNOWN; + } +} + } // namespace dom } // namespace mozilla diff --git a/dom/svg/SVGRectElement.h b/dom/svg/SVGRectElement.h index 0a395f69c8fd..ba5843a052d2 100644 --- a/dom/svg/SVGRectElement.h +++ b/dom/svg/SVGRectElement.h @@ -7,6 +7,7 @@ #ifndef mozilla_dom_SVGRectElement_h #define mozilla_dom_SVGRectElement_h +#include "nsCSSPropertyID.h" #include "SVGAnimatedLength.h" #include "SVGGeometryElement.h" @@ -14,6 +15,8 @@ nsresult NS_NewSVGRectElement( nsIContent** aResult, already_AddRefed&& aNodeInfo); namespace mozilla { +class ComputedStyle; + namespace dom { typedef SVGGeometryElement SVGRectElementBase; @@ -28,6 +31,8 @@ class SVGRectElement final : public SVGRectElementBase { already_AddRefed&& aNodeInfo)); public: + NS_IMETHOD_(bool) IsAttributeMapped(const nsAtom* aAttribute) const override; + // nsSVGSVGElement methods: virtual bool HasValidDimensions() const override; @@ -42,6 +47,10 @@ class SVGRectElement final : public SVGRectElementBase { virtual nsresult Clone(dom::NodeInfo*, nsINode** aResult) const override; + static bool IsLengthChangedViaCSS(const ComputedStyle& aNewStyle, + const ComputedStyle& aOldStyle); + static nsCSSPropertyID GetCSSPropertyIdForAttrEnum(uint8_t aAttrEnum); + // WebIDL already_AddRefed X(); already_AddRefed Y(); diff --git a/dom/svg/SVGViewportElement.h b/dom/svg/SVGViewportElement.h index 60f34ee11fe5..2419ad577e13 100644 --- a/dom/svg/SVGViewportElement.h +++ b/dom/svg/SVGViewportElement.h @@ -124,6 +124,17 @@ class SVGViewportElement : public SVGGraphicsElement { mViewportHeight = aSize.height; } + /** + * Returns true if either this is an SVG element that is the child of + * another non-foreignObject SVG element, or this is a SVG element + * this is the root of a use-element shadow tree. + */ + bool IsInner() const { + const nsIContent* parent = GetFlattenedTreeParent(); + return parent && parent->IsSVGElement() && + !parent->IsSVGElement(nsGkAtoms::foreignObject); + } + // WebIDL already_AddRefed ViewBox(); already_AddRefed PreserveAspectRatio(); @@ -139,17 +150,6 @@ class SVGViewportElement : public SVGGraphicsElement { return IsInUncomposedDoc() && !GetParent(); } - /** - * Returns true if either this is an SVG element that is the child of - * another non-foreignObject SVG element, or this is a SVG element - * this is the root of a use-element shadow tree. - */ - bool IsInner() const { - const nsIContent* parent = GetFlattenedTreeParent(); - return parent && parent->IsSVGElement() && - !parent->IsSVGElement(nsGkAtoms::foreignObject); - } - /** * Returns the explicit or default preserveAspectRatio, unless we're * synthesizing a viewBox, in which case it returns the "none" value. diff --git a/dom/svg/moz.build b/dom/svg/moz.build index f4a9b1086335..e55c39a28419 100644 --- a/dom/svg/moz.build +++ b/dom/svg/moz.build @@ -181,6 +181,7 @@ UNIFIED_SOURCES += [ 'SVGFragmentIdentifier.cpp', 'SVGGElement.cpp', 'SVGGeometryElement.cpp', + 'SVGGeometryProperty.cpp', 'SVGGradientElement.cpp', 'SVGGraphicsElement.cpp', 'SVGImageElement.cpp', diff --git a/dom/u2f/tests/browser/browser_abort_visibility.js b/dom/u2f/tests/browser/browser_abort_visibility.js index 469d687b59e7..449da4d95561 100644 --- a/dom/u2f/tests/browser/browser_abort_visibility.js +++ b/dom/u2f/tests/browser/browser_abort_visibility.js @@ -70,6 +70,7 @@ add_task(async function test_abort() { Services.prefs.setBoolPref("security.webauth.u2f", true); Services.prefs.setBoolPref("security.webauth.webauthn_enable_softtoken", false); Services.prefs.setBoolPref("security.webauth.webauthn_enable_usbtoken", true); + Services.prefs.setBoolPref("security.webauth.webauthn_enable_android_fido2", false); // Create a new tab for the MakeCredential() request. let tab_create = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL); diff --git a/dom/u2f/tests/browser/browser_appid_localhost.js b/dom/u2f/tests/browser/browser_appid_localhost.js index cc7a35a0e745..cf2f08fdd6f2 100644 --- a/dom/u2f/tests/browser/browser_appid_localhost.js +++ b/dom/u2f/tests/browser/browser_appid_localhost.js @@ -25,6 +25,7 @@ add_task(async function () { Services.prefs.setBoolPref("security.webauth.u2f", true); Services.prefs.setBoolPref("security.webauth.webauthn_enable_softtoken", true); Services.prefs.setBoolPref("security.webauth.webauthn_enable_usbtoken", false); + Services.prefs.setBoolPref("security.webauth.webauthn_enable_android_fido2", false); // Open a new tab. let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL); diff --git a/dom/u2f/tests/test_appid_facet.html b/dom/u2f/tests/test_appid_facet.html index 0940244d4dfd..94f09a12e561 100644 --- a/dom/u2f/tests/test_appid_facet.html +++ b/dom/u2f/tests/test_appid_facet.html @@ -33,6 +33,7 @@ SimpleTest.waitForExplicitFinish(); window.addEventListener("message", handleEventMessage); SpecialPowers.pushPrefEnv({"set": [["security.webauth.u2f", true], ["security.webauth.webauthn_enable_softtoken", true], + ["security.webauth.webauthn_enable_android_fido2", false], ["security.webauth.webauthn_enable_usbtoken", false]]}, function(){ document.getElementById('testing_frame').src = "https://example.com/tests/dom/u2f/tests/frame_appid_facet.html"; diff --git a/dom/u2f/tests/test_appid_facet_insecure.html b/dom/u2f/tests/test_appid_facet_insecure.html index 1c0fddd2ba93..6c35e7501548 100644 --- a/dom/u2f/tests/test_appid_facet_insecure.html +++ b/dom/u2f/tests/test_appid_facet_insecure.html @@ -33,6 +33,7 @@ SimpleTest.waitForExplicitFinish(); window.addEventListener("message", handleEventMessage); SpecialPowers.pushPrefEnv({"set": [["security.webauth.u2f", true], ["security.webauth.webauthn_enable_softtoken", true], + ["security.webauth.webauthn_enable_android_fido2", false], ["security.webauth.webauthn_enable_usbtoken", false]]}, function(){ document.getElementById('testing_frame').src = "http://test2.example.com/tests/dom/u2f/tests/frame_appid_facet_insecure.html"; diff --git a/dom/u2f/tests/test_appid_facet_subdomain.html b/dom/u2f/tests/test_appid_facet_subdomain.html index d94007b688e1..6c9f019d4721 100644 --- a/dom/u2f/tests/test_appid_facet_subdomain.html +++ b/dom/u2f/tests/test_appid_facet_subdomain.html @@ -33,6 +33,7 @@ SimpleTest.waitForExplicitFinish(); window.addEventListener("message", handleEventMessage); SpecialPowers.pushPrefEnv({"set": [["security.webauth.u2f", true], ["security.webauth.webauthn_enable_softtoken", true], + ["security.webauth.webauthn_enable_android_fido2", false], ["security.webauth.webauthn_enable_usbtoken", false]]}, function(){ document.getElementById('testing_frame').src = "https://test1.example.com/tests/dom/u2f/tests/frame_appid_facet_subdomain.html"; diff --git a/dom/u2f/tests/test_multiple_keys.html b/dom/u2f/tests/test_multiple_keys.html index 97f048cb3e5d..a8ff58a7296d 100644 --- a/dom/u2f/tests/test_multiple_keys.html +++ b/dom/u2f/tests/test_multiple_keys.html @@ -33,6 +33,7 @@ SimpleTest.waitForExplicitFinish(); window.addEventListener("message", handleEventMessage); SpecialPowers.pushPrefEnv({"set": [["security.webauth.u2f", true], ["security.webauth.webauthn_enable_softtoken", true], + ["security.webauth.webauthn_enable_android_fido2", false], ["security.webauth.webauthn_enable_usbtoken", false]]}, function(){ document.getElementById('testing_frame').src = "https://test2.example.com/tests/dom/u2f/tests/frame_multiple_keys.html"; diff --git a/dom/u2f/tests/test_no_token.html b/dom/u2f/tests/test_no_token.html index ff7bd20694f8..6b50cbf276ef 100644 --- a/dom/u2f/tests/test_no_token.html +++ b/dom/u2f/tests/test_no_token.html @@ -31,6 +31,7 @@ SimpleTest.waitForExplicitFinish(); SpecialPowers.pushPrefEnv({"set": [["security.webauth.u2f", true], ["security.webauth.webauthn_enable_softtoken", false], + ["security.webauth.webauthn_enable_android_fido2", false], ["security.webauth.webauthn_enable_usbtoken", false]]}, function() { // listen for messages from the test harness diff --git a/dom/u2f/tests/test_override_request.html b/dom/u2f/tests/test_override_request.html index efd71bf53ebb..76ee3b0e43f2 100644 --- a/dom/u2f/tests/test_override_request.html +++ b/dom/u2f/tests/test_override_request.html @@ -23,6 +23,7 @@ SpecialPowers.pushPrefEnv({"set": [ ["security.webauth.u2f", true], ["security.webauth.webauthn_enable_softtoken", false], + ["security.webauth.webauthn_enable_android_fido2", false], ["security.webauth.webauthn_enable_usbtoken", true], ]}, () => { addEventListener("message", handleEventMessage); diff --git a/dom/u2f/tests/test_register.html b/dom/u2f/tests/test_register.html index da2b39f4c298..14ffcbaf9d3a 100644 --- a/dom/u2f/tests/test_register.html +++ b/dom/u2f/tests/test_register.html @@ -31,6 +31,7 @@ SimpleTest.waitForExplicitFinish(); SpecialPowers.pushPrefEnv({"set": [["security.webauth.u2f", true], ["security.webauth.webauthn_enable_softtoken", true], + ["security.webauth.webauthn_enable_android_fido2", false], ["security.webauth.webauthn_enable_usbtoken", false]]}, function() { // listen for messages from the test harness diff --git a/dom/u2f/tests/test_register_sign.html b/dom/u2f/tests/test_register_sign.html index ccb8dfb057d9..115007ec228d 100644 --- a/dom/u2f/tests/test_register_sign.html +++ b/dom/u2f/tests/test_register_sign.html @@ -27,6 +27,7 @@ SimpleTest.waitForExplicitFinish(); SpecialPowers.pushPrefEnv({"set": [["security.webauth.u2f", true], ["security.webauth.webauthn_enable_softtoken", true], + ["security.webauth.webauthn_enable_android_fido2", false], ["security.webauth.webauthn_enable_usbtoken", false]]}, function() { // listen for messages from the test harness diff --git a/dom/webauthn/tests/browser/browser_abort_visibility.js b/dom/webauthn/tests/browser/browser_abort_visibility.js index cf88f44fc6e7..7d4499cd726a 100644 --- a/dom/webauthn/tests/browser/browser_abort_visibility.js +++ b/dom/webauthn/tests/browser/browser_abort_visibility.js @@ -86,6 +86,7 @@ add_task(async function test_setup() { "set": [ ["security.webauth.webauthn", true], ["security.webauth.webauthn_enable_softtoken", false], + ["security.webauth.webauthn_enable_android_fido2", false], ["security.webauth.webauthn_enable_usbtoken", true] ] }); diff --git a/dom/webauthn/tests/browser/browser_fido_appid_extension.js b/dom/webauthn/tests/browser/browser_fido_appid_extension.js index 1f783f4b3b8b..ea0b76c7556d 100644 --- a/dom/webauthn/tests/browser/browser_fido_appid_extension.js +++ b/dom/webauthn/tests/browser/browser_fido_appid_extension.js @@ -93,6 +93,7 @@ function promiseWebAuthnSign(tab, key_handle, extensions = {}) { add_task(function test_setup() { Services.prefs.setBoolPref("security.webauth.u2f", true); Services.prefs.setBoolPref("security.webauth.webauthn", true); + Services.prefs.setBoolPref("security.webauth.webauthn_enable_android_fido2", false); Services.prefs.setBoolPref("security.webauth.webauthn_enable_softtoken", true); Services.prefs.setBoolPref("security.webauth.webauthn_enable_usbtoken", false); }); diff --git a/dom/webauthn/tests/browser/browser_webauthn_prompts.js b/dom/webauthn/tests/browser/browser_webauthn_prompts.js index 3856bf8a53ac..b1a3a6ea6798 100644 --- a/dom/webauthn/tests/browser/browser_webauthn_prompts.js +++ b/dom/webauthn/tests/browser/browser_webauthn_prompts.js @@ -99,6 +99,7 @@ add_task(async function test_setup_usbtoken() { ["security.webauth.u2f", false], ["security.webauth.webauthn", true], ["security.webauth.webauthn_enable_softtoken", false], + ["security.webauth.webauthn_enable_android_fido2", false], ["security.webauth.webauthn_enable_usbtoken", true] ] }); diff --git a/dom/webauthn/tests/browser/browser_webauthn_telemetry.js b/dom/webauthn/tests/browser/browser_webauthn_telemetry.js index 2ae6dfccb13c..fe1ec41d36ea 100644 --- a/dom/webauthn/tests/browser/browser_webauthn_telemetry.js +++ b/dom/webauthn/tests/browser/browser_webauthn_telemetry.js @@ -98,6 +98,7 @@ add_task(async function test_setup() { ["security.webauth.webauthn", true], ["security.webauth.webauthn_enable_softtoken", true], ["security.webauth.webauthn_enable_usbtoken", false], + ["security.webauth.webauthn_enable_android_fido2", false], ["security.webauth.webauthn_testing_allow_direct_attestation", true] ] }); diff --git a/dom/webauthn/tests/test_webauthn_abort_signal.html b/dom/webauthn/tests/test_webauthn_abort_signal.html index 078a9ca7b6b5..5dc42a13f0ad 100644 --- a/dom/webauthn/tests/test_webauthn_abort_signal.html +++ b/dom/webauthn/tests/test_webauthn_abort_signal.html @@ -28,6 +28,7 @@ ["security.webauth.webauthn", true], ["security.webauth.webauthn_enable_softtoken", false], ["security.webauth.webauthn_enable_usbtoken", true], + ["security.webauth.webauthn_enable_android_fido2", false], ]}); }); diff --git a/dom/webauthn/tests/test_webauthn_attestation_conveyance.html b/dom/webauthn/tests/test_webauthn_attestation_conveyance.html index 058d57c7cd63..bf934a0dfc93 100644 --- a/dom/webauthn/tests/test_webauthn_attestation_conveyance.html +++ b/dom/webauthn/tests/test_webauthn_attestation_conveyance.html @@ -62,6 +62,7 @@ ["security.webauth.webauthn", true], ["security.webauth.webauthn_enable_softtoken", true], ["security.webauth.webauthn_enable_usbtoken", false], + ["security.webauth.webauthn_enable_android_fido2", false], ["security.webauth.webauthn_testing_allow_direct_attestation", true], ]}); }); diff --git a/dom/webauthn/tests/test_webauthn_authenticator_selection.html b/dom/webauthn/tests/test_webauthn_authenticator_selection.html index b839541249ba..10ba6b643b64 100644 --- a/dom/webauthn/tests/test_webauthn_authenticator_selection.html +++ b/dom/webauthn/tests/test_webauthn_authenticator_selection.html @@ -37,6 +37,7 @@ ["security.webauth.webauthn", true], ["security.webauth.webauthn_enable_softtoken", true], ["security.webauth.webauthn_enable_usbtoken", false], + ["security.webauth.webauthn_enable_android_fido2", false], ]}); }); diff --git a/dom/webauthn/tests/test_webauthn_authenticator_transports.html b/dom/webauthn/tests/test_webauthn_authenticator_transports.html index a063415dc537..44f99673b34b 100644 --- a/dom/webauthn/tests/test_webauthn_authenticator_transports.html +++ b/dom/webauthn/tests/test_webauthn_authenticator_transports.html @@ -40,6 +40,7 @@ ["security.webauth.webauthn", true], ["security.webauth.webauthn_enable_softtoken", true], ["security.webauth.webauthn_enable_usbtoken", false], + ["security.webauth.webauthn_enable_android_fido2", false], ]}); }); diff --git a/dom/webauthn/tests/test_webauthn_get_assertion.html b/dom/webauthn/tests/test_webauthn_get_assertion.html index 82974a987b59..c49155fb6fe9 100644 --- a/dom/webauthn/tests/test_webauthn_get_assertion.html +++ b/dom/webauthn/tests/test_webauthn_get_assertion.html @@ -62,7 +62,8 @@ return SpecialPowers.pushPrefEnv({"set": [ ["security.webauth.webauthn", true], ["security.webauth.webauthn_enable_softtoken", true], - ["security.webauth.webauthn_enable_usbtoken", false] + ["security.webauth.webauthn_enable_usbtoken", false], + ["security.webauth.webauthn_enable_android_fido2", false], ]}); }); diff --git a/dom/webauthn/tests/test_webauthn_isexternalctap2securitykeysupported.html b/dom/webauthn/tests/test_webauthn_isexternalctap2securitykeysupported.html index 7fd406d2ab76..b22d44387560 100644 --- a/dom/webauthn/tests/test_webauthn_isexternalctap2securitykeysupported.html +++ b/dom/webauthn/tests/test_webauthn_isexternalctap2securitykeysupported.html @@ -23,7 +23,9 @@ SimpleTest.waitForExplicitFinish(); SpecialPowers.pushPrefEnv({"set": [["security.webauth.webauthn", true], ["security.webauth.webauthn_enable_softtoken", true], - ["security.webauth.webauthn_enable_usbtoken", false]]}, + ["security.webauth.webauthn_enable_usbtoken", false], + ["security.webauth.webauthn_enable_android_fido2", false], + ]}, function() { PublicKeyCredential.isExternalCTAP2SecurityKeySupported() .then(aResult => ok(true, `Should always return either true or false: ${aResult}`)) diff --git a/dom/webauthn/tests/test_webauthn_isplatformauthenticatoravailable.html b/dom/webauthn/tests/test_webauthn_isplatformauthenticatoravailable.html index b76aba4e0655..3fd9d70e1a67 100644 --- a/dom/webauthn/tests/test_webauthn_isplatformauthenticatoravailable.html +++ b/dom/webauthn/tests/test_webauthn_isplatformauthenticatoravailable.html @@ -23,7 +23,9 @@ SimpleTest.waitForExplicitFinish(); SpecialPowers.pushPrefEnv({"set": [["security.webauth.webauthn", true], ["security.webauth.webauthn_enable_softtoken", true], - ["security.webauth.webauthn_enable_usbtoken", false]]}, + ["security.webauth.webauthn_enable_usbtoken", false], + ["security.webauth.webauthn_enable_android_fido2", false], + ]}, async function() { // This test ensures that isUserVerifyingPlatformAuthenticatorAvailable() // is a callable method, but with the softtoken enabled, it's not useful to diff --git a/dom/webauthn/tests/test_webauthn_loopback.html b/dom/webauthn/tests/test_webauthn_loopback.html index 7cbfb2fa7a35..764dc54ef297 100644 --- a/dom/webauthn/tests/test_webauthn_loopback.html +++ b/dom/webauthn/tests/test_webauthn_loopback.html @@ -25,6 +25,7 @@ SimpleTest.waitForExplicitFinish(); SpecialPowers.pushPrefEnv({"set": [["security.webauth.webauthn", true], ["security.webauth.webauthn_enable_softtoken", true], ["security.webauth.webauthn_enable_usbtoken", false], + ["security.webauth.webauthn_enable_android_fido2", false], ["security.webauth.webauthn_testing_allow_direct_attestation", true]]}, function() { is(navigator.authentication, undefined, "navigator.authentication does not exist any longer"); diff --git a/dom/webauthn/tests/test_webauthn_make_credential.html b/dom/webauthn/tests/test_webauthn_make_credential.html index ecb5b08a11f2..3ddd688590a5 100644 --- a/dom/webauthn/tests/test_webauthn_make_credential.html +++ b/dom/webauthn/tests/test_webauthn_make_credential.html @@ -48,6 +48,7 @@ SpecialPowers.pushPrefEnv({"set": [["security.webauth.webauthn", true], ["security.webauth.webauthn_enable_softtoken", true], + ["security.webauth.webauthn_enable_android_fido2", false], ["security.webauth.webauthn_enable_usbtoken", false]]}, runTests); function runTests() { is(navigator.authentication, undefined, "navigator.authentication does not exist any longer"); diff --git a/dom/webauthn/tests/test_webauthn_no_token.html b/dom/webauthn/tests/test_webauthn_no_token.html index e0af8a80849c..75bd57d645b6 100644 --- a/dom/webauthn/tests/test_webauthn_no_token.html +++ b/dom/webauthn/tests/test_webauthn_no_token.html @@ -24,6 +24,7 @@ SimpleTest.waitForExplicitFinish(); // Turn off all tokens. This should result in "not allowed" failures SpecialPowers.pushPrefEnv({"set": [["security.webauth.webauthn", true], ["security.webauth.webauthn_enable_softtoken", false], + ["security.webauth.webauthn_enable_android_fido2", false], ["security.webauth.webauthn_enable_usbtoken", false]]}, function() { is(navigator.authentication, undefined, "navigator.authentication does not exist any longer"); diff --git a/dom/webauthn/tests/test_webauthn_override_request.html b/dom/webauthn/tests/test_webauthn_override_request.html index b4021c9dd577..4c65af4226d3 100644 --- a/dom/webauthn/tests/test_webauthn_override_request.html +++ b/dom/webauthn/tests/test_webauthn_override_request.html @@ -22,6 +22,7 @@ return SpecialPowers.pushPrefEnv({"set": [ ["security.webauth.webauthn", true], ["security.webauth.webauthn_enable_softtoken", false], + ["security.webauth.webauthn_enable_android_fido2", false], ["security.webauth.webauthn_enable_usbtoken", true], ]}); }); diff --git a/dom/webauthn/tests/test_webauthn_sameorigin.html b/dom/webauthn/tests/test_webauthn_sameorigin.html index bebf26fac668..00c6e3edb4ae 100644 --- a/dom/webauthn/tests/test_webauthn_sameorigin.html +++ b/dom/webauthn/tests/test_webauthn_sameorigin.html @@ -299,6 +299,7 @@ }; SpecialPowers.pushPrefEnv({"set": [["security.webauth.webauthn", true], ["security.webauth.webauthn_enable_softtoken", true], + ["security.webauth.webauthn_enable_android_fido2", false], ["security.webauth.webauthn_enable_usbtoken", false]]}, runTests); diff --git a/dom/webauthn/tests/test_webauthn_store_credential.html b/dom/webauthn/tests/test_webauthn_store_credential.html index 94d9cf7330ca..c23f1929da4c 100644 --- a/dom/webauthn/tests/test_webauthn_store_credential.html +++ b/dom/webauthn/tests/test_webauthn_store_credential.html @@ -26,6 +26,7 @@ add_task(async function(){ await SpecialPowers.pushPrefEnv({"set": [["security.webauth.webauthn", true], ["security.webauth.webauthn_enable_softtoken", true], + ["security.webauth.webauthn_enable_android_fido2", false], ["security.webauth.webauthn_enable_usbtoken", false]]}); isnot(navigator.credentials, undefined, "Credential Management API endpoint must exist"); diff --git a/gfx/skia/skia/src/ports/SkScalerContext_win_dw.cpp b/gfx/skia/skia/src/ports/SkScalerContext_win_dw.cpp index 96293436d7b1..8515a9cb63cf 100644 --- a/gfx/skia/skia/src/ports/SkScalerContext_win_dw.cpp +++ b/gfx/skia/skia/src/ports/SkScalerContext_win_dw.cpp @@ -42,17 +42,46 @@ /* Note: * In versions 8 and 8.1 of Windows, some calls in DWrite are not thread safe. * The DWriteFactoryMutex protects the calls that are problematic. + * + * On DWrite 3 or above, which is only available on Windows 10, we don't enable + * the locking to avoid thread contention. */ static SkSharedMutex DWriteFactoryMutex; -typedef SkAutoSharedMutexShared Shared; +struct MaybeExclusive { + MaybeExclusive(SkScalerContext_DW* ctx) : fEnabled(!ctx->isDWrite3()) { + if (fEnabled) { + DWriteFactoryMutex.acquire(); + } + } + ~MaybeExclusive() { + if (fEnabled) { + DWriteFactoryMutex.release(); + } + } + bool fEnabled; +}; + +struct MaybeShared { + MaybeShared(SkScalerContext_DW* ctx) : fEnabled(!ctx->isDWrite3()) { + if (fEnabled) { + DWriteFactoryMutex.acquireShared(); + } + } + ~MaybeShared() { + if (fEnabled) { + DWriteFactoryMutex.releaseShared(); + } + } + bool fEnabled; +}; static bool isLCD(const SkScalerContextRec& rec) { return SkMask::kLCD16_Format == rec.fMaskFormat; } -static bool is_hinted(DWriteFontTypeface* typeface) { - SkAutoExclusive l(DWriteFactoryMutex); +static bool is_hinted(SkScalerContext_DW* ctx, DWriteFontTypeface* typeface) { + MaybeExclusive l(ctx); AutoTDWriteTable maxp(typeface->fDWriteFontFace.get()); if (!maxp.fExists) { return false; @@ -122,8 +151,8 @@ static bool is_gridfit_only(GaspRange::Behavior flags) { return flags.raw.value == GaspRange::Behavior::Raw::GridfitMask; } -static bool has_bitmap_strike(DWriteFontTypeface* typeface, GaspRange range) { - SkAutoExclusive l(DWriteFactoryMutex); +static bool has_bitmap_strike(SkScalerContext_DW* ctx, DWriteFontTypeface* typeface, GaspRange range) { + MaybeExclusive l(ctx); { AutoTDWriteTable eblc(typeface->fDWriteFontFace.get()); if (!eblc.fExists) { @@ -268,7 +297,7 @@ SkScalerContext_DW::SkScalerContext_DW(sk_sp typefaceRef, range = GaspRange(bitmapPPEM, bitmapPPEM, 0, GaspRange::Behavior()); } } - treatLikeBitmap = has_bitmap_strike(typeface, range); + treatLikeBitmap = has_bitmap_strike(this, typeface, range); axisAlignedBitmap = is_axis_aligned(fRec); } @@ -304,7 +333,7 @@ SkScalerContext_DW::SkScalerContext_DW(sk_sp typefaceRef, // If the font has a gasp table version 1, use it to determine symmetric rendering. } else if ((get_gasp_range(typeface, SkScalarRoundToInt(gdiTextSize), &range) && range.fVersion >= 1) || - realTextSize > SkIntToScalar(20) || !is_hinted(typeface)) { + realTextSize > SkIntToScalar(20) || !is_hinted(this, typeface)) { fTextSizeRender = realTextSize; fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1; fTextSizeMeasure = realTextSize; @@ -397,7 +426,7 @@ bool SkScalerContext_DW::generateAdvance(SkGlyph* glyph) { if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode || DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode) { - SkAutoExclusive l(DWriteFactoryMutex); + MaybeExclusive l(this); HRBM(this->getDWriteTypeface()->fDWriteFontFace->GetGdiCompatibleGlyphMetrics( fTextSizeMeasure, 1.0f, // pixelsPerDip @@ -409,14 +438,14 @@ bool SkScalerContext_DW::generateAdvance(SkGlyph* glyph) { &gm), "Could not get gdi compatible glyph metrics."); } else { - SkAutoExclusive l(DWriteFactoryMutex); + MaybeExclusive l(this); HRBM(this->getDWriteTypeface()->fDWriteFontFace->GetDesignGlyphMetrics(&glyphId, 1, &gm), "Could not get design metrics."); } DWRITE_FONT_METRICS dwfm; { - Shared l(DWriteFactoryMutex); + MaybeShared l(this); this->getDWriteTypeface()->fDWriteFontFace->GetMetrics(&dwfm); } SkScalar advanceX = fTextSizeMeasure * gm.advanceWidth / dwfm.designUnitsPerEm; @@ -465,7 +494,7 @@ HRESULT SkScalerContext_DW::getBoundingBox(SkGlyph* glyph, SkTScopedComPtr glyphRunAnalysis; { - SkAutoExclusive l(DWriteFactoryMutex); + MaybeExclusive l(this); // IDWriteFactory2::CreateGlyphRunAnalysis is very bad at aliased glyphs. if (this->getDWriteTypeface()->fFactory2 && (fGridFitMode == DWRITE_GRID_FIT_MODE_DISABLED || @@ -495,7 +524,7 @@ HRESULT SkScalerContext_DW::getBoundingBox(SkGlyph* glyph, } } { - Shared l(DWriteFactoryMutex); + MaybeShared l(this); HRM(glyphRunAnalysis->GetAlphaTextureBounds(textureType, bbox), "Could not get texture bounds."); } @@ -588,7 +617,7 @@ void SkScalerContext_DW::generateColorMetrics(SkGlyph* glyph) { HRVM(SkDWriteGeometrySink::Create(&path, &geometryToPath), "Could not create geometry to path converter."); { - SkAutoExclusive l(DWriteFactoryMutex); + MaybeExclusive l(this); HRVM(colorGlyph->glyphRun.fontFace->GetGlyphRunOutline( colorGlyph->glyphRun.fontEmSize, colorGlyph->glyphRun.glyphIndices, @@ -947,7 +976,7 @@ const void* SkScalerContext_DW::drawDWMask(const SkGlyph& glyph, { SkTScopedComPtr glyphRunAnalysis; { - SkAutoExclusive l(DWriteFactoryMutex); + MaybeExclusive l(this); // IDWriteFactory2::CreateGlyphRunAnalysis is very bad at aliased glyphs. if (this->getDWriteTypeface()->fFactory2 && (fGridFitMode == DWRITE_GRID_FIT_MODE_DISABLED || @@ -983,7 +1012,7 @@ const void* SkScalerContext_DW::drawDWMask(const SkGlyph& glyph, bbox.right = glyph.fLeft + glyph.fWidth; bbox.bottom = glyph.fTop + glyph.fHeight; { - Shared l(DWriteFactoryMutex); + MaybeShared l(this); HRNM(glyphRunAnalysis->CreateAlphaTexture(textureType, &bbox, fBits.begin(), @@ -1047,7 +1076,7 @@ void SkScalerContext_DW::generateColorGlyphImage(const SkGlyph& glyph) { HRVM(SkDWriteGeometrySink::Create(&path, &geometryToPath), "Could not create geometry to path converter."); { - SkAutoExclusive l(DWriteFactoryMutex); + MaybeExclusive l(this); HRVM(colorGlyph->glyphRun.fontFace->GetGlyphRunOutline( colorGlyph->glyphRun.fontEmSize, colorGlyph->glyphRun.glyphIndices, @@ -1186,7 +1215,7 @@ bool SkScalerContext_DW::generatePath(SkGlyphID glyph, SkPath* path) { "Could not create geometry to path converter."); UINT16 glyphId = SkTo(glyph); { - SkAutoExclusive l(DWriteFactoryMutex); + MaybeExclusive l(this); //TODO: convert to<->from DIUs? This would make a difference if hinting. //It may not be needed, it appears that DirectWrite only hints at em size. HRBM(this->getDWriteTypeface()->fDWriteFontFace->GetGlyphRunOutline( diff --git a/gfx/skia/skia/src/ports/SkScalerContext_win_dw.h b/gfx/skia/skia/src/ports/SkScalerContext_win_dw.h index a462d98de009..30d4bf3232d6 100644 --- a/gfx/skia/skia/src/ports/SkScalerContext_win_dw.h +++ b/gfx/skia/skia/src/ports/SkScalerContext_win_dw.h @@ -26,6 +26,10 @@ public: const SkDescriptor*); ~SkScalerContext_DW() override; + // The IDWriteFontFace4 interface is only available in DWrite 3, + // so checking if it was found is sufficient to detect DWrite 3. + bool isDWrite3() { return bool(getDWriteTypeface()->fDWriteFontFace4); } + protected: unsigned generateGlyphCount() override; uint16_t generateCharToGlyph(SkUnichar uni) override; diff --git a/gfx/thebes/gfxPrefs.h b/gfx/thebes/gfxPrefs.h index 7196aedd646b..a536e4ba2887 100644 --- a/gfx/thebes/gfxPrefs.h +++ b/gfx/thebes/gfxPrefs.h @@ -724,7 +724,7 @@ class gfxPrefs final { DECL_GFX_PREF(Once, "layout.paint_rects_separately", LayoutPaintRectsSeparately, bool, true); // This and code dependent on it should be removed once containerless scrolling looks stable. - DECL_OVERRIDE_PREF(Live, "layout.scroll.root-frame-containers", LayoutUseContainersForRootFrames, !OverrideBase_WebRender()); + DECL_GFX_PREF(Live, "layout.scroll.root-frame-containers", LayoutUseContainersForRootFrames, bool, false); // This pref is to be set by test code only. DECL_GFX_PREF(Live, "layout.scrollbars.always-layerize-track", AlwaysLayerizeScrollbarTrackTestOnly, bool, false); DECL_GFX_PREF(Live, "layout.smaller-painted-layers", LayoutSmallerPaintedLayers, bool, false); diff --git a/gfx/webrender_bindings/RenderCompositorANGLE.h b/gfx/webrender_bindings/RenderCompositorANGLE.h index f66acbd3c67b..86fb77b98ce0 100644 --- a/gfx/webrender_bindings/RenderCompositorANGLE.h +++ b/gfx/webrender_bindings/RenderCompositorANGLE.h @@ -50,7 +50,7 @@ class RenderCompositorANGLE : public RenderCompositor { bool UseDComp() const override { return !!mCompositionDevice; } - bool UseTripleBuffering() const { return mUseTripleBuffering; } + bool UseTripleBuffering() const override { return mUseTripleBuffering; } LayoutDeviceIntSize GetBufferSize() override; diff --git a/layout/reftests/svg/geometry-properties-in-css-ref.html b/layout/reftests/svg/geometry-properties-in-css-ref.html new file mode 100644 index 000000000000..7998b7b86f41 --- /dev/null +++ b/layout/reftests/svg/geometry-properties-in-css-ref.html @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/layout/reftests/svg/geometry-properties-in-css.html b/layout/reftests/svg/geometry-properties-in-css.html new file mode 100644 index 000000000000..4204fc41ae9b --- /dev/null +++ b/layout/reftests/svg/geometry-properties-in-css.html @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/layout/reftests/svg/reftest.list b/layout/reftests/svg/reftest.list index d76646bfe9aa..40b10acd8608 100644 --- a/layout/reftests/svg/reftest.list +++ b/layout/reftests/svg/reftest.list @@ -244,6 +244,7 @@ fuzzy-if(Android,0-18,0-600) == foreignObject-fixedpos-01.html foreignObject-dyn == g-transform-01.svg pass.svg == getElementById-a-element-01.svg pass.svg +== geometry-properties-in-css.html geometry-properties-in-css-ref.html fuzzy-if(Android,0-9,0-980) fuzzy-if(skiaContent,0-3,0-32000) == gradient-live-01a.svg gradient-live-01-ref.svg fuzzy-if(Android,0-9,0-980) fuzzy-if(skiaContent,0-3,0-32000) == gradient-live-01b.svg gradient-live-01-ref.svg diff --git a/layout/style/nsDOMCSSAttrDeclaration.cpp b/layout/style/nsDOMCSSAttrDeclaration.cpp index 8da15e47db47..3ed24764e1c3 100644 --- a/layout/style/nsDOMCSSAttrDeclaration.cpp +++ b/layout/style/nsDOMCSSAttrDeclaration.cpp @@ -10,10 +10,12 @@ #include "mozilla/dom/Document.h" #include "mozilla/dom/Element.h" +#include "mozilla/dom/SVGElement.h" #include "mozilla/dom/MutationEventBinding.h" #include "mozilla/DeclarationBlock.h" #include "mozilla/InternalMutationEvent.h" #include "mozilla/SMILCSSValueType.h" +#include "mozilla/SMILValue.h" #include "mozAutoDocUpdate.h" #include "nsIURI.h" #include "nsNodeUtils.h" @@ -133,9 +135,10 @@ nsDOMCSSAttributeDeclaration::GetParsingEnvironment( }; } -nsresult nsDOMCSSAttributeDeclaration::SetSMILValue( - const nsCSSPropertyID aPropID, const SMILValue& aValue) { +template +nsresult nsDOMCSSAttributeDeclaration::SetSMILValueHelper(SetterFunc aFunc) { MOZ_ASSERT(mIsSMILOverride); + // No need to do the ActiveLayerTracker / ScrollLinkedEffectDetector bits, // since we're in a SMIL animation anyway, no need to try to detect we're a // scripted animation. @@ -147,7 +150,9 @@ nsresult nsDOMCSSAttributeDeclaration::SetSMILValue( } mozAutoDocUpdate autoUpdate(DocToUpdate(), true); RefPtr decl = olddecl->EnsureMutable(); - bool changed = SMILCSSValueType::SetPropertyValues(aValue, *decl); + + bool changed = aFunc(*decl); + if (changed) { // We can pass nullptr as the latter param, since this is // mIsSMILOverride == true case. @@ -156,6 +161,23 @@ nsresult nsDOMCSSAttributeDeclaration::SetSMILValue( return NS_OK; } +nsresult nsDOMCSSAttributeDeclaration::SetSMILValue( + const nsCSSPropertyID /*aPropID*/, const SMILValue& aValue) { + MOZ_ASSERT(aValue.mType == &SMILCSSValueType::sSingleton, + "We should only try setting a CSS value type"); + return SetSMILValueHelper([&aValue](DeclarationBlock& aDecl) { + return SMILCSSValueType::SetPropertyValues(aValue, aDecl); + }); +} + +nsresult nsDOMCSSAttributeDeclaration::SetSMILValue( + const nsCSSPropertyID aPropID, const SVGAnimatedLength& aLength) { + return SetSMILValueHelper([aPropID, &aLength](DeclarationBlock& aDecl) { + return SVGElement::UpdateDeclarationBlockFromLength( + aDecl, aPropID, aLength, SVGElement::ValToUse::Anim); + }); +} + nsresult nsDOMCSSAttributeDeclaration::SetPropertyValue( const nsCSSPropertyID aPropID, const nsAString& aValue, nsIPrincipal* aSubjectPrincipal) { diff --git a/layout/style/nsDOMCSSAttrDeclaration.h b/layout/style/nsDOMCSSAttrDeclaration.h index 53d2451bce3e..3790df92e56b 100644 --- a/layout/style/nsDOMCSSAttrDeclaration.h +++ b/layout/style/nsDOMCSSAttrDeclaration.h @@ -18,6 +18,7 @@ struct RawServoUnlockedDeclarationBlock; namespace mozilla { class SMILValue; +class SVGAnimatedLength; namespace dom { class DomGroup; @@ -29,6 +30,7 @@ class nsDOMCSSAttributeDeclaration final : public nsDOMCSSDeclaration { public: typedef mozilla::dom::Element Element; typedef mozilla::SMILValue SMILValue; + typedef mozilla::SVGAnimatedLength SVGAnimatedLength; nsDOMCSSAttributeDeclaration(Element* aContent, bool aIsSMILOverride); NS_DECL_CYCLE_COLLECTING_ISUPPORTS @@ -45,7 +47,9 @@ class nsDOMCSSAttributeDeclaration final : public nsDOMCSSDeclaration { nsINode* GetParentObject() override { return mElement; } - nsresult SetSMILValue(const nsCSSPropertyID aPropID, const SMILValue&); + nsresult SetSMILValue(const nsCSSPropertyID aPropID, const SMILValue& aValue); + nsresult SetSMILValue(const nsCSSPropertyID aPropID, + const SVGAnimatedLength& aLength); nsresult SetPropertyValue(const nsCSSPropertyID aPropID, const nsAString& aValue, @@ -79,6 +83,10 @@ class nsDOMCSSAttributeDeclaration final : public nsDOMCSSDeclaration { * than the inline style rule). */ const bool mIsSMILOverride; + + private: + template + nsresult SetSMILValueHelper(SetterFunc aFunc); }; #endif /* nsDOMCSSAttributeDeclaration_h */ diff --git a/layout/style/nsStyleStruct.cpp b/layout/style/nsStyleStruct.cpp index b03bdf5030ff..160307afaacc 100644 --- a/layout/style/nsStyleStruct.cpp +++ b/layout/style/nsStyleStruct.cpp @@ -1069,7 +1069,14 @@ void nsStyleFilter::SetDropShadow(nsCSSShadowArray* aDropShadow) { // nsStyleSVGReset // nsStyleSVGReset::nsStyleSVGReset(const Document& aDocument) - : mMask(nsStyleImageLayers::LayerType::Mask), + : mX(LengthPercentage::Zero()), + mY(LengthPercentage::Zero()), + mCx(LengthPercentage::Zero()), + mCy(LengthPercentage::Zero()), + mRx(NonNegativeLengthPercentageOrAuto::Auto()), + mRy(NonNegativeLengthPercentageOrAuto::Auto()), + mR(NonNegativeLengthPercentage::Zero()), + mMask(nsStyleImageLayers::LayerType::Mask), mStopColor(StyleColor::Black()), mFloodColor(StyleColor::Black()), mLightingColor(StyleColor::White()), @@ -1084,7 +1091,14 @@ nsStyleSVGReset::nsStyleSVGReset(const Document& aDocument) nsStyleSVGReset::~nsStyleSVGReset() { MOZ_COUNT_DTOR(nsStyleSVGReset); } nsStyleSVGReset::nsStyleSVGReset(const nsStyleSVGReset& aSource) - : mMask(aSource.mMask), + : mX(aSource.mX), + mY(aSource.mY), + mCx(aSource.mCx), + mCy(aSource.mCy), + mRx(aSource.mRx), + mRy(aSource.mRy), + mR(aSource.mR), + mMask(aSource.mMask), mClipPath(aSource.mClipPath), mStopColor(aSource.mStopColor), mFloodColor(aSource.mFloodColor), @@ -1136,6 +1150,12 @@ nsChangeHint nsStyleSVGReset::CalcDifference( const nsStyleSVGReset& aNewData) const { nsChangeHint hint = nsChangeHint(0); + if (mX != aNewData.mX || mY != aNewData.mY || mCx != aNewData.mCx || + mCy != aNewData.mCy || mR != aNewData.mR || mRx != aNewData.mRx || + mRy != aNewData.mRy) { + hint |= nsChangeHint_InvalidateRenderingObservers | nsChangeHint_NeedReflow; + } + if (mClipPath != aNewData.mClipPath) { hint |= nsChangeHint_UpdateEffects | nsChangeHint_RepaintFrame; } diff --git a/layout/style/nsStyleStruct.h b/layout/style/nsStyleStruct.h index 8d8486d7b6b5..17e33b5280d2 100644 --- a/layout/style/nsStyleStruct.h +++ b/layout/style/nsStyleStruct.h @@ -2859,6 +2859,15 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleSVGReset { return mVectorEffect == NS_STYLE_VECTOR_EFFECT_NON_SCALING_STROKE; } + // geometry properties + mozilla::LengthPercentage mX; + mozilla::LengthPercentage mY; + mozilla::LengthPercentage mCx; + mozilla::LengthPercentage mCy; + mozilla::NonNegativeLengthPercentageOrAuto mRx; + mozilla::NonNegativeLengthPercentageOrAuto mRy; + mozilla::NonNegativeLengthPercentage mR; + nsStyleImageLayers mMask; mozilla::StyleShapeSource mClipPath; mozilla::StyleColor mStopColor; diff --git a/layout/style/test/property_database.js b/layout/style/test/property_database.js index 8e4ada7ab803..e75199f53494 100644 --- a/layout/style/test/property_database.js +++ b/layout/style/test/property_database.js @@ -5632,6 +5632,62 @@ var gCSSProperties = { other_values: [ "0", "0px", "-0em", "17px", "0.2em", "0.0002", "context-value" ], invalid_values: [ "-0.1px", "-3px" ] }, + "x": { + domProp: "x", + inherited: false, + type: CSS_TYPE_LONGHAND, + initial_values: [ "0px" ], + other_values: [ "-1em", "17px", "0.2em", "23.4%" ], + invalid_values: [ "auto", "context-value", "0.0002" ] + }, + "y": { + domProp: "y", + inherited: false, + type: CSS_TYPE_LONGHAND, + initial_values: [ "0px" ], + other_values: [ "-1em", "17px", "0.2em", "23.4%" ], + invalid_values: [ "auto", "context-value", "0.0002" ] + }, + "cx": { + domProp: "cx", + inherited: false, + type: CSS_TYPE_LONGHAND, + initial_values: [ "0px" ], + other_values: [ "-1em", "17px", "0.2em", "23.4%" ], + invalid_values: [ "auto", "context-value", "0.0002" ] + }, + "cy": { + domProp: "cy", + inherited: false, + type: CSS_TYPE_LONGHAND, + initial_values: [ "0px" ], + other_values: [ "-1em", "17px", "0.2em", "23.4%" ], + invalid_values: [ "auto", "context-value", "0.0002" ] + }, + "r": { + domProp: "r", + inherited: false, + type: CSS_TYPE_LONGHAND, + initial_values: [ "0px" ], + other_values: [ "17px", "0.2em", "23.4%" ], + invalid_values: [ "auto", "-1", "-1.5px", "0.0002" ] + }, + "rx": { + domProp: "rx", + inherited: false, + type: CSS_TYPE_LONGHAND, + initial_values: [ "auto" ], + other_values: [ "17px", "0.2em", "23.4%" ], + invalid_values: [ "hello", "-12px", "0.0002" ] + }, + "ry": { + domProp: "ry", + inherited: false, + type: CSS_TYPE_LONGHAND, + initial_values: [ "auto" ], + other_values: [ "17px", "0.2em", "23.4%" ], + invalid_values: [ "hello", "-1.3px", "0.0002" ] + }, "text-anchor": { domProp: "textAnchor", inherited: true, diff --git a/layout/style/test/test_transitions_per_property.html b/layout/style/test/test_transitions_per_property.html index 09ecbbb687b9..faf62f7079ff 100644 --- a/layout/style/test/test_transitions_per_property.html +++ b/layout/style/test/test_transitions_per_property.html @@ -80,6 +80,10 @@ var supported_properties = { test_length_clamped ], "column-width": [ test_length_transition, test_length_clamped ], + "cx": [ test_length_transition, test_percent_transition, + test_length_unclamped, test_percent_unclamped ], + "cy": [ test_length_transition, test_percent_transition, + test_length_unclamped, test_percent_unclamped ], "-moz-image-region": [ test_rect_transition ], "-moz-outline-radius-bottomleft": [ test_radius_transition ], "-moz-outline-radius-bottomright": [ test_radius_transition ], @@ -244,6 +248,12 @@ var supported_properties = { "right": [ test_length_transition, test_percent_transition, test_length_percent_calc_transition, test_length_unclamped, test_percent_unclamped ], + "r": [ test_length_transition, test_percent_transition, + test_length_clamped, test_percent_clamped ], + "rx": [ test_length_transition, test_percent_transition, + test_length_clamped, test_percent_clamped ], + "ry": [ test_length_transition, test_percent_transition, + test_length_clamped, test_percent_clamped ], "shape-image-threshold": [ test_float_zeroToOne_transition, // shape-image-threshold (like opacity) is // clamped in computed style @@ -297,6 +307,10 @@ var supported_properties = { test_length_percent_calc_transition, test_length_clamped, test_percent_clamped ], "word-spacing": [ test_length_transition, test_length_unclamped ], + "x": [ test_length_transition, test_percent_transition, + test_length_unclamped, test_percent_unclamped ], + "y": [ test_length_transition, test_percent_transition, + test_length_unclamped, test_percent_unclamped ], "z-index": [ test_integer_transition, test_pos_integer_or_auto_transition ], "-webkit-line-clamp": [ test_pos_integer_or_none_transition ], "-webkit-text-fill-color": [ test_color_transition, diff --git a/layout/svg/SVGGeometryFrame.cpp b/layout/svg/SVGGeometryFrame.cpp index 584a8739f9f0..faad162d106d 100644 --- a/layout/svg/SVGGeometryFrame.cpp +++ b/layout/svg/SVGGeometryFrame.cpp @@ -197,6 +197,10 @@ void SVGGeometryFrame::DidSetComputedStyle(ComputedStyle* aOldComputedStyle) { } } } + + if (element->IsGeometryChangedViaCSS(*Style(), *aOldComputedStyle)) { + element->ClearAnyCachedPath(); + } } } diff --git a/layout/svg/nsSVGForeignObjectFrame.cpp b/layout/svg/nsSVGForeignObjectFrame.cpp index 7e3822b3bb4d..c4b2b138828b 100644 --- a/layout/svg/nsSVGForeignObjectFrame.cpp +++ b/layout/svg/nsSVGForeignObjectFrame.cpp @@ -19,6 +19,7 @@ #include "nsLayoutUtils.h" #include "nsRegion.h" #include "nsSVGContainerFrame.h" +#include "SVGGeometryProperty.h" #include "SVGObserverUtils.h" #include "nsSVGIntegrationUtils.h" #include "nsSVGOuterSVGFrame.h" @@ -27,6 +28,7 @@ using namespace mozilla; using namespace mozilla::dom; using namespace mozilla::image; +namespace SVGT = SVGGeometryProperty::Tags; //---------------------------------------------------------------------- // Implementation @@ -242,8 +244,9 @@ void nsSVGForeignObjectFrame::PaintSVG(gfxContext& aContext, if (StyleDisplay()->IsScrollableOverflow()) { float x, y, width, height; - static_cast(GetContent()) - ->GetAnimatedLengthValues(&x, &y, &width, &height, nullptr); + SVGGeometryProperty::ResolveAll( + static_cast(GetContent()), &x, &y, &width, &height); gfxRect clipRect = nsSVGUtils::GetClipRectForFrame(this, 0.0f, 0.0f, width, height); @@ -291,8 +294,8 @@ nsIFrame* nsSVGForeignObjectFrame::GetFrameForPoint(const gfxPoint& aPoint) { } float x, y, width, height; - static_cast(GetContent()) - ->GetAnimatedLengthValues(&x, &y, &width, &height, nullptr); + SVGGeometryProperty::ResolveAll( + static_cast(GetContent()), &x, &y, &width, &height); if (!gfxRect(x, y, width, height).Contains(aPoint) || !nsSVGUtils::HitTestClip(this, aPoint)) { @@ -323,8 +326,8 @@ void nsSVGForeignObjectFrame::ReflowSVG() { // correct dimensions: float x, y, w, h; - static_cast(GetContent()) - ->GetAnimatedLengthValues(&x, &y, &w, &h, nullptr); + SVGGeometryProperty::ResolveAll( + static_cast(GetContent()), &x, &y, &w, &h); // If mRect's width or height are negative, reflow blows up! We must clamp! if (w < 0.0f) w = 0.0f; @@ -376,21 +379,17 @@ void nsSVGForeignObjectFrame::NotifySVGChanged(uint32_t aFlags) { bool needNewCanvasTM = false; if (aFlags & COORD_CONTEXT_CHANGED) { - SVGForeignObjectElement* fO = - static_cast(GetContent()); // Coordinate context changes affect mCanvasTM if we have a // percentage 'x' or 'y' - if (fO->mLengthAttributes[SVGForeignObjectElement::ATTR_X].IsPercentage() || - fO->mLengthAttributes[SVGForeignObjectElement::ATTR_Y].IsPercentage()) { + if (StyleSVGReset()->mX.HasPercent() || StyleSVGReset()->mY.HasPercent()) { needNewBounds = true; needNewCanvasTM = true; } + // Our coordinate context's width/height has changed. If we have a // percentage width/height our dimensions will change so we must reflow. - if (fO->mLengthAttributes[SVGForeignObjectElement::ATTR_WIDTH] - .IsPercentage() || - fO->mLengthAttributes[SVGForeignObjectElement::ATTR_HEIGHT] - .IsPercentage()) { + if (StylePosition()->mWidth.HasPercent() || + StylePosition()->mHeight.HasPercent()) { needNewBounds = true; needReflow = true; } @@ -443,7 +442,8 @@ SVGBBox nsSVGForeignObjectFrame::GetBBoxContribution( static_cast(GetContent()); float x, y, w, h; - content->GetAnimatedLengthValues(&x, &y, &w, &h, nullptr); + SVGGeometryProperty::ResolveAll( + content, &x, &y, &w, &h); if (w < 0.0f) w = 0.0f; if (h < 0.0f) h = 0.0f; diff --git a/layout/tools/reftest/remotereftest.py b/layout/tools/reftest/remotereftest.py index ee20f4eaa774..fed96888747f 100644 --- a/layout/tools/reftest/remotereftest.py +++ b/layout/tools/reftest/remotereftest.py @@ -432,7 +432,7 @@ def run_test_harness(parser, options): reftest.stopWebServer(options) if options.printDeviceInfo and not options.verify: - reftest.printDeviceInfo(printLogcat=True) + reftest.printDeviceInfo(printLogcat=(retVal != 0)) return retVal diff --git a/mobile/android/app/geckoview-prefs.js b/mobile/android/app/geckoview-prefs.js index dd41dcfec90f..610ccc035eec 100644 --- a/mobile/android/app/geckoview-prefs.js +++ b/mobile/android/app/geckoview-prefs.js @@ -36,7 +36,7 @@ pref("dom.storageManager.enabled", true); pref("dom.visualviewport.enabled", true); // Use containerless scrolling. -pref("layout.scroll.root-frame-containers", 0); +pref("layout.scroll.root-frame-containers", false); // Inherit locale from the OS, used for multi-locale builds pref("intl.locale.requested", ""); diff --git a/mobile/android/app/mobile.js b/mobile/android/app/mobile.js index 7739b60d8596..7690555458f4 100644 --- a/mobile/android/app/mobile.js +++ b/mobile/android/app/mobile.js @@ -542,7 +542,7 @@ pref("layers.low-precision-opacity", "1.0"); pref("layers.max-active", 20); // Use containerless scrolling on Fennec. -pref("layout.scroll.root-frame-containers", 0); +pref("layout.scroll.root-frame-containers", false); pref("notification.feature.enabled", true); pref("dom.webnotifications.enabled", true); diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/ActivityResultHandler.java b/mobile/android/base/java/org/mozilla/gecko/util/ActivityResultHandler.java similarity index 100% rename from mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/ActivityResultHandler.java rename to mobile/android/base/java/org/mozilla/gecko/util/ActivityResultHandler.java diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/ActivityResultHandlerMap.java b/mobile/android/base/java/org/mozilla/gecko/util/ActivityResultHandlerMap.java similarity index 100% rename from mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/ActivityResultHandlerMap.java rename to mobile/android/base/java/org/mozilla/gecko/util/ActivityResultHandlerMap.java diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/InputOptionsUtils.java b/mobile/android/base/java/org/mozilla/gecko/util/InputOptionsUtils.java similarity index 100% rename from mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/InputOptionsUtils.java rename to mobile/android/base/java/org/mozilla/gecko/util/InputOptionsUtils.java diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/JSONUtils.java b/mobile/android/base/java/org/mozilla/gecko/util/JSONUtils.java similarity index 100% rename from mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/JSONUtils.java rename to mobile/android/base/java/org/mozilla/gecko/util/JSONUtils.java diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/MapUtils.java b/mobile/android/base/java/org/mozilla/gecko/util/MapUtils.java similarity index 100% rename from mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/MapUtils.java rename to mobile/android/base/java/org/mozilla/gecko/util/MapUtils.java diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/MenuUtils.java b/mobile/android/base/java/org/mozilla/gecko/util/MenuUtils.java similarity index 100% rename from mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/MenuUtils.java rename to mobile/android/base/java/org/mozilla/gecko/util/MenuUtils.java diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/PrefUtils.java b/mobile/android/base/java/org/mozilla/gecko/util/PrefUtils.java similarity index 100% rename from mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/PrefUtils.java rename to mobile/android/base/java/org/mozilla/gecko/util/PrefUtils.java diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/WindowUtils.java b/mobile/android/base/java/org/mozilla/gecko/util/WindowUtils.java similarity index 100% rename from mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/WindowUtils.java rename to mobile/android/base/java/org/mozilla/gecko/util/WindowUtils.java diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/SpeechSynthesisService.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/SpeechSynthesisService.java index 9eae1fda68a6..57c8be31dd18 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/SpeechSynthesisService.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/SpeechSynthesisService.java @@ -20,13 +20,20 @@ import java.util.HashSet; import java.util.Locale; import java.util.Set; import java.util.UUID; +import java.util.concurrent.atomic.AtomicBoolean; public class SpeechSynthesisService { private static final String LOGTAG = "GeckoSpeechSynthesis"; - private static TextToSpeech sTTS; + // Object type is used to make it easier to remove android.speech dependencies using Proguard. + private static Object sTTS; @WrapForJNI(calledFrom = "gecko") public static void initSynth() { + initSynthInternal(); + } + + // Extra internal method to make it easier to remove android.speech dependencies using Proguard. + private static void initSynthInternal() { if (sTTS != null) { return; } @@ -47,15 +54,20 @@ public class SpeechSynthesisService { }); } + private static TextToSpeech getTTS() { + return (TextToSpeech) sTTS; + } + private static void registerVoicesByLocale() { ThreadUtils.postToBackgroundThread(new Runnable() { @Override public void run() { + TextToSpeech tss = getTTS(); Locale defaultLocale = Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2 - ? sTTS.getDefaultLanguage() - : sTTS.getLanguage(); + ? tss.getDefaultLanguage() + : tss.getLanguage(); for (Locale locale : getAvailableLanguages()) { - final Set features = sTTS.getFeatures(locale); + final Set features = tss.getFeatures(locale); boolean isLocal = features != null && features.contains(TextToSpeech.Engine.KEY_FEATURE_EMBEDDED_SYNTHESIS); String localeStr = locale.toString(); registerVoice("moz-tts:android:" + localeStr, locale.getDisplayName(), localeStr.replace("_", "-"), !isLocal, defaultLocale == locale); @@ -69,11 +81,11 @@ public class SpeechSynthesisService { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { // While this method was introduced in 21, it seems that it // has not been implemented in the speech service side until 23. - return sTTS.getAvailableLanguages(); + return getTTS().getAvailableLanguages(); } Set locales = new HashSet(); for (Locale locale : Locale.getAvailableLocales()) { - if (locale.getVariant().isEmpty() && sTTS.isLanguageAvailable(locale) > 0) { + if (locale.getVariant().isEmpty() && getTTS().isLanguageAvailable(locale) > 0) { locales.add(locale); } } @@ -90,24 +102,29 @@ public class SpeechSynthesisService { @WrapForJNI(calledFrom = "gecko") public static String speak(final String uri, final String text, final float rate, final float pitch, final float volume) { + AtomicBoolean result = new AtomicBoolean(false); + final String utteranceId = UUID.randomUUID().toString(); + speakInternal(uri, text, rate, pitch, volume, utteranceId, result); + return result.get() ? utteranceId : null; + } + + // Extra internal method to make it easier to remove android.speech dependencies using Proguard. + private static void speakInternal(final String uri, final String text, final float rate, + final float pitch, final float volume, final String utteranceId, final AtomicBoolean result) { if (sTTS == null) { Log.w(LOGTAG, "TextToSpeech is not initialized"); - return null; + return; } HashMap params = new HashMap(); - final String utteranceId = UUID.randomUUID().toString(); params.put(TextToSpeech.Engine.KEY_PARAM_VOLUME, Float.toString(volume)); params.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, utteranceId); - sTTS.setLanguage(new Locale(uri.substring("moz-tts:android:".length()))); - sTTS.setSpeechRate(rate); - sTTS.setPitch(pitch); - int result = sTTS.speak(text, TextToSpeech.QUEUE_FLUSH, params); - if (result != TextToSpeech.SUCCESS) { - return null; - } - - return utteranceId; + TextToSpeech tss = (TextToSpeech) sTTS; + tss.setLanguage(new Locale(uri.substring("moz-tts:android:".length()))); + tss.setSpeechRate(rate); + tss.setPitch(pitch); + int speakRes = tss.speak(text, TextToSpeech.QUEUE_FLUSH, params); + result.set(speakRes == TextToSpeech.SUCCESS); } private static void setUtteranceListener() { @@ -116,7 +133,7 @@ public class SpeechSynthesisService { return; } - sTTS.setOnUtteranceProgressListener(new UtteranceProgressListener() { + getTTS().setOnUtteranceProgressListener(new UtteranceProgressListener() { @Override public void onDone(final String utteranceId) { dispatchEnd(utteranceId); @@ -163,12 +180,17 @@ public class SpeechSynthesisService { @WrapForJNI(calledFrom = "gecko") public static void stop() { + stopInternal(); + } + + // Extra internal method to make it easier to remove android.speech dependencies using Proguard. + private static void stopInternal() { if (sTTS == null) { Log.w(LOGTAG, "TextToSpeech is not initialized"); return; } - sTTS.stop(); + getTTS().stop(); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { // Android M has onStop method. If Android L or above, dispatch // event diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/NonEvictingLruCache.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/NonEvictingLruCache.java deleted file mode 100644 index b859bcf6d2a3..000000000000 --- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/NonEvictingLruCache.java +++ /dev/null @@ -1,44 +0,0 @@ -/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- - * 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/. */ - -package org.mozilla.gecko.util; - -import android.util.LruCache; - -import java.util.concurrent.ConcurrentHashMap; - -/** - * An LruCache that also supports a set of items that will never be evicted. - * - * Alas, LruCache is final, so we compose rather than inherit. - */ -public class NonEvictingLruCache { - private final ConcurrentHashMap mPermanent = new ConcurrentHashMap(); - private final LruCache mEvitable; - - public NonEvictingLruCache(final int evictableSize) { - mEvitable = new LruCache(evictableSize); - } - - public V get(final K key) { - V val = mPermanent.get(key); - if (val == null) { - return mEvitable.get(key); - } - return val; - } - - public void putWithoutEviction(final K key, final V value) { - mPermanent.put(key, value); - } - - public void put(final K key, final V value) { - mEvitable.put(key, value); - } - - public void evictAll() { - mEvitable.evictAll(); - } -} diff --git a/modules/libpref/init/StaticPrefList.h b/modules/libpref/init/StaticPrefList.h index 9c1ef692ca0a..e50dde3d8ae7 100644 --- a/modules/libpref/init/StaticPrefList.h +++ b/modules/libpref/init/StaticPrefList.h @@ -2588,6 +2588,13 @@ VARCACHE_PREF( bool, true ) +// Maximum size for an array to store the safebrowsing prefixset. +VARCACHE_PREF( + "browser.safebrowsing.prefixset_max_array_size", + browser_safebrowsing_prefixset_max_array_size, + RelaxedAtomicUint32, 512*1024 +) + // When this pref is enabled document loads with a mismatched // Cross-Origin header will fail to load VARCACHE_PREF("browser.tabs.remote.useCrossOriginPolicy", diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 9092bd4932a8..23d32e588169 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -777,7 +777,7 @@ pref("gfx.hidpi.enabled", 2); #endif // Default to containerless scrolling -pref("layout.scroll.root-frame-containers", 0); +pref("layout.scroll.root-frame-containers", false); pref("layout.scrollbars.always-layerize-track", false); @@ -6037,8 +6037,9 @@ pref("dom.datatransfer.mozAtAPIs", true); // cycles. pref("dom.sidebar.enabled", true); -// Turn on fission frameloader swapping -pref("fission.rebuild_frameloaders_on_remoteness_change", true); +// Turn off fission frameloader swapping while regressions are being fixed. +// Should be turned back on to resolve bug 1551993. +pref("fission.rebuild_frameloaders_on_remoteness_change", false); // If true, preserve browsing contexts between process swaps. Should be set to // true in bug 1550571. diff --git a/mozglue/linker/moz.build b/mozglue/linker/moz.build index 4dc6ac0dd1d5..5204347c3bd1 100644 --- a/mozglue/linker/moz.build +++ b/mozglue/linker/moz.build @@ -21,17 +21,7 @@ DEFINES['IMPL_MFBT'] = True DisableStlWrapping() -# Avoid building the linker tests if building with icecc since it doesn't deal -# well with .incbin. -# -# A better solution would be to set ICECC=no in the environment before building -# these objects to force the local build, but moz.build lacks such a capability -# at the moment. -# -# TODO: Remove this when https://github.com/icecc/icecream/pull/463 is merged -# and in a release. -if not CONFIG['CXX_IS_ICECREAM']: - TEST_DIRS += ['tests'] +TEST_DIRS += ['tests'] if CONFIG['CC_TYPE'] in ('clang', 'gcc'): CXXFLAGS += ['-Wno-error=shadow'] diff --git a/mozglue/linker/tests/TestZip.cpp b/mozglue/linker/tests/TestZip.cpp index ac5372a11365..a2d2b10bdd5d 100644 --- a/mozglue/linker/tests/TestZip.cpp +++ b/mozglue/linker/tests/TestZip.cpp @@ -11,37 +11,14 @@ Logging Logging::Singleton; -/** - * ZIP_DATA(FOO, "foo") defines the variables FOO and FOO_SIZE. - * The former contains the content of the "foo" file in the same directory - * as this file, and FOO_SIZE its size. - */ -/* clang-format off */ -#define ZIP_DATA(name, file) \ - __asm__(".global " #name "\n" \ - ".data\n" \ - ".balign 16\n" \ - #name ":\n" \ - " .incbin \"" SRCDIR "/" file "\"\n" \ - ".L" #name "_END:\n" \ - " .size " #name ", .L" #name "_END-" #name \ - "\n" \ - ".global " #name "_SIZE\n" \ - ".data\n" \ - ".balign 4\n" \ - #name "_SIZE:\n" \ - " .int .L" #name "_END-" #name "\n"); \ - extern const unsigned char name[]; \ - extern const unsigned int name##_SIZE -/* clang-format on */ - /** * test.zip is a basic test zip file with a central directory. It contains * four entries, in the following order: * "foo", "bar", "baz", "qux". * The entries are going to be read out of order. */ -ZIP_DATA(TEST_ZIP, "test.zip"); +extern const unsigned char TEST_ZIP[]; +extern const unsigned int TEST_ZIP_SIZE; const char* test_entries[] = {"baz", "foo", "bar", "qux"}; /** @@ -58,7 +35,8 @@ const char* test_entries[] = {"baz", "foo", "bar", "qux"}; * zipalign if it had a data descriptor originally. * - Fourth entry is a file "d", STOREd. */ -ZIP_DATA(NO_CENTRAL_DIR_ZIP, "no_central_dir.zip"); +extern const unsigned char NO_CENTRAL_DIR_ZIP[]; +extern const unsigned int NO_CENTRAL_DIR_ZIP_SIZE; const char* no_central_dir_entries[] = {"a", "b", "c", "d"}; TEST(Zip, TestZip) diff --git a/mozglue/linker/tests/TestZipData.S b/mozglue/linker/tests/TestZipData.S new file mode 100644 index 000000000000..5fbb82545197 --- /dev/null +++ b/mozglue/linker/tests/TestZipData.S @@ -0,0 +1,17 @@ +.macro zip_data name, path + .global \name + .data + .balign 16 + \name: + .incbin "\path" + .L\name\()_END: + .size \name, .L\name\()_END-\name + .global \name\()_SIZE + .data + .balign 4 + \name\()_SIZE: + .int .L\name\()_END-\name +.endm + +zip_data TEST_ZIP, "test.zip" +zip_data NO_CENTRAL_DIR_ZIP, "no_central_dir.zip" diff --git a/mozglue/linker/tests/moz.build b/mozglue/linker/tests/moz.build index 29b0e6e428ce..f2470dbbbeb0 100644 --- a/mozglue/linker/tests/moz.build +++ b/mozglue/linker/tests/moz.build @@ -11,9 +11,13 @@ UNIFIED_SOURCES += [ 'TestZip.cpp', ] +SOURCES += [ + 'TestZipData.S', +] + LOCAL_INCLUDES += ['..'] if CONFIG['CC_TYPE'] in ('clang', 'gcc'): CXXFLAGS += ['-Wno-error=shadow'] -DEFINES['SRCDIR'] = '"%s"' % SRCDIR +ASFLAGS += ['-I', SRCDIR] diff --git a/old-configure.in b/old-configure.in index 48fbff7383be..62e6e1e2eeb0 100644 --- a/old-configure.in +++ b/old-configure.in @@ -1691,6 +1691,13 @@ elif test "$EARLY_BETA_OR_EARLIER"; then fi AC_SUBST(EARLY_BETA_OR_EARLIER) + +if test "$EARLY_BETA_OR_EARLIER"; then + MOZ_NEW_CERT_STORAGE=1 + AC_DEFINE(MOZ_NEW_CERT_STORAGE) +fi +AC_SUBST(MOZ_NEW_CERT_STORAGE) + # Allow someone to change MOZ_APP_NAME and MOZ_APP_BASENAME in mozconfig MOZ_ARG_WITH_STRING(app-name, [--with-app-name=APPNAME sets MOZ_APP_NAME to APPNAME], diff --git a/security/manager/ssl/RemoteSecuritySettings.jsm b/security/manager/ssl/RemoteSecuritySettings.jsm index 4e36c165d88f..7cc3081e4490 100644 --- a/security/manager/ssl/RemoteSecuritySettings.jsm +++ b/security/manager/ssl/RemoteSecuritySettings.jsm @@ -83,6 +83,15 @@ function bytesToString(bytes) { return String.fromCharCode.apply(null, bytes); } +class CertInfo { + constructor(cert, subject) { + this.cert = cert; + this.subject = subject; + this.trust = Ci.nsICertStorage.TRUST_INHERIT; + } +} +CertInfo.prototype.QueryInterface = ChromeUtils.generateQI([Ci.nsICertInfo]); + this.RemoteSecuritySettings = class RemoteSecuritySettings { constructor() { this.client = RemoteSettings(Services.prefs.getCharPref(INTERMEDIATES_COLLECTION_PREF), { @@ -148,22 +157,42 @@ this.RemoteSecuritySettings = class RemoteSecuritySettings { TelemetryStopwatch.start(INTERMEDIATES_UPDATE_MS_TELEMETRY); - Promise.all(waiting.slice(0, maxDownloadsPerRun) - .map(record => this.maybeDownloadAttachment(record, col, certStorage)) - ).then(async () => { - const finalCurrent = await this.client.get(); - const finalWaiting = finalCurrent.filter(record => !record.cert_import_complete); - const countPreloaded = finalCurrent.length - finalWaiting.length; + let toDownload = waiting.slice(0, maxDownloadsPerRun); + let recordsCertsAndSubjects = await Promise.all( + toDownload.map(record => this.maybeDownloadAttachment(record))); + let certInfos = []; + let recordsToUpdate = []; + for (let {record, cert, subject} of recordsCertsAndSubjects) { + if (cert && subject) { + certInfos.push(new CertInfo(cert, subject)); + recordsToUpdate.push(record); + } + } + let result = await new Promise((resolve) => { + certStorage.addCerts(certInfos, resolve); + }).catch((err) => err); + if (result != Cr.NS_OK) { + Cu.reportError(`certStorage.addCerts failed: ${result}`); + Services.telemetry.getHistogramById(INTERMEDIATES_ERRORS_TELEMETRY) + .add("failedToUpdateDB"); + return; + } + await Promise.all(recordsToUpdate.map((record) => { + record.cert_import_complete = true; + return col.update(record); + })); + const finalCurrent = await this.client.get(); + const finalWaiting = finalCurrent.filter(record => !record.cert_import_complete); + const countPreloaded = finalCurrent.length - finalWaiting.length; - TelemetryStopwatch.finish(INTERMEDIATES_UPDATE_MS_TELEMETRY); - Services.telemetry.scalarSet(INTERMEDIATES_PRELOADED_TELEMETRY, - countPreloaded); - Services.telemetry.scalarSet(INTERMEDIATES_PENDING_TELEMETRY, - finalWaiting.length); + TelemetryStopwatch.finish(INTERMEDIATES_UPDATE_MS_TELEMETRY); + Services.telemetry.scalarSet(INTERMEDIATES_PRELOADED_TELEMETRY, + countPreloaded); + Services.telemetry.scalarSet(INTERMEDIATES_PENDING_TELEMETRY, + finalWaiting.length); - Services.obs.notifyObservers(null, "remote-security-settings:intermediates-updated", - "success"); - }); + Services.obs.notifyObservers(null, "remote-security-settings:intermediates-updated", + "success"); } async onObservePollEnd(subject, topic, data) { @@ -227,98 +256,87 @@ this.RemoteSecuritySettings = class RemoteSecuritySettings { /** * Attempts to download the attachment, assuming it's not been processed * already. Does not retry, and always resolves (e.g., does not reject upon - * failure.) Errors are reported via Cu.reportError; If you need to know - * success/failure, check record.cert_import_complete. + * failure.) Errors are reported via Cu.reportError. * @param {AttachmentRecord} record defines which data to obtain - * @param {KintoCollection} col The kinto collection to update - * @param {nsICertStorage} certStorage The certificate storage to update - * @return {Promise} a Promise representing the transaction + * @return {Promise} a Promise that will resolve to an object with the properties + * record, cert, and subject. record is the original record. + * cert is the base64-encoded bytes of the downloaded certificate (if + * downloading was successful), and null otherwise. + * subject is the base64-encoded bytes of the subject distinguished + * name of the same. */ - async maybeDownloadAttachment(record, col, certStorage) { + async maybeDownloadAttachment(record) { const {attachment: {hash, size}} = record; + let result = { record, cert: null, subject: null }; - return this._downloadAttachmentBytes(record) - .then(async function(attachmentData) { - if (!attachmentData || attachmentData.length == 0) { - // Bug 1519273 - Log telemetry for these rejections - log.debug(`Empty attachment. Hash=${hash}`); - - Services.telemetry.getHistogramById(INTERMEDIATES_ERRORS_TELEMETRY) - .add("emptyAttachment"); - - return; - } - - // check the length - if (attachmentData.length !== size) { - log.debug(`Unexpected attachment length. Hash=${hash} Lengths ${attachmentData.length} != ${size}`); - - Services.telemetry.getHistogramById(INTERMEDIATES_ERRORS_TELEMETRY) - .add("unexpectedLength"); - - return; - } - - // check the hash - let dataAsString = gTextDecoder.decode(attachmentData); - let calculatedHash = getHash(dataAsString); - if (calculatedHash !== hash) { - log.warn(`Invalid hash. CalculatedHash=${calculatedHash}, Hash=${hash}, data=${dataAsString}`); - - Services.telemetry.getHistogramById(INTERMEDIATES_ERRORS_TELEMETRY) - .add("unexpectedHash"); - - return; - } - - let certBase64; - let subjectBase64; - try { - // split off the header and footer - certBase64 = dataAsString.split("-----")[2].replace(/\s/g, ""); - // get an array of bytes so we can use X509.jsm - let certBytes = stringToBytes(atob(certBase64)); - let cert = new X509.Certificate(); - cert.parse(certBytes); - // get the DER-encoded subject and get a base64-encoded string from it - // TODO(bug 1542028): add getters for _der and _bytes - subjectBase64 = btoa(bytesToString(cert.tbsCertificate.subject._der._bytes)); - } catch (err) { - Cu.reportError(`Failed to decode cert: ${err}`); - - // Re-purpose the "failedToUpdateNSS" telemetry tag as "failed to - // decode preloaded intermediate certificate" - Services.telemetry.getHistogramById(INTERMEDIATES_ERRORS_TELEMETRY) - .add("failedToUpdateNSS"); - - return; - } - log.debug(`Adding cert. Hash=${hash}. Size=${size}`); - // We can assume that certs obtained from remote-settings are part of - // the root program. If they aren't, they won't be used for path- - // building anyway, so just add it to the DB with trust set to - // "inherit". - let result = await new Promise((resolve) => { - certStorage.addCertBySubject(certBase64, subjectBase64, - Ci.nsICertStorage.TRUST_INHERIT, - resolve); - }); - if (result != Cr.NS_OK) { - Cu.reportError(`Failed to add to cert storage: ${result}`); - Services.telemetry.getHistogramById(INTERMEDIATES_ERRORS_TELEMETRY) - .add("failedToUpdateDB"); - return; - } - - record.cert_import_complete = true; - await col.update(record); - }) - .catch(() => { - // Don't abort the outer Promise.all because of an error. Errors were - // sent using Cu.reportError() + let attachmentData; + try { + attachmentData = await this._downloadAttachmentBytes(record); + } catch (err) { + Cu.reportError(`Failed to download attachment: ${err}`); Services.telemetry.getHistogramById(INTERMEDIATES_ERRORS_TELEMETRY) .add("failedToDownloadMisc"); - }); + return result; + } + + if (!attachmentData || attachmentData.length == 0) { + // Bug 1519273 - Log telemetry for these rejections + log.debug(`Empty attachment. Hash=${hash}`); + + Services.telemetry.getHistogramById(INTERMEDIATES_ERRORS_TELEMETRY) + .add("emptyAttachment"); + + return result; + } + + // check the length + if (attachmentData.length !== size) { + log.debug(`Unexpected attachment length. Hash=${hash} Lengths ${attachmentData.length} != ${size}`); + + Services.telemetry.getHistogramById(INTERMEDIATES_ERRORS_TELEMETRY) + .add("unexpectedLength"); + + return result; + } + + // check the hash + let dataAsString = gTextDecoder.decode(attachmentData); + let calculatedHash = getHash(dataAsString); + if (calculatedHash !== hash) { + log.warn(`Invalid hash. CalculatedHash=${calculatedHash}, Hash=${hash}, data=${dataAsString}`); + + Services.telemetry.getHistogramById(INTERMEDIATES_ERRORS_TELEMETRY) + .add("unexpectedHash"); + + return result; + } + log.debug(`downloaded cert with hash=${hash}, size=${size}`); + + let certBase64; + let subjectBase64; + try { + // split off the header and footer + certBase64 = dataAsString.split("-----")[2].replace(/\s/g, ""); + // get an array of bytes so we can use X509.jsm + let certBytes = stringToBytes(atob(certBase64)); + let cert = new X509.Certificate(); + cert.parse(certBytes); + // get the DER-encoded subject and get a base64-encoded string from it + // TODO(bug 1542028): add getters for _der and _bytes + subjectBase64 = btoa(bytesToString(cert.tbsCertificate.subject._der._bytes)); + } catch (err) { + Cu.reportError(`Failed to decode cert: ${err}`); + + // Re-purpose the "failedToUpdateNSS" telemetry tag as "failed to + // decode preloaded intermediate certificate" + Services.telemetry.getHistogramById(INTERMEDIATES_ERRORS_TELEMETRY) + .add("failedToUpdateNSS"); + + return result; + } + result.cert = certBase64; + result.subject = subjectBase64; + return result; } async maybeSync(expectedTimestamp, options) { @@ -327,19 +345,12 @@ this.RemoteSecuritySettings = class RemoteSecuritySettings { async removeCerts(recordsToRemove) { let certStorage = Cc["@mozilla.org/security/certstorage;1"].getService(Ci.nsICertStorage); - let failures = 0; - for (let record of recordsToRemove) { - let result = await new Promise((resolve) => { - certStorage.removeCertByHash(record.pubKeyHash, resolve); - }); - if (result != Cr.NS_OK) { - Cu.reportError(`Failed to remove intermediate certificate Hash=${record.pubKeyHash}: ${result}`); - failures++; - } - } - - if (failures > 0) { - Cu.reportError(`Failed to remove ${failures} intermediate certificates`); + let hashes = recordsToRemove.map(record => record.pubKeyHash); + let result = await new Promise((resolve) => { + certStorage.removeCertsByHashes(hashes, resolve); + }).catch((err) => err); + if (result != Cr.NS_OK) { + Cu.reportError(`Failed to remove some intermediate certificates`); Services.telemetry.getHistogramById(INTERMEDIATES_ERRORS_TELEMETRY) .add("failedToRemove"); } diff --git a/security/manager/ssl/cert_storage/src/lib.rs b/security/manager/ssl/cert_storage/src/lib.rs index 2136d78f3203..3aaed181843f 100644 --- a/security/manager/ssl/cert_storage/src/lib.rs +++ b/security/manager/ssl/cert_storage/src/lib.rs @@ -26,7 +26,7 @@ use lmdb::EnvironmentFlags; use moz_task::{create_thread, is_main_thread, Task, TaskRunnable}; use nserror::{ nsresult, NS_ERROR_FAILURE, NS_ERROR_NOT_SAME_THREAD, NS_ERROR_NO_AGGREGATION, - NS_ERROR_UNEXPECTED, NS_OK, + NS_ERROR_NULL_POINTER, NS_ERROR_UNEXPECTED, NS_OK, }; use nsstring::{nsACString, nsAString, nsCStr, nsCString, nsString}; use rkv::error::StoreError; @@ -47,9 +47,9 @@ use std::time::{Duration, SystemTime}; use storage_variant::VariantType; use thin_vec::ThinVec; use xpcom::interfaces::{ - nsICertStorage, nsICertStorageCallback, nsIFile, nsIIssuerAndSerialRevocationState, - nsIObserver, nsIPrefBranch, nsIRevocationState, nsISubjectAndPubKeyRevocationState, - nsISupports, nsIThread, + nsICertInfo, nsICertStorage, nsICertStorageCallback, nsIFile, + nsIIssuerAndSerialRevocationState, nsIObserver, nsIPrefBranch, nsIRevocationState, + nsISubjectAndPubKeyRevocationState, nsISupports, nsIThread, }; use xpcom::{nsIID, GetterAddrefs, RefPtr, ThreadBoundRefPtr, XpCom}; @@ -395,21 +395,19 @@ impl SecurityState { self.int_prefs.insert(name.to_owned(), value); } - // To store a certificate by subject, we first create a Cert out of the given cert, subject, and - // trust. We hash the certificate with sha-256 to obtain a unique* key for that certificate, and - // we store the Cert in the database. We also look up or create a CertHashList for the given - // subject and add the new certificate's hash if it isn't present in the list. If it wasn't - // present, we write out the updated CertHashList. + // To store certificates, we create a Cert out of each given cert, subject, and trust tuple. We + // hash each certificate with sha-256 to obtain a unique* key for that certificate, and we store + // the Cert in the database. We also look up or create a CertHashList for the given subject and + // add the new certificate's hash if it isn't present in the list. If it wasn't present, we + // write out the updated CertHashList. // *By the pigeon-hole principle, there exist collisions for sha-256, so this key is not // actually unique. We rely on the assumption that sha-256 is a cryptographically strong hash. // If an adversary can find two different certificates with the same sha-256 hash, they can // probably forge a sha-256-based signature, so assuming the keys we create here are unique is // not a security issue. - pub fn add_cert_by_subject( + pub fn add_certs( &mut self, - cert_der: &[u8], - subject: &[u8], - trust: i16, + certs: &[(Vec, Vec, i16)], ) -> Result<(), SecurityStateError> { self.reopen_store_read_write()?; { @@ -428,32 +426,30 @@ impl SecurityState { &Value::Bool(true), )?; - let mut digest = Sha256::default(); - digest.input(cert_der); - let cert_hash = digest.result(); - let cert_key = make_key!(PREFIX_CERT, &cert_hash); - let cert = Cert::new(cert_der, subject, trust)?; - env_and_store - .store - .put(&mut writer, &cert_key, &Value::Blob(&cert.to_bytes()?))?; - let subject_key = make_key!(PREFIX_SUBJECT, subject); - // This reader will only be able to "see" data outside the current transaction. This is - // fine, though, because what we're reading has not yet been touched by this - // transaction. - let reader = env_and_store.env.read()?; - let empty_vec = Vec::new(); - let old_cert_hash_list = match env_and_store.store.get(&reader, &subject_key)? { - Some(Value::Blob(hashes)) => hashes, - Some(_) => &empty_vec, - None => &empty_vec, - }; - let new_cert_hash_list = CertHashList::add(old_cert_hash_list, &cert_hash)?; - if new_cert_hash_list.len() != old_cert_hash_list.len() { - env_and_store.store.put( - &mut writer, - &subject_key, - &Value::Blob(&new_cert_hash_list), - )?; + for (cert_der, subject, trust) in certs { + let mut digest = Sha256::default(); + digest.input(cert_der); + let cert_hash = digest.result(); + let cert_key = make_key!(PREFIX_CERT, &cert_hash); + let cert = Cert::new(cert_der, subject, *trust)?; + env_and_store + .store + .put(&mut writer, &cert_key, &Value::Blob(&cert.to_bytes()?))?; + let subject_key = make_key!(PREFIX_SUBJECT, subject); + let empty_vec = Vec::new(); + let old_cert_hash_list = match env_and_store.store.get(&writer, &subject_key)? { + Some(Value::Blob(hashes)) => hashes.to_owned(), + Some(_) => empty_vec, + None => empty_vec, + }; + let new_cert_hash_list = CertHashList::add(&old_cert_hash_list, &cert_hash)?; + if new_cert_hash_list.len() != old_cert_hash_list.len() { + env_and_store.store.put( + &mut writer, + &subject_key, + &Value::Blob(&new_cert_hash_list), + )?; + } } writer.commit()?; @@ -462,11 +458,11 @@ impl SecurityState { Ok(()) } - // Given a certificate's sha-256 hash, we can look up its Cert entry in the database. We use - // this to find its subject so we can look up the CertHashList it should appear in. If that list - // contains the given hash, we remove it and update the CertHashList. Finally we delete the Cert - // entry. - pub fn remove_cert_by_hash(&mut self, hash: &[u8]) -> Result<(), SecurityStateError> { + // Given a list of certificate sha-256 hashes, we can look up each Cert entry in the database. + // We use this to find the corresponding subject so we can look up the CertHashList it should + // appear in. If that list contains the given hash, we remove it and update the CertHashList. + // Finally we delete the Cert entry. + pub fn remove_certs_by_hashes(&mut self, hashes: &[Vec]) -> Result<(), SecurityStateError> { self.reopen_store_read_write()?; { let env_and_store = match self.env_and_store.as_mut() { @@ -474,33 +470,40 @@ impl SecurityState { None => return Err(SecurityStateError::from("env and store not initialized?")), }; let mut writer = env_and_store.env.write()?; - let reader = env_and_store.env.read()?; - let cert_key = make_key!(PREFIX_CERT, hash); - if let Some(Value::Blob(cert_bytes)) = env_and_store.store.get(&reader, &cert_key)? { - if let Ok(cert) = Cert::from_bytes(cert_bytes) { - let subject_key = make_key!(PREFIX_SUBJECT, &cert.subject); - let empty_vec = Vec::new(); - let old_cert_hash_list = match env_and_store.store.get(&reader, &subject_key)? { - Some(Value::Blob(hashes)) => hashes, - Some(_) => &empty_vec, - None => &empty_vec, - }; - let new_cert_hash_list = CertHashList::remove(old_cert_hash_list, hash)?; - if new_cert_hash_list.len() != old_cert_hash_list.len() { - env_and_store.store.put( - &mut writer, - &subject_key, - &Value::Blob(&new_cert_hash_list), - )?; + + for hash in hashes { + let cert_key = make_key!(PREFIX_CERT, hash); + if let Some(Value::Blob(cert_bytes)) = + env_and_store.store.get(&reader, &cert_key)? + { + if let Ok(cert) = Cert::from_bytes(cert_bytes) { + let subject_key = make_key!(PREFIX_SUBJECT, &cert.subject); + let empty_vec = Vec::new(); + // We have to use the writer here to make sure we have an up-to-date view of + // the cert hash list. + let old_cert_hash_list = + match env_and_store.store.get(&writer, &subject_key)? { + Some(Value::Blob(hashes)) => hashes.to_owned(), + Some(_) => empty_vec, + None => empty_vec, + }; + let new_cert_hash_list = CertHashList::remove(&old_cert_hash_list, hash)?; + if new_cert_hash_list.len() != old_cert_hash_list.len() { + env_and_store.store.put( + &mut writer, + &subject_key, + &Value::Blob(&new_cert_hash_list), + )?; + } } } + match env_and_store.store.delete(&mut writer, &cert_key) { + Ok(()) => {} + Err(StoreError::LmdbError(lmdb::Error::NotFound)) => {} + Err(e) => return Err(SecurityStateError::from(e)), + }; } - match env_and_store.store.delete(&mut writer, &cert_key) { - Ok(()) => {} - Err(StoreError::LmdbError(lmdb::Error::NotFound)) => {} - Err(e) => return Err(SecurityStateError::from(e)), - }; writer.commit()?; } self.reopen_store_read_only()?; @@ -1029,7 +1032,7 @@ impl CertStorage { return NS_ERROR_NOT_SAME_THREAD; } if callback.is_null() { - return NS_ERROR_FAILURE; + return NS_ERROR_NULL_POINTER; } let task = Box::new(SecurityStateTask::new( &*callback, @@ -1051,7 +1054,7 @@ impl CertStorage { return NS_ERROR_NOT_SAME_THREAD; } if revocations.is_null() || callback.is_null() { - return NS_ERROR_FAILURE; + return NS_ERROR_NULL_POINTER; } let revocations = &*revocations; @@ -1115,7 +1118,7 @@ impl CertStorage { // TODO (bug 1541212): We really want to restrict this to non-main-threads only, but we // can't do so until bug 1406854 and bug 1534600 are fixed. if issuer.is_null() || serial.is_null() || subject.is_null() || pub_key.is_null() { - return NS_ERROR_FAILURE; + return NS_ERROR_NULL_POINTER; } *state = nsICertStorage::STATE_UNSET as i16; let ss = get_security_state!(self); @@ -1140,51 +1143,65 @@ impl CertStorage { NS_OK } - unsafe fn AddCertBySubject( + unsafe fn AddCerts( &self, - cert: *const nsACString, - subject: *const nsACString, - trust: i16, + certs: *const ThinVec>, callback: *const nsICertStorageCallback, ) -> nserror::nsresult { if !is_main_thread() { return NS_ERROR_NOT_SAME_THREAD; } - if cert.is_null() || subject.is_null() || callback.is_null() { - return NS_ERROR_FAILURE; + if certs.is_null() || callback.is_null() { + return NS_ERROR_NULL_POINTER; + } + let certs = &*certs; + let mut cert_entries = Vec::with_capacity(certs.len()); + for cert in certs { + let mut der = nsCString::new(); + try_ns!((*cert).GetCert(&mut *der).to_result(), or continue); + let der = try_ns!(base64::decode(&der), or continue); + let mut subject = nsCString::new(); + try_ns!((*cert).GetSubject(&mut *subject).to_result(), or continue); + let subject = try_ns!(base64::decode(&subject), or continue); + let mut trust: i16 = 0; + try_ns!((*cert).GetTrust(&mut trust).to_result(), or continue); + cert_entries.push((der, subject, trust)); } - let cert_decoded = try_ns!(base64::decode(&*cert)); - let subject_decoded = try_ns!(base64::decode(&*subject)); let task = Box::new(SecurityStateTask::new( &*callback, &self.security_state, - move |ss| ss.add_cert_by_subject(&cert_decoded, &subject_decoded, trust), + move |ss| ss.add_certs(&cert_entries), )); let thread = try_ns!(self.thread.lock()); - let runnable = try_ns!(TaskRunnable::new("AddCertBySubject", task)); + let runnable = try_ns!(TaskRunnable::new("AddCerts", task)); try_ns!(runnable.dispatch(&*thread)); NS_OK } - unsafe fn RemoveCertByHash( + unsafe fn RemoveCertsByHashes( &self, - hash: *const nsACString, + hashes: *const ThinVec, callback: *const nsICertStorageCallback, ) -> nserror::nsresult { if !is_main_thread() { return NS_ERROR_NOT_SAME_THREAD; } - if hash.is_null() || callback.is_null() { - return NS_ERROR_FAILURE; + if hashes.is_null() || callback.is_null() { + return NS_ERROR_NULL_POINTER; + } + let hashes = &*hashes; + let mut hash_entries = Vec::with_capacity(hashes.len()); + for hash in hashes { + let hash_decoded = try_ns!(base64::decode(&*hash), or continue); + hash_entries.push(hash_decoded); } - let hash_decoded = try_ns!(base64::decode(&*hash)); let task = Box::new(SecurityStateTask::new( &*callback, &self.security_state, - move |ss| ss.remove_cert_by_hash(&hash_decoded), + move |ss| ss.remove_certs_by_hashes(&hash_entries), )); let thread = try_ns!(self.thread.lock()); - let runnable = try_ns!(TaskRunnable::new("RemoveCertByHash", task)); + let runnable = try_ns!(TaskRunnable::new("RemoveCertsByHashes", task)); try_ns!(runnable.dispatch(&*thread)); NS_OK } @@ -1197,7 +1214,7 @@ impl CertStorage { // TODO (bug 1541212): We really want to restrict this to non-main-threads only, but we // can't do so until bug 1406854 and bug 1534600 are fixed. if subject.is_null() || certs.is_null() { - return NS_ERROR_FAILURE; + return NS_ERROR_NULL_POINTER; } let ss = get_security_state!(self); match ss.find_certs_by_subject(&*subject, &mut *certs) { diff --git a/security/manager/ssl/nsICertStorage.idl b/security/manager/ssl/nsICertStorage.idl index 98eb50190b35..74f516bdc4df 100644 --- a/security/manager/ssl/nsICertStorage.idl +++ b/security/manager/ssl/nsICertStorage.idl @@ -55,6 +55,22 @@ interface nsISubjectAndPubKeyRevocationState : nsIRevocationState { readonly attribute ACString pubKey; }; +/** + * An interface representing a certificate to add to storage. Consists of the + * base64-encoded DER bytes of the certificate (cert), the base64-encoded DER + * bytes of the subject distinguished name of the certificate (subject), and the + * trust of the certificate (one of the nsICertStorage.TRUST_* constants). + * (Note that this implementation does not validate that the given subject DN + * actually matches the subject DN of the certificate, nor that the given cert + * is a valid DER X.509 certificate.) + */ +[scriptable, uuid(27b66f5e-0faf-403b-95b4-bc11691ac50d)] +interface nsICertInfo : nsISupports { + readonly attribute ACString cert; + readonly attribute ACString subject; + readonly attribute short trust; +}; + [scriptable, uuid(327100a7-3401-45ef-b160-bf880f1016fd)] interface nsICertStorage : nsISupports { const octet DATA_TYPE_REVOCATION = 1; @@ -118,34 +134,27 @@ interface nsICertStorage : nsISupports { const short TRUST_ANCHOR = 1; /** - * Asynchronously add a certificate to the backing storage. - * cert is the bytes of the certificate as base64-encoded DER. - * subject is the subject distinguished name of the certificate as - * base64-encoded DER (although we don't actually validate that the given - * certificate has the indicated subject). - * trust is one of the TRUST_* constants in this interface. + * Asynchronously add a list of certificates to the backing storage. + * See the documentation for nsICertInfo. * The given callback is called with the result of the operation when it * completes. * Must only be called from the main thread. */ [must_use] - void addCertBySubject(in ACString cert, - in ACString subject, - in short trust, - in nsICertStorageCallback callback); + void addCerts(in Array certs, in nsICertStorageCallback callback); /** - * Asynchronously remove the certificate with the given sha-256 hash from the - * backing storage. - * hash is the base64-encoded bytes of the sha-256 hash of the certificate's - * bytes (DER-encoded). + * Asynchronously remove the certificates with the given sha-256 hashes from + * the backing storage. + * hashes is an array of base64-encoded bytes of the sha-256 hashes of each + * certificate's bytes (DER-encoded). * The given callback is called with the result of the operation when it * completes. * Must only be called from the main thread. */ [must_use] - void removeCertByHash(in ACString hash, - in nsICertStorageCallback callback); + void removeCertsByHashes(in Array hashes, + in nsICertStorageCallback callback); /** * Find all certificates in the backing storage with the given subject diff --git a/security/manager/ssl/nsNSSCallbacks.cpp b/security/manager/ssl/nsNSSCallbacks.cpp index 0ff9202a3fbb..2c9c041e8c4e 100644 --- a/security/manager/ssl/nsNSSCallbacks.cpp +++ b/security/manager/ssl/nsNSSCallbacks.cpp @@ -1271,10 +1271,12 @@ void HandshakeCallback(PRFileDesc* fd, void* client_data) { bool renegotiationUnsafe = !siteSupportsSafeRenego && ioLayerHelpers.treatUnsafeNegotiationAsBroken(); + bool deprecatedTlsVer = + (channelInfo.protocolVersion < SSL_LIBRARY_VERSION_TLS_1_2); RememberCertErrorsTable::GetInstance().LookupCertErrorBits(infoObject); uint32_t state; - if (renegotiationUnsafe) { + if (renegotiationUnsafe || deprecatedTlsVer) { state = nsIWebProgressListener::STATE_IS_BROKEN; } else { state = nsIWebProgressListener::STATE_IS_SECURE; diff --git a/security/manager/ssl/security-prefs.js b/security/manager/ssl/security-prefs.js index 3fc1686ebeae..eb2376efb0b9 100644 --- a/security/manager/ssl/security-prefs.js +++ b/security/manager/ssl/security-prefs.js @@ -164,10 +164,10 @@ pref("security.pki.mitm_canary_issuer.enabled", true); pref("security.pki.mitm_detected", false); // Intermediate CA Preloading settings -#if defined(RELEASE_OR_BETA) || defined(MOZ_WIDGET_ANDROID) -pref("security.remote_settings.intermediates.enabled", false); -#else +#if defined(MOZ_NEW_CERT_STORAGE) && !defined(MOZ_WIDGET_ANDROID) pref("security.remote_settings.intermediates.enabled", true); +#else +pref("security.remote_settings.intermediates.enabled", false); #endif pref("security.remote_settings.intermediates.bucket", "security-state"); pref("security.remote_settings.intermediates.collection", "intermediates"); diff --git a/security/manager/ssl/tests/unit/test_cert_storage_broken_db.js b/security/manager/ssl/tests/unit/test_cert_storage_broken_db.js index 5f8ffeb400e2..35dd10630a78 100644 --- a/security/manager/ssl/tests/unit/test_cert_storage_broken_db.js +++ b/security/manager/ssl/tests/unit/test_cert_storage_broken_db.js @@ -54,10 +54,9 @@ add_task({ check_has_prior_cert_data(certStorage, false); result = await new Promise((resolve) => { - certStorage.addCertBySubject(btoa("some cert"), btoa("some subject"), - Ci.nsICertStorage.TRUST_INHERIT, resolve); + certStorage.addCerts([], resolve); }); - Assert.equal(result, Cr.NS_OK, "addCertBySubject should succeed"); + Assert.equal(result, Cr.NS_OK, "addCerts should succeed"); check_has_prior_revocation_data(certStorage, true); check_has_prior_cert_data(certStorage, true); diff --git a/security/manager/ssl/tests/unit/test_cert_storage_direct.js b/security/manager/ssl/tests/unit/test_cert_storage_direct.js index 040827d60600..c6d95c92a372 100644 --- a/security/manager/ssl/tests/unit/test_cert_storage_direct.js +++ b/security/manager/ssl/tests/unit/test_cert_storage_direct.js @@ -13,19 +13,18 @@ if (AppConstants.MOZ_NEW_CERT_STORAGE) { this.certStorage = Cc["@mozilla.org/security/certstorage;1"].getService(Ci.nsICertStorage); } -async function addCertBySubject(cert, subject) { +async function addCerts(certInfos) { let result = await new Promise((resolve) => { - certStorage.addCertBySubject(btoa(cert), btoa(subject), Ci.nsICertStorage.TRUST_INHERIT, - resolve); + certStorage.addCerts(certInfos, resolve); }); - Assert.equal(result, Cr.NS_OK, "addCertBySubject should succeed"); + Assert.equal(result, Cr.NS_OK, "addCerts should succeed"); } -async function removeCertByHash(hashBase64) { +async function removeCertsByHashes(hashesBase64) { let result = await new Promise((resolve) => { - certStorage.removeCertByHash(hashBase64, resolve); + certStorage.removeCertsByHashes(hashesBase64, resolve); }); - Assert.equal(result, Cr.NS_OK, "removeCertByHash should succeed"); + Assert.equal(result, Cr.NS_OK, "removeCertsByHashes should succeed"); } function stringToArray(s) { @@ -48,19 +47,31 @@ function getLongString(uniquePart, length) { return String(uniquePart).padStart(length, "0"); } +class CertInfo { + constructor(cert, subject) { + this.cert = btoa(cert); + this.subject = btoa(subject); + this.trust = Ci.nsICertStorage.TRUST_INHERIT; + } +} +if (AppConstants.MOZ_NEW_CERT_STORAGE) { + CertInfo.prototype.QueryInterface = ChromeUtils.generateQI([Ci.nsICertInfo]); +} + add_task({ skip_if: () => !AppConstants.MOZ_NEW_CERT_STORAGE, }, async function test_common_subject() { - await addCertBySubject("some certificate bytes 1", "some common subject"); - await addCertBySubject("some certificate bytes 2", "some common subject"); - await addCertBySubject("some certificate bytes 3", "some common subject"); + let someCert1 = new CertInfo("some certificate bytes 1", "some common subject"); + let someCert2 = new CertInfo("some certificate bytes 2", "some common subject"); + let someCert3 = new CertInfo("some certificate bytes 3", "some common subject"); + await addCerts([someCert1, someCert2, someCert3]); let storedCerts = certStorage.findCertsBySubject(stringToArray("some common subject")); let storedCertsAsStrings = storedCerts.map(arrayToString); let expectedCerts = ["some certificate bytes 1", "some certificate bytes 2", "some certificate bytes 3"]; Assert.deepEqual(storedCertsAsStrings.sort(), expectedCerts.sort(), "should find expected certs"); - await addCertBySubject("some other certificate bytes", "some other subject"); + await addCerts([new CertInfo("some other certificate bytes", "some other subject")]); storedCerts = certStorage.findCertsBySubject(stringToArray("some common subject")); storedCertsAsStrings = storedCerts.map(arrayToString); Assert.deepEqual(storedCertsAsStrings.sort(), expectedCerts.sort(), @@ -78,9 +89,11 @@ add_task({ const NUM_CERTS = 500; const CERT_LENGTH = 3000; const SUBJECT_LENGTH = 40; + let certs = []; for (let i = 0; i < NUM_CERTS; i++) { - await addCertBySubject(getLongString(i, CERT_LENGTH), getLongString(i, SUBJECT_LENGTH)); + certs.push(new CertInfo(getLongString(i, CERT_LENGTH), getLongString(i, SUBJECT_LENGTH))); } + await addCerts(certs); for (let i = 0; i < NUM_CERTS; i++) { let subject = stringToArray(getLongString(i, SUBJECT_LENGTH)); let storedCerts = certStorage.findCertsBySubject(subject); @@ -96,11 +109,12 @@ add_task({ }, async function test_removal() { // As long as cert_storage is given valid base64, attempting to delete some nonexistent // certificate will "succeed" (it'll do nothing). - await removeCertByHash(btoa("thishashisthewrongsize")); + await removeCertsByHashes([btoa("thishashisthewrongsize")]); - await addCertBySubject("removal certificate bytes 1", "common subject to remove"); - await addCertBySubject("removal certificate bytes 2", "common subject to remove"); - await addCertBySubject("removal certificate bytes 3", "common subject to remove"); + let removalCert1 = new CertInfo("removal certificate bytes 1", "common subject to remove"); + let removalCert2 = new CertInfo("removal certificate bytes 2", "common subject to remove"); + let removalCert3 = new CertInfo("removal certificate bytes 3", "common subject to remove"); + await addCerts([removalCert1, removalCert2, removalCert3]); let storedCerts = certStorage.findCertsBySubject(stringToArray("common subject to remove")); let storedCertsAsStrings = storedCerts.map(arrayToString); @@ -110,7 +124,7 @@ add_task({ "should find expected certs before removing them"); // echo -n "removal certificate bytes 2" | sha256sum | xxd -r -p | base64 - await removeCertByHash("2nUPHwl5TVr1mAD1FU9FivLTlTb0BAdnVUhsYgBccN4="); + await removeCertsByHashes(["2nUPHwl5TVr1mAD1FU9FivLTlTb0BAdnVUhsYgBccN4="]); storedCerts = certStorage.findCertsBySubject(stringToArray("common subject to remove")); storedCertsAsStrings = storedCerts.map(arrayToString); expectedCerts = ["removal certificate bytes 1", "removal certificate bytes 3"]; @@ -118,7 +132,7 @@ add_task({ "should only have first and third certificates now"); // echo -n "removal certificate bytes 1" | sha256sum | xxd -r -p | base64 - await removeCertByHash("8zoRqHYrklr7Zx6UWpzrPuL+ol8KL1Ml6XHBQmXiaTY="); + await removeCertsByHashes(["8zoRqHYrklr7Zx6UWpzrPuL+ol8KL1Ml6XHBQmXiaTY="]); storedCerts = certStorage.findCertsBySubject(stringToArray("common subject to remove")); storedCertsAsStrings = storedCerts.map(arrayToString); expectedCerts = ["removal certificate bytes 3"]; @@ -126,11 +140,34 @@ add_task({ "should only have third certificate now"); // echo -n "removal certificate bytes 3" | sha256sum | xxd -r -p | base64 - await removeCertByHash("vZn7GwDSabB/AVo0T+N26nUsfSXIIx4NgQtSi7/0p/w="); + await removeCertsByHashes(["vZn7GwDSabB/AVo0T+N26nUsfSXIIx4NgQtSi7/0p/w="]); storedCerts = certStorage.findCertsBySubject(stringToArray("common subject to remove")); Assert.equal(storedCerts.length, 0, "shouldn't have any certificates now"); // echo -n "removal certificate bytes 3" | sha256sum | xxd -r -p | base64 // Again, removing a nonexistent certificate should "succeed". - await removeCertByHash("vZn7GwDSabB/AVo0T+N26nUsfSXIIx4NgQtSi7/0p/w="); + await removeCertsByHashes(["vZn7GwDSabB/AVo0T+N26nUsfSXIIx4NgQtSi7/0p/w="]); +}); + +add_task({ + skip_if: () => !AppConstants.MOZ_NEW_CERT_STORAGE, +}, async function test_batched_removal() { + let removalCert1 = new CertInfo("batch removal certificate bytes 1", "batch subject to remove"); + let removalCert2 = new CertInfo("batch removal certificate bytes 2", "batch subject to remove"); + let removalCert3 = new CertInfo("batch removal certificate bytes 3", "batch subject to remove"); + await addCerts([removalCert1, removalCert2, removalCert3]); + let storedCerts = certStorage.findCertsBySubject(stringToArray("batch subject to remove")); + let storedCertsAsStrings = storedCerts.map(arrayToString); + let expectedCerts = ["batch removal certificate bytes 1", "batch removal certificate bytes 2", + "batch removal certificate bytes 3"]; + Assert.deepEqual(storedCertsAsStrings.sort(), expectedCerts.sort(), + "should find expected certs before removing them"); + // echo -n "batch removal certificate bytes 1" | sha256sum | xxd -r -p | base64 + // echo -n "batch removal certificate bytes 2" | sha256sum | xxd -r -p | base64 + // echo -n "batch removal certificate bytes 3" | sha256sum | xxd -r -p | base64 + await removeCertsByHashes(["EOEEUTuanHZX9NFVCoMKVT22puIJC6g+ZuNPpJgvaa8=", + "Xz6h/Kvn35cCLJEZXkjPqk1GG36b56sreLyAXpO+0zg=", + "Jr7XdiTT8ZONUL+ogNNMW2oxKxanvYOLQPKBPgH/has="]); + storedCerts = certStorage.findCertsBySubject(stringToArray("batch subject to remove")); + Assert.equal(storedCerts.length, 0, "shouldn't have any certificates now"); }); diff --git a/services/common/blocklist-clients.js b/services/common/blocklist-clients.js index 80c850847df8..12a70171f4f1 100644 --- a/services/common/blocklist-clients.js +++ b/services/common/blocklist-clients.js @@ -182,71 +182,6 @@ async function updatePinningList({ data: { current: records } }) { } } -/** - * This custom filter function is used to limit the entries returned - * by `RemoteSettings("...").get()` depending on the target app information - * defined on entries. - * - * Note that this is async because `jexlFilterFunc` is async. - */ -async function targetAppFilter(entry, environment) { - // If the entry has a JEXL filter expression, it should prevail. - // The legacy target app mechanism will be kept in place for old entries. - // See https://bugzilla.mozilla.org/show_bug.cgi?id=1463377 - const { filter_expression } = entry; - if (filter_expression) { - return jexlFilterFunc(entry, environment); - } - - // Keep entries without target information. - if (!("versionRange" in entry)) { - return entry; - } - - const { appID, version: appVersion, toolkitVersion } = environment; - const { versionRange } = entry; - - // Everywhere in this method, we avoid checking the minVersion, because - // we want to retain items whose minVersion is higher than the current - // app version, so that we have the items around for app updates. - - // Gfx blocklist has a specific versionRange object, which is not a list. - if (!Array.isArray(versionRange)) { - const { maxVersion = "*" } = versionRange; - const matchesRange = (Services.vc.compare(appVersion, maxVersion) <= 0); - return matchesRange ? entry : null; - } - - // Iterate the targeted applications, at least one of them must match. - // If no target application, keep the entry. - if (versionRange.length == 0) { - return entry; - } - for (const vr of versionRange) { - const { targetApplication = [] } = vr; - if (targetApplication.length == 0) { - return entry; - } - for (const ta of targetApplication) { - const { guid } = ta; - if (!guid) { - return entry; - } - const { maxVersion = "*" } = ta; - if (guid == appID && - Services.vc.compare(appVersion, maxVersion) <= 0) { - return entry; - } - if (guid == "toolkit@mozilla.org" && - Services.vc.compare(toolkitVersion, maxVersion) <= 0) { - return entry; - } - } - } - // Skip this entry. - return null; -} - var OneCRLBlocklistClient; var PinningBlocklistClient; var RemoteSecuritySettingsClient; @@ -291,5 +226,5 @@ function initialize(options = {}) { }; } -let BlocklistClients = {initialize, targetAppFilter}; +let BlocklistClients = {initialize}; diff --git a/servo/components/style/properties/data.py b/servo/components/style/properties/data.py index ae3070776903..82a98d60d7bd 100644 --- a/servo/components/style/properties/data.py +++ b/servo/components/style/properties/data.py @@ -172,7 +172,7 @@ class Longhand(object): gecko_ffi_name=None, allowed_in_keyframe_block=True, cast_type='u8', logical=False, logical_group=None, alias=None, extra_prefixes=None, boxed=False, - flags=None, allowed_in_page_rule=False, allow_quirks=False, + flags=None, allowed_in_page_rule=False, allow_quirks="No", ignored_when_colors_disabled=False, vector=False, servo_restyle_damage="repaint"): self.name = name diff --git a/servo/components/style/properties/helpers.mako.rs b/servo/components/style/properties/helpers.mako.rs index 8310d537f36d..9b63ca8465cf 100644 --- a/servo/components/style/properties/helpers.mako.rs +++ b/servo/components/style/properties/helpers.mako.rs @@ -10,7 +10,7 @@ <%def name="predefined_type(name, type, initial_value, parse_method='parse', needs_context=True, vector=False, computed_type=None, initial_specified_value=None, - allow_quirks=False, allow_empty=False, **kwargs)"> + allow_quirks='No', allow_empty=False, **kwargs)"> <%def name="predefined_type_inner(name, type, initial_value, parse_method)"> #[allow(unused_imports)] use app_units::Au; @@ -42,8 +42,8 @@ context: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result> { - % if allow_quirks: - specified::${type}::${parse_method}_quirky(context, input, AllowQuirks::Yes) + % if allow_quirks != "No": + specified::${type}::${parse_method}_quirky(context, input, AllowQuirks::${allow_quirks}) % elif needs_context: specified::${type}::${parse_method}(context, input) % else: @@ -405,8 +405,8 @@ context: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result> { - % if property.allow_quirks: - parse_quirky(context, input, specified::AllowQuirks::Yes) + % if property.allow_quirks != "No": + parse_quirky(context, input, specified::AllowQuirks::${property.allow_quirks}) % else: parse(context, input) % endif @@ -868,7 +868,7 @@ <%def name="four_sides_shorthand(name, sub_property_pattern, parser_function, - needs_context=True, allow_quirks=False, **kwargs)"> + needs_context=True, allow_quirks='No', **kwargs)"> <% sub_properties=' '.join(sub_property_pattern % side for side in PHYSICAL_SIDES) %> <%call expr="self.shorthand(name, sub_properties=sub_properties, **kwargs)"> #[allow(unused_imports)] @@ -881,8 +881,8 @@ input: &mut Parser<'i, 't>, ) -> Result> { let rect = Rect::parse_with(context, input, |_c, i| { - % if allow_quirks: - ${parser_function}_quirky(_c, i, specified::AllowQuirks::Yes) + % if allow_quirks != "No": + ${parser_function}_quirky(_c, i, specified::AllowQuirks::${allow_quirks}) % elif needs_context: ${parser_function}(_c, i) % else: diff --git a/servo/components/style/properties/longhands/background.mako.rs b/servo/components/style/properties/longhands/background.mako.rs index 42344a18cb9c..9c66e4676f96 100644 --- a/servo/components/style/properties/longhands/background.mako.rs +++ b/servo/components/style/properties/longhands/background.mako.rs @@ -14,7 +14,7 @@ ${helpers.predefined_type( spec="https://drafts.csswg.org/css-backgrounds/#background-color", animation_value_type="AnimatedColor", ignored_when_colors_disabled=True, - allow_quirks=True, + allow_quirks="Yes", flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER \ CAN_ANIMATE_ON_COMPOSITOR", )} diff --git a/servo/components/style/properties/longhands/border.mako.rs b/servo/components/style/properties/longhands/border.mako.rs index 13a7f2373501..7ea8b8dd0eb3 100644 --- a/servo/components/style/properties/longhands/border.mako.rs +++ b/servo/components/style/properties/longhands/border.mako.rs @@ -28,7 +28,7 @@ animation_value_type="AnimatedColor", logical=is_logical, logical_group="border-color", - allow_quirks=not is_logical, + allow_quirks="No" if is_logical else "Yes", flags="APPLIES_TO_FIRST_LETTER", ignored_when_colors_disabled=True, )} @@ -56,7 +56,7 @@ logical=is_logical, logical_group="border-width", flags="APPLIES_TO_FIRST_LETTER GETCS_NEEDS_LAYOUT_FLUSH", - allow_quirks=not is_logical, + allow_quirks="No" if is_logical else "Yes", servo_restyle_damage="reflow rebuild_and_reflow_inline" )} % endfor diff --git a/servo/components/style/properties/longhands/effects.mako.rs b/servo/components/style/properties/longhands/effects.mako.rs index 0b3f96f0dde3..63db3a64348c 100644 --- a/servo/components/style/properties/longhands/effects.mako.rs +++ b/servo/components/style/properties/longhands/effects.mako.rs @@ -37,7 +37,7 @@ ${helpers.predefined_type( "computed::ClipRectOrAuto::auto()", animation_value_type="ComputedValue", boxed=True, - allow_quirks=True, + allow_quirks="Yes", spec="https://drafts.fxtf.org/css-masking/#clip-property", )} diff --git a/servo/components/style/properties/longhands/font.mako.rs b/servo/components/style/properties/longhands/font.mako.rs index c1d3d8fcc6c3..8d84ef34cb3c 100644 --- a/servo/components/style/properties/longhands/font.mako.rs +++ b/servo/components/style/properties/longhands/font.mako.rs @@ -64,7 +64,7 @@ ${helpers.predefined_type( initial_value="computed::FontSize::medium()", initial_specified_value="specified::FontSize::medium()", animation_value_type="NonNegativeLength", - allow_quirks=True, + allow_quirks="Yes", flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER", spec="https://drafts.csswg.org/css-fonts/#propdef-font-size", servo_restyle_damage="rebuild_and_reflow", diff --git a/servo/components/style/properties/longhands/inherited_text.mako.rs b/servo/components/style/properties/longhands/inherited_text.mako.rs index cdd7df932560..8a3803045046 100644 --- a/servo/components/style/properties/longhands/inherited_text.mako.rs +++ b/servo/components/style/properties/longhands/inherited_text.mako.rs @@ -56,7 +56,7 @@ ${helpers.predefined_type( "computed::LengthPercentage::zero()", animation_value_type="ComputedValue", spec="https://drafts.csswg.org/css-text/#propdef-text-indent", - allow_quirks=True, + allow_quirks="Yes", servo_restyle_damage = "reflow", )} diff --git a/servo/components/style/properties/longhands/margin.mako.rs b/servo/components/style/properties/longhands/margin.mako.rs index d2a3be11d1d2..c3289c34b7cb 100644 --- a/servo/components/style/properties/longhands/margin.mako.rs +++ b/servo/components/style/properties/longhands/margin.mako.rs @@ -17,7 +17,7 @@ "LengthPercentageOrAuto", "computed::LengthPercentageOrAuto::zero()", alias=maybe_moz_logical_alias(product, side, "-moz-margin-%s"), - allow_quirks=not side[1], + allow_quirks="No" if side[1] else "Yes", animation_value_type="ComputedValue", logical=side[1], logical_group="margin", diff --git a/servo/components/style/properties/longhands/padding.mako.rs b/servo/components/style/properties/longhands/padding.mako.rs index a1262aee0fce..6142bbf901ec 100644 --- a/servo/components/style/properties/longhands/padding.mako.rs +++ b/servo/components/style/properties/longhands/padding.mako.rs @@ -24,7 +24,7 @@ logical_group="padding", spec=spec, flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_PLACEHOLDER GETCS_NEEDS_LAYOUT_FLUSH", - allow_quirks=not side[1], + allow_quirks="No" if side[1] else "Yes", servo_restyle_damage="reflow rebuild_and_reflow_inline" )} % endfor diff --git a/servo/components/style/properties/longhands/position.mako.rs b/servo/components/style/properties/longhands/position.mako.rs index 096349f4b1cf..34216385feda 100644 --- a/servo/components/style/properties/longhands/position.mako.rs +++ b/servo/components/style/properties/longhands/position.mako.rs @@ -17,7 +17,7 @@ spec="https://www.w3.org/TR/CSS2/visuren.html#propdef-%s" % side, flags="GETCS_NEEDS_LAYOUT_FLUSH", animation_value_type="ComputedValue", - allow_quirks=True, + allow_quirks="Yes", servo_restyle_damage="reflow_out_of_flow", logical_group="inset", )} @@ -253,7 +253,7 @@ ${helpers.predefined_type( "computed::Size::auto()", logical=logical, logical_group="size", - allow_quirks=not logical, + allow_quirks="No" if logical else "Yes", spec=spec % size, animation_value_type="Size", flags="GETCS_NEEDS_LAYOUT_FLUSH", @@ -266,7 +266,7 @@ ${helpers.predefined_type( "computed::Size::auto()", logical=logical, logical_group="min-size", - allow_quirks=not logical, + allow_quirks="No" if logical else "Yes", spec=spec % size, animation_value_type="Size", servo_restyle_damage="reflow", @@ -277,7 +277,7 @@ ${helpers.predefined_type( "computed::MaxSize::none()", logical=logical, logical_group="max-size", - allow_quirks=not logical, + allow_quirks="No" if logical else "Yes", spec=spec % size, animation_value_type="MaxSize", servo_restyle_damage="reflow", diff --git a/servo/components/style/properties/longhands/svg.mako.rs b/servo/components/style/properties/longhands/svg.mako.rs index 3e4d207397ac..8e93d03dbb1b 100644 --- a/servo/components/style/properties/longhands/svg.mako.rs +++ b/servo/components/style/properties/longhands/svg.mako.rs @@ -191,3 +191,66 @@ ${helpers.predefined_type( animation_value_type="discrete", flags="CREATES_STACKING_CONTEXT", )} + +${helpers.predefined_type( + "x", + "LengthPercentage", + "computed::LengthPercentage::zero()", + products="gecko", + animation_value_type="ComputedValue", + spec="https://svgwg.org/svg2-draft/geometry.html#X", +)} + +${helpers.predefined_type( + "y", + "LengthPercentage", + "computed::LengthPercentage::zero()", + products="gecko", + animation_value_type="ComputedValue", + spec="https://svgwg.org/svg2-draft/geometry.html#Y", +)} + +${helpers.predefined_type( + "cx", + "LengthPercentage", + "computed::LengthPercentage::zero()", + products="gecko", + animation_value_type="ComputedValue", + spec="https://svgwg.org/svg2-draft/geometry.html#CX", +)} + +${helpers.predefined_type( + "cy", + "LengthPercentage", + "computed::LengthPercentage::zero()", + products="gecko", + animation_value_type="ComputedValue", + spec="https://svgwg.org/svg2-draft/geometry.html#CY", +)} + +${helpers.predefined_type( + "rx", + "NonNegativeLengthPercentageOrAuto", + "computed::NonNegativeLengthPercentageOrAuto::auto()", + products="gecko", + animation_value_type="LengthPercentageOrAuto", + spec="https://svgwg.org/svg2-draft/geometry.html#RX", +)} + +${helpers.predefined_type( + "ry", + "NonNegativeLengthPercentageOrAuto", + "computed::NonNegativeLengthPercentageOrAuto::auto()", + products="gecko", + animation_value_type="LengthPercentageOrAuto", + spec="https://svgwg.org/svg2-draft/geometry.html#RY", +)} + +${helpers.predefined_type( + "r", + "NonNegativeLengthPercentage", + "computed::NonNegativeLengthPercentage::zero()", + products="gecko", + animation_value_type="LengthPercentage", + spec="https://svgwg.org/svg2-draft/geometry.html#R", +)} diff --git a/servo/components/style/properties/shorthands/border.mako.rs b/servo/components/style/properties/shorthands/border.mako.rs index cd4720687935..1f8df0df6a12 100644 --- a/servo/components/style/properties/shorthands/border.mako.rs +++ b/servo/components/style/properties/shorthands/border.mako.rs @@ -7,7 +7,7 @@ ${helpers.four_sides_shorthand("border-color", "border-%s-color", "specified::Color::parse", spec="https://drafts.csswg.org/css-backgrounds/#border-color", - allow_quirks=True)} + allow_quirks="Yes")} ${helpers.four_sides_shorthand( "border-style", diff --git a/servo/components/style/properties/shorthands/margin.mako.rs b/servo/components/style/properties/shorthands/margin.mako.rs index fd3124a6ae15..9b996abbe86b 100644 --- a/servo/components/style/properties/shorthands/margin.mako.rs +++ b/servo/components/style/properties/shorthands/margin.mako.rs @@ -10,7 +10,7 @@ ${helpers.four_sides_shorthand( "specified::LengthPercentageOrAuto::parse", spec="https://drafts.csswg.org/css-box/#propdef-margin", allowed_in_page_rule=True, - allow_quirks=True, + allow_quirks="Yes", )} ${helpers.two_properties_shorthand( diff --git a/servo/components/style/properties/shorthands/padding.mako.rs b/servo/components/style/properties/shorthands/padding.mako.rs index a4e013caabc3..8d50c3b9e38d 100644 --- a/servo/components/style/properties/shorthands/padding.mako.rs +++ b/servo/components/style/properties/shorthands/padding.mako.rs @@ -9,7 +9,7 @@ ${helpers.four_sides_shorthand( "padding-%s", "specified::NonNegativeLengthPercentage::parse", spec="https://drafts.csswg.org/css-box-3/#propdef-padding", - allow_quirks=True, + allow_quirks="Yes", )} ${helpers.two_properties_shorthand( diff --git a/servo/components/style/properties/shorthands/position.mako.rs b/servo/components/style/properties/shorthands/position.mako.rs index 6fdbe1235cff..63298b86ba12 100644 --- a/servo/components/style/properties/shorthands/position.mako.rs +++ b/servo/components/style/properties/shorthands/position.mako.rs @@ -768,7 +768,7 @@ ${helpers.four_sides_shorthand( "%s", "specified::LengthPercentageOrAuto::parse", spec="https://drafts.csswg.org/css-logical/#propdef-inset", - allow_quirks=False, + allow_quirks="No", )} ${helpers.two_properties_shorthand( diff --git a/servo/ports/geckolib/glue.rs b/servo/ports/geckolib/glue.rs index bda1dd711003..e995731aeccd 100644 --- a/servo/ports/geckolib/glue.rs +++ b/servo/ports/geckolib/glue.rs @@ -4513,7 +4513,7 @@ pub extern "C" fn Servo_DeclarationBlock_SetLengthValue( use style::properties::longhands::_moz_script_min_size::SpecifiedValue as MozScriptMinSize; use style::properties::PropertyDeclaration; use style::values::generics::NonNegative; - use style::values::generics::length::Size; + use style::values::generics::length::{Size, LengthPercentageOrAuto}; use style::values::specified::length::NoCalcLength; use style::values::specified::length::{AbsoluteLength, FontRelativeLength}; use style::values::specified::length::LengthPercentage; @@ -4542,6 +4542,14 @@ pub extern "C" fn Servo_DeclarationBlock_SetLengthValue( let prop = match_wrap_declared! { long, Width => Size::LengthPercentage(NonNegative(LengthPercentage::Length(nocalc))), + Height => Size::LengthPercentage(NonNegative(LengthPercentage::Length(nocalc))), + X => LengthPercentage::Length(nocalc), + Y => LengthPercentage::Length(nocalc), + Cx => LengthPercentage::Length(nocalc), + Cy => LengthPercentage::Length(nocalc), + R => NonNegative(LengthPercentage::Length(nocalc)), + Rx => LengthPercentageOrAuto::LengthPercentage(NonNegative(LengthPercentage::Length(nocalc))), + Ry => LengthPercentageOrAuto::LengthPercentage(NonNegative(LengthPercentage::Length(nocalc))), FontSize => LengthPercentage::from(nocalc).into(), MozScriptMinSize => MozScriptMinSize(nocalc), }; @@ -4592,6 +4600,13 @@ pub extern "C" fn Servo_DeclarationBlock_SetPercentValue( let prop = match_wrap_declared! { long, Height => Size::LengthPercentage(NonNegative(lp)), Width => Size::LengthPercentage(NonNegative(lp)), + X => lp, + Y => lp, + Cx => lp, + Cy => lp, + R => NonNegative(lp), + Rx => LengthPercentageOrAuto::LengthPercentage(NonNegative(lp)), + Ry => LengthPercentageOrAuto::LengthPercentage(NonNegative(lp)), MarginTop => lp_or_auto, MarginRight => lp_or_auto, MarginBottom => lp_or_auto, diff --git a/taskcluster/ci/build/windows.yml b/taskcluster/ci/build/windows.yml index 6827a32e8992..cc211ab81c0f 100755 --- a/taskcluster/ci/build/windows.yml +++ b/taskcluster/ci/build/windows.yml @@ -270,6 +270,7 @@ win32-shippable/opt: nightly: true beta: true release: true + esr.*: false default: by-project: # browser/confvars.sh looks for nightly-try diff --git a/taskcluster/ci/config.yml b/taskcluster/ci/config.yml index 2b8a2826f79a..3e0119785044 100755 --- a/taskcluster/ci/config.yml +++ b/taskcluster/ci/config.yml @@ -264,7 +264,7 @@ partner-urls: task-priority: by-project: 'mozilla-release': 'highest' - 'mozilla-esr60': 'very-high' + 'mozilla-esr.*': 'very-high' 'mozilla-beta': 'high' 'mozilla-central': 'medium' 'autoland': 'low' diff --git a/taskcluster/ci/release-early-tagging/kind.yml b/taskcluster/ci/release-early-tagging/kind.yml index 64de0ebae547..6e7622a2f8cc 100644 --- a/taskcluster/ci/release-early-tagging/kind.yml +++ b/taskcluster/ci/release-early-tagging/kind.yml @@ -27,10 +27,7 @@ job-defaults: dontbuild: true push: by-project: - mozilla-beta: true - mozilla-release: true - mozilla-esr52: true - mozilla-esr60: true + mozilla-(beta|release|esr.*): true maple: true birch: true default: false diff --git a/taskcluster/ci/release-notify-promote/kind.yml b/taskcluster/ci/release-notify-promote/kind.yml index 37058f14fb72..c7a29b98e559 100644 --- a/taskcluster/ci/release-notify-promote/kind.yml +++ b/taskcluster/ci/release-notify-promote/kind.yml @@ -34,9 +34,7 @@ job-defaults: message: "{task[shipping-product]} {release_config[version]} build{release_config[build_number]}/{config[params][project]} is in the candidates directory" emails: by-project: - mozilla-beta: ["release-signoff@mozilla.org"] - mozilla-release: ["release-signoff@mozilla.org"] - mozilla-esr60: ["release-signoff@mozilla.org"] + mozilla-(beta|release|esr.*): ["release-signoff@mozilla.org"] try: ["{config[params][owner]}"] default: [] diff --git a/taskcluster/ci/release-notify-push/kind.yml b/taskcluster/ci/release-notify-push/kind.yml index 28e09e6b6d39..8e050ae2450c 100644 --- a/taskcluster/ci/release-notify-push/kind.yml +++ b/taskcluster/ci/release-notify-push/kind.yml @@ -32,9 +32,7 @@ job-defaults: message: "{task[shipping-product]} {release_config[version]} build{release_config[build_number]}/{config[params][project]} has been pushed to cdntest" emails: by-project: - mozilla-beta: ["release-signoff@mozilla.org"] - mozilla-release: ["release-signoff@mozilla.org"] - mozilla-esr60: ["release-signoff@mozilla.org"] + mozilla-(beta|release|esr.*): ["release-signoff@mozilla.org"] try: ["{config[params][owner]}"] default: [] diff --git a/taskcluster/ci/release-notify-ship/kind.yml b/taskcluster/ci/release-notify-ship/kind.yml index dbc744e24558..a7cb09ca71dd 100644 --- a/taskcluster/ci/release-notify-ship/kind.yml +++ b/taskcluster/ci/release-notify-ship/kind.yml @@ -34,9 +34,7 @@ job-defaults: notifications: emails: by-project: - mozilla-beta: ["release-signoff@mozilla.org"] - mozilla-release: ["release-signoff@mozilla.org"] - mozilla-esr60: ["release-signoff@mozilla.org"] + mozilla-(beta|release|esr.*): ["release-signoff@mozilla.org"] try: ["{config[params][owner]}"] default: [] diff --git a/taskcluster/ci/release-notify-started/kind.yml b/taskcluster/ci/release-notify-started/kind.yml index a7be076eed13..f2c772e2e5b8 100644 --- a/taskcluster/ci/release-notify-started/kind.yml +++ b/taskcluster/ci/release-notify-started/kind.yml @@ -21,9 +21,7 @@ job-defaults: max-run-time: 600 emails: by-project: - mozilla-beta: ["release-signoff@mozilla.org"] - mozilla-release: ["release-signoff@mozilla.org"] - mozilla-esr60: ["release-signoff@mozilla.org"] + mozilla-(beta|release|esr.*): ["release-signoff@mozilla.org"] try: ["{config[params][owner]}"] default: [] diff --git a/taskcluster/ci/release-secondary-update-verify-config/kind.yml b/taskcluster/ci/release-secondary-update-verify-config/kind.yml index 5031c8d4fadf..25b68a18eab1 100644 --- a/taskcluster/ci/release-secondary-update-verify-config/kind.yml +++ b/taskcluster/ci/release-secondary-update-verify-config/kind.yml @@ -57,7 +57,7 @@ jobs: firefox-secondary-linux: treeherder: symbol: UVCS - platform: linux/opt + platform: linux-shippable/opt kind: test tier: 1 attributes: @@ -69,7 +69,7 @@ jobs: firefox-secondary-linux64: treeherder: symbol: UVCS - platform: linux64/opt + platform: linux64-shippable/opt kind: test tier: 1 attributes: @@ -93,7 +93,7 @@ jobs: firefox-secondary-win32: treeherder: symbol: UVCS - platform: win32/opt + platform: windows2012-32-shippable/opt kind: test tier: 1 attributes: @@ -105,7 +105,7 @@ jobs: firefox-secondary-win64: treeherder: symbol: UVCS - platform: win64/opt + platform: windows2012-64-shippable/opt kind: test tier: 1 attributes: @@ -117,7 +117,7 @@ jobs: firefox-secondary-win64-aarch64: treeherder: symbol: UVCS - platform: win64-aarch64/opt + platform: windows2012-aarch64-shippable/opt kind: test tier: 1 attributes: diff --git a/taskcluster/ci/release-secondary-update-verify/kind.yml b/taskcluster/ci/release-secondary-update-verify/kind.yml index c4b158a4c818..de96ce19de72 100644 --- a/taskcluster/ci/release-secondary-update-verify/kind.yml +++ b/taskcluster/ci/release-secondary-update-verify/kind.yml @@ -33,6 +33,9 @@ job-defaults: - 255 env: CHANNEL: "beta-localtest" + treeherder: + symbol: UV(UVS) + kind: test extra: chunks: 12 @@ -40,65 +43,35 @@ jobs: firefox-secondary-linux64: description: linux64 secondary channel update verify shipping-product: firefox - treeherder: - symbol: UV(UVS) - platform: linux64/opt - kind: test - tier: 1 attributes: build_platform: linux64-shippable firefox-secondary-linux: description: linux secondary channel update verify shipping-product: firefox - treeherder: - symbol: UV(UVS) - platform: linux32/opt - kind: test - tier: 1 attributes: build_platform: linux-shippable firefox-secondary-win64: description: win64 secondary channel update verify shipping-product: firefox - treeherder: - symbol: UV(UVS) - platform: windows2012-64/opt - kind: test - tier: 1 attributes: build_platform: win64-shippable firefox-secondary-win64-aarch64: description: win64 secondary channel update verify shipping-product: firefox - treeherder: - symbol: UV(UVS) - platform: windows2012-aarch6464/opt - kind: test - tier: 1 attributes: build_platform: win64-aarch64-shippable firefox-secondary-win32: description: win32 secondary channel update verify shipping-product: firefox - treeherder: - symbol: UV(UVS) - platform: windows2012-32/opt - kind: test - tier: 1 attributes: build_platform: win32-shippable firefox-secondary-macosx64: description: macosx64 secondary channel update verify shipping-product: firefox - treeherder: - symbol: UV(UVS) - platform: osx-cross/opt - kind: test - tier: 1 attributes: build_platform: macosx64-shippable diff --git a/taskcluster/ci/release-update-verify-config/kind.yml b/taskcluster/ci/release-update-verify-config/kind.yml index 5a856951d6d6..be734f98b921 100644 --- a/taskcluster/ci/release-update-verify-config/kind.yml +++ b/taskcluster/ci/release-update-verify-config/kind.yml @@ -52,7 +52,7 @@ job-defaults: by-release-type: beta: beta release(-rc)?: nonbeta - esr60: esr + esr.*: esr default: beta last-watershed: by-release-type: @@ -77,7 +77,7 @@ jobs: shipping-product: firefox treeherder: symbol: UVC - platform: linux32/opt + platform: linux32-shippable/opt kind: test tier: 1 attributes: @@ -90,7 +90,7 @@ jobs: by-release-type: beta: "beta-localtest" release(-rc)?: "release-localtest" - esr60: "esr-localtest" + esr.*: "esr-localtest" default: "default" mar-channel-id-override: by-release-type: @@ -101,7 +101,7 @@ jobs: shipping-product: firefox treeherder: symbol: UVC - platform: linux64/opt + platform: linux64-shippable/opt kind: test tier: 1 attributes: @@ -114,7 +114,7 @@ jobs: by-release-type: beta: "beta-localtest" release(-rc)?: "release-localtest" - esr60: "esr-localtest" + esr.*: "esr-localtest" default: "default" mar-channel-id-override: by-release-type: @@ -125,7 +125,7 @@ jobs: shipping-product: firefox treeherder: symbol: UVC - platform: osx-cross/opt + platform: osx-shippable/opt kind: test tier: 1 attributes: @@ -138,7 +138,7 @@ jobs: by-release-type: beta: "beta-localtest" release(-rc)?: "release-localtest" - esr60: "esr-localtest" + esr.*: "esr-localtest" default: "default" mar-channel-id-override: by-release-type: @@ -149,7 +149,7 @@ jobs: shipping-product: firefox treeherder: symbol: UVC - platform: windows2012-32/opt + platform: windows2012-32-shippable/opt kind: test tier: 1 attributes: @@ -162,7 +162,7 @@ jobs: by-release-type: beta: "beta-localtest" release(-rc)?: "release-localtest" - esr60: "esr-localtest" + esr.*: "esr-localtest" default: "default" mar-channel-id-override: by-release-type: @@ -173,7 +173,7 @@ jobs: shipping-product: firefox treeherder: symbol: UVC - platform: windows2012-64/opt + platform: windows2012-64-shippable/opt kind: test tier: 1 attributes: @@ -186,7 +186,7 @@ jobs: by-release-type: beta: "beta-localtest" release(-rc)?: "release-localtest" - esr60: "esr-localtest" + esr.*: "esr-localtest" default: "default" mar-channel-id-override: by-release-type: @@ -197,7 +197,7 @@ jobs: shipping-product: firefox treeherder: symbol: UVC - platform: windows2012-aarch64/opt + platform: windows2012-aarch64-shippable/opt kind: test tier: 1 attributes: @@ -210,7 +210,7 @@ jobs: by-release-type: beta: "beta-localtest" release(-rc)?: "release-localtest" - esr60: "esr-localtest" + esr.*: "esr-localtest" default: "default" mar-channel-id-override: by-release-type: diff --git a/taskcluster/ci/release-update-verify/kind.yml b/taskcluster/ci/release-update-verify/kind.yml index 94c8f8d938ce..5c0dee05b112 100644 --- a/taskcluster/ci/release-update-verify/kind.yml +++ b/taskcluster/ci/release-update-verify/kind.yml @@ -31,6 +31,9 @@ job-defaults: max-run-time: 5400 retry-exit-status: - 255 + treeherder: + symbol: UV(UV) + kind: test extra: chunks: 16 @@ -38,203 +41,71 @@ jobs: firefox-linux64: description: linux64 update verify shipping-product: firefox - worker: - env: - CHANNEL: - by-release-type: - beta: "beta-localtest" - release(-rc)?: "release-localtest" - esr60: "esr-localtest" - nightly: "nightly" - default: "default" - treeherder: - symbol: UV(UV) - platform: linux64/opt - kind: test - tier: 1 attributes: build_platform: linux64-shippable firefox-linux: description: linux update verify shipping-product: firefox - worker: - env: - CHANNEL: - by-release-type: - beta: "beta-localtest" - release(-rc)?: "release-localtest" - esr60: "esr-localtest" - nightly: "nightly" - default: "default" - treeherder: - symbol: UV(UV) - platform: linux32/opt - kind: test - tier: 1 attributes: build_platform: linux-shippable firefox-win64: description: win64 update verify shipping-product: firefox - worker: - env: - CHANNEL: - by-release-type: - beta: "beta-localtest" - release(-rc)?: "release-localtest" - esr60: "esr-localtest" - nightly: "nightly" - default: "default" - treeherder: - symbol: UV(UV) - platform: windows2012-64/opt - kind: test - tier: 1 attributes: build_platform: win64-shippable firefox-win64-aarch64: description: win64-aarch64 update verify shipping-product: firefox - worker: - env: - CHANNEL: - by-release-type: - beta: "beta-localtest" - release(-rc)?: "release-localtest" - esr60: "esr-localtest" - nightly: "nightly" - default: "default" - treeherder: - symbol: UV(UV) - platform: windows2012-aarch64/opt - kind: test - tier: 1 attributes: build_platform: win64-aarch64-shippable firefox-win32: description: win32 update verify shipping-product: firefox - worker: - env: - CHANNEL: - by-release-type: - beta: "beta-localtest" - release(-rc)?: "release-localtest" - esr60: "esr-localtest" - nightly: "nightly" - default: "default" - treeherder: - symbol: UV(UV) - platform: windows2012-32/opt - kind: test - tier: 1 attributes: build_platform: win32-shippable firefox-macosx64: description: macosx64 update verify shipping-product: firefox - worker: - env: - CHANNEL: - by-release-type: - beta: "beta-localtest" - release(-rc)?: "release-localtest" - esr60: "esr-localtest" - nightly: "nightly" - default: "default" - treeherder: - symbol: UV(UV) - platform: osx-cross/opt - kind: test - tier: 1 attributes: build_platform: macosx64-shippable devedition-linux64: description: linux64 update verify shipping-product: devedition - worker: - env: - CHANNEL: "aurora-localtest" - treeherder: - symbol: UV(UV) - platform: linux64-devedition/opt - kind: test - tier: 1 attributes: build_platform: linux64-devedition-nightly devedition-linux: description: linux update verify shipping-product: devedition - worker: - env: - CHANNEL: "aurora-localtest" - treeherder: - symbol: UV(UV) - platform: linux32-devedition/opt - kind: test - tier: 1 attributes: build_platform: linux-devedition-nightly devedition-win64: description: win64 update verify shipping-product: devedition - worker: - env: - CHANNEL: "aurora-localtest" - treeherder: - symbol: UV(UV) - platform: windows2012-64-devedition/opt - kind: test - tier: 1 attributes: build_platform: win64-devedition-nightly devedition-win64-aarch64: description: win64-aarch64 update verify shipping-product: devedition - worker: - env: - CHANNEL: "aurora-localtest" - treeherder: - symbol: UV(UV) - platform: windows2012-aarch64-devedition/opt - kind: test - tier: 1 attributes: build_platform: win64-aarch64-devedition-nightly devedition-win32: description: win32 update verify shipping-product: devedition - worker: - env: - CHANNEL: "aurora-localtest" - treeherder: - symbol: UV(UV) - platform: windows2012-32-devedition/opt - kind: test - tier: 1 attributes: build_platform: win32-devedition-nightly devedition-macosx64: description: macosx64 update verify shipping-product: devedition - worker: - env: - CHANNEL: "aurora-localtest" - treeherder: - symbol: UV(UV) - platform: osx-cross-devedition/opt - kind: test - tier: 1 attributes: build_platform: macosx64-devedition-nightly diff --git a/taskcluster/ci/release-version-bump/kind.yml b/taskcluster/ci/release-version-bump/kind.yml index e1463748f46d..ce6d0c13a00c 100644 --- a/taskcluster/ci/release-version-bump/kind.yml +++ b/taskcluster/ci/release-version-bump/kind.yml @@ -31,15 +31,7 @@ job-defaults: bump-files: by-project: default: ["browser/config/version_display.txt"] - mozilla-release: - - "browser/config/version.txt" - - "browser/config/version_display.txt" - - "config/milestone.txt" - mozilla-esr52: - - "browser/config/version.txt" - - "browser/config/version_display.txt" - - "config/milestone.txt" - mozilla-esr60: + mozilla-(release|esr.*): - "browser/config/version.txt" - "browser/config/version_display.txt" - "config/milestone.txt" @@ -49,10 +41,7 @@ job-defaults: - "config/milestone.txt" push: by-project: - mozilla-beta: true - mozilla-release: true - mozilla-esr52: true - mozilla-esr60: true + mozilla-(beta|release|esr.*): true maple: true birch: true jamun: true diff --git a/taskcluster/ci/repo-update/kind.yml b/taskcluster/ci/repo-update/kind.yml index 5b6a097b1be4..2d7846b634b4 100644 --- a/taskcluster/ci/repo-update/kind.yml +++ b/taskcluster/ci/repo-update/kind.yml @@ -14,35 +14,23 @@ job-defaults: env: DO_HSTS: by-project: - mozilla-central: "1" - mozilla-esr60: "1" - mozilla-beta: "1" + mozilla-(central|beta|esr.*): "1" default: "" DO_HPKP: by-project: - mozilla-central: "1" - mozilla-esr60: "1" - mozilla-beta: "1" + mozilla-(central|beta|esr.*): "1" default: "" DO_BLOCKLIST: by-project: - mozilla-central: "1" - mozilla-esr60: "1" - mozilla-beta: "1" - mozilla-release: "1" + mozilla-(central|beta|release|esr.*): "1" default: "" DO_REMOTE_SETTINGS: by-project: - mozilla-central: "1" - mozilla-esr60: "1" - mozilla-beta: "1" - mozilla-release: "1" + mozilla-(central|beta|release|esr.*): "1" default: "" DO_SUFFIX_LIST: by-project: - mozilla-central: "1" - mozilla-esr60: "1" - mozilla-beta: "1" + mozilla-(central|beta|esr.*): "1" default: "" USE_MOZILLA_CENTRAL: by-project: diff --git a/taskcluster/docs/parameters.rst b/taskcluster/docs/parameters.rst index 10120432b2bf..fa9d16678468 100644 --- a/taskcluster/docs/parameters.rst +++ b/taskcluster/docs/parameters.rst @@ -156,7 +156,7 @@ Release Promotion Specify the next version for version bump tasks. ``release_type`` - The type of release being promoted. One of "nightly", "beta", "esr60", "release-rc", or "release". + The type of release being promoted. One of "nightly", "beta", "esr60", "esr68", "release-rc", or "release". ``release_eta`` The time and date when a release is scheduled to live. This value is passed to Balrog. diff --git a/taskcluster/scripts/run-task b/taskcluster/scripts/run-task index 0f8d7007f069..98c57bdebdcc 100755 --- a/taskcluster/scripts/run-task +++ b/taskcluster/scripts/run-task @@ -27,6 +27,7 @@ import errno import io import json import os +import platform import random import re import shutil @@ -37,7 +38,6 @@ import subprocess import urllib.error import urllib.request - FINGERPRINT_URL = 'http://taskcluster/secrets/v1/secret/project/taskcluster/gecko/hgfingerprint' FALLBACK_FINGERPRINT = { 'fingerprints': @@ -405,7 +405,12 @@ def vcs_checkout(source_repo, dest, store_path, sys.exit(1) if IS_MACOSX: + release = platform.mac_ver() + versionNums = release[0].split('.')[:2] + os_version = "%s.%s" % (versionNums[0], versionNums[1]) hg_bin = '/tools/python27-mercurial/bin/hg' + if os_version == "10.14": + hg_bin = 'hg' elif IS_POSIX: hg_bin = 'hg' elif IS_WINDOWS: diff --git a/taskcluster/taskgraph/decision.py b/taskcluster/taskgraph/decision.py index 8fec64cd0794..6dc3dc50fed6 100644 --- a/taskcluster/taskgraph/decision.py +++ b/taskcluster/taskgraph/decision.py @@ -82,6 +82,11 @@ PER_PROJECT_PARAMETERS = { 'release_type': 'esr60', }, + 'mozilla-esr68': { + 'target_tasks_method': 'mozilla_esr68_tasks', + 'release_type': 'esr68', + }, + 'comm-central': { 'target_tasks_method': 'default', 'release_type': 'nightly', @@ -97,6 +102,11 @@ PER_PROJECT_PARAMETERS = { 'release_type': 'release', }, + 'comm-esr68': { + 'target_tasks_method': 'mozilla_esr68_tasks', + 'release_type': 'release', + }, + 'pine': { 'target_tasks_method': 'pine_tasks', }, diff --git a/taskcluster/taskgraph/task.py b/taskcluster/taskgraph/task.py index 74c12c16dc0e..3bdd81667d5f 100644 --- a/taskcluster/taskgraph/task.py +++ b/taskcluster/taskgraph/task.py @@ -46,6 +46,15 @@ class Task(object): def __attrs_post_init__(self): self.attributes['kind'] = self.kind + @property + def name(self): + if self.label.startswith(self.kind + "-"): + return self.label[len(self.kind)+1:] + elif self.label.startswith("build-docker-image-"): + return self.label[len("build-docker-image-"):] + else: + raise AttributeError("Task {} does not have a name.".format(self.label)) + def to_json(self): rv = { 'kind': self.kind, diff --git a/taskcluster/taskgraph/test/python.ini b/taskcluster/taskgraph/test/python.ini index 135961b73a11..f994526162a9 100644 --- a/taskcluster/taskgraph/test/python.ini +++ b/taskcluster/taskgraph/test/python.ini @@ -14,6 +14,7 @@ skip-if = python == 3 [test_parameters.py] [test_target_tasks.py] [test_taskgraph.py] +[test_taskcluster_yml.py] [test_transforms_base.py] [test_transforms_job.py] [test_try_option_syntax.py] diff --git a/taskcluster/taskgraph/test/test_taskcluster_yml.py b/taskcluster/taskgraph/test/test_taskcluster_yml.py new file mode 100644 index 000000000000..a2e5c6d95147 --- /dev/null +++ b/taskcluster/taskgraph/test/test_taskcluster_yml.py @@ -0,0 +1,118 @@ +# 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/. + +from __future__ import absolute_import, unicode_literals + +import jsone +import pprint +import slugid +import unittest + +from mozunit import main + +from taskgraph.util.yaml import load_yaml +from taskgraph.util.time import current_json_time +from taskgraph import GECKO + + +class TestTaskclusterYml(unittest.TestCase): + + taskcluster_yml = load_yaml(GECKO, ".taskcluster.yml") + + def test_push(self): + context = { + "tasks_for": "hg-push", + "push": { + "revision": "e8d2d9aff5026ef1f1777b781b47fdcbdb9d8f20", + "owner": "dustin@mozilla.com", + "pushlog_id": 1556565286, + "pushdate": 112957, + }, + "repository": { + "url": "https://hg.mozilla.org/mozilla-central", + "project": "mozilla-central", + "level": "3", + }, + "ownTaskId": slugid.nice().encode("ascii"), + } + rendered = jsone.render(self.taskcluster_yml, context) + pprint.pprint(rendered) + self.assertEqual( + rendered["tasks"][0]["metadata"]["name"], "Gecko Decision Task" + ) + + def test_cron(self): + context = { + "tasks_for": "cron", + "repository": { + "url": "https://hg.mozilla.org/mozilla-central", + "project": "mozilla-central", + "level": 3, + }, + "push": { + "revision": "e8aebe488b2f2e567940577de25013d00e818f7c", + "pushlog_id": -1, + "pushdate": 0, + "owner": "cron", + }, + "cron": { + "task_id": "", + "job_name": "test", + "job_symbol": "T", + "quoted_args": "abc def", + }, + "now": current_json_time(), + "ownTaskId": slugid.nice().encode("ascii"), + } + rendered = jsone.render(self.taskcluster_yml, context) + pprint.pprint(rendered) + self.assertEqual( + rendered["tasks"][0]["metadata"]["name"], "Decision Task for cron job test" + ) + + def test_action(self): + context = { + "tasks_for": "action", + "repository": { + "url": "https://hg.mozilla.org/mozilla-central", + "project": "mozilla-central", + "level": 3, + }, + "push": { + "revision": "e8d2d9aff5026ef1f1777b781b47fdcbdb9d8f20", + "owner": "dustin@mozilla.com", + "pushlog_id": 1556565286, + "pushdate": 112957, + }, + "action": { + "name": "test-action", + "title": "Test Action", + "description": "Just testing", + "taskGroupId": slugid.nice().encode("ascii"), + "symbol": "t", + "repo_scope": "assume:repo:hg.mozilla.org/try:action:generic", + "cb_name": "test_action", + }, + "input": {}, + "parameters": {}, + "now": current_json_time(), + "taskId": slugid.nice().encode("ascii"), + "ownTaskId": slugid.nice().encode("ascii"), + "clientId": "testing/testing/testing", + } + rendered = jsone.render(self.taskcluster_yml, context) + pprint.pprint(rendered) + self.assertEqual( + rendered["tasks"][0]["metadata"]["name"], "Action: Test Action" + ) + + def test_unknown(self): + context = {"tasks_for": "bitkeeper-push"} + rendered = jsone.render(self.taskcluster_yml, context) + pprint.pprint(rendered) + self.assertEqual(rendered["tasks"], []) + + +if __name__ == "__main__": + main() diff --git a/taskcluster/taskgraph/transforms/beetmover_langpack_checksums.py b/taskcluster/taskgraph/transforms/beetmover_langpack_checksums.py index 68d087a7adab..d5f4b7f7c709 100644 --- a/taskcluster/taskgraph/transforms/beetmover_langpack_checksums.py +++ b/taskcluster/taskgraph/transforms/beetmover_langpack_checksums.py @@ -17,6 +17,7 @@ from taskgraph.util.scriptworker import (generate_beetmover_artifact_map, get_beetmover_bucket_scope, get_worker_type_for_scope, should_use_artifact_map) +from taskgraph.util.treeherder import inherit_treeherder_from_dep from taskgraph.transforms.task import task_description_schema from voluptuous import Required, Optional @@ -40,17 +41,11 @@ def make_beetmover_checksums_description(config, jobs): dep_job = job['primary-dependency'] attributes = dep_job.attributes - treeherder = job.get('treeherder', {}) + treeherder = inherit_treeherder_from_dep(job, dep_job) treeherder.setdefault( 'symbol', 'BMcslang(N{})'.format(attributes.get('l10n_chunk', '')) ) - dep_th_platform = dep_job.task.get('extra', {}).get( - 'treeherder', {}).get('machine', {}).get('platform', '') - treeherder.setdefault('platform', - "{}/opt".format(dep_th_platform)) - treeherder.setdefault('tier', 1) - treeherder.setdefault('kind', 'build') label = job['label'] build_platform = attributes.get('build_platform') diff --git a/taskcluster/taskgraph/transforms/job/mach.py b/taskcluster/taskgraph/transforms/job/mach.py index 8b8f92d98631..0ae0624346d8 100644 --- a/taskcluster/taskgraph/transforms/job/mach.py +++ b/taskcluster/taskgraph/transforms/job/mach.py @@ -44,6 +44,9 @@ def configure_mach(config, job, taskdesc): run = job['run'] command_prefix = 'cd $GECKO_PATH && ./mach ' + if job['worker-type'].endswith('1014'): + command_prefix = 'cd $GECKO_PATH && LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 ./mach ' + mach = run['mach'] if isinstance(mach, dict): ref, pattern = next(iter(mach.items())) diff --git a/taskcluster/taskgraph/transforms/job/python_test.py b/taskcluster/taskgraph/transforms/job/python_test.py index 23395475371b..8c9828118720 100644 --- a/taskcluster/taskgraph/transforms/job/python_test.py +++ b/taskcluster/taskgraph/transforms/job/python_test.py @@ -40,6 +40,8 @@ def configure_python_test(config, job, taskdesc): if worker['os'] == 'macosx' and run['python-version'] == 3: # OSX hosts can't seem to find python 3 on their own run['python-version'] = '/tools/python36/bin/python3.6' + if job['worker-type'].endswith('1014'): + run['python-version'] = '/usr/local/bin/python3' # defer to the mach implementation run['mach'] = 'python-test --python {python-version} --subsuite {subsuite}'.format(**run) diff --git a/taskcluster/taskgraph/transforms/job/run_task.py b/taskcluster/taskgraph/transforms/job/run_task.py index a2fa4227b857..46ca7483e4f4 100644 --- a/taskcluster/taskgraph/transforms/job/run_task.py +++ b/taskcluster/taskgraph/transforms/job/run_task.py @@ -130,6 +130,8 @@ def generic_worker_run_task(config, job, taskdesc): command = ['C:/mozilla-build/python3/python3.exe', 'run-task'] elif is_mac: command = ['/tools/python36/bin/python3.6', 'run-task'] + if job['worker-type'].endswith('1014'): + command = ['/usr/local/bin/python3', 'run-task'] else: command = ['./run-task'] diff --git a/taskcluster/taskgraph/transforms/l10n.py b/taskcluster/taskgraph/transforms/l10n.py index 8c1391c846a2..a7d0bbda5bf9 100644 --- a/taskcluster/taskgraph/transforms/l10n.py +++ b/taskcluster/taskgraph/transforms/l10n.py @@ -187,8 +187,7 @@ def setup_name(config, jobs): dep = job['primary-dependency'] # Set the name to the same as the dep task, without kind name. # Label will get set automatically with this kinds name. - job['name'] = job.get('name', - dep.task['metadata']['name'][len(dep.kind) + 1:]) + job['name'] = job.get('name', dep.name) yield job diff --git a/taskcluster/taskgraph/transforms/release_beetmover_signed_addons.py b/taskcluster/taskgraph/transforms/release_beetmover_signed_addons.py index 5d167a5e64e5..7b50aaa48cd9 100644 --- a/taskcluster/taskgraph/transforms/release_beetmover_signed_addons.py +++ b/taskcluster/taskgraph/transforms/release_beetmover_signed_addons.py @@ -17,6 +17,7 @@ from taskgraph.util.scriptworker import (get_beetmover_bucket_scope, generate_beetmover_upstream_artifacts, generate_beetmover_artifact_map, should_use_artifact_map) +from taskgraph.util.treeherder import inherit_treeherder_from_dep from taskgraph.transforms.task import task_description_schema from taskgraph.transforms.release_sign_and_push_langpacks import get_upstream_task_ref from voluptuous import Required, Optional @@ -89,14 +90,8 @@ def make_task_description(config, jobs): dep_job = job['primary-dependency'] attributes = dep_job.attributes - treeherder = job.get('treeherder', {}) + treeherder = inherit_treeherder_from_dep(job, dep_job) treeherder.setdefault('symbol', 'langpack(BM{})'.format(attributes.get('l10n_chunk', ''))) - dep_th_platform = dep_job.task.get('extra', {}).get( - 'treeherder', {}).get('machine', {}).get('platform', '') - treeherder.setdefault('platform', - "{}/opt".format(dep_th_platform)) - treeherder.setdefault('tier', 1) - treeherder.setdefault('kind', 'build') job['attributes'].update(copy_attributes_from_dependent_job(dep_job)) job['attributes']['chunk_locales'] = dep_job.attributes['chunk_locales'] diff --git a/taskcluster/taskgraph/transforms/release_sign_and_push_langpacks.py b/taskcluster/taskgraph/transforms/release_sign_and_push_langpacks.py index 89de71106cb4..9a5b358d1ed4 100644 --- a/taskcluster/taskgraph/transforms/release_sign_and_push_langpacks.py +++ b/taskcluster/taskgraph/transforms/release_sign_and_push_langpacks.py @@ -11,6 +11,7 @@ from taskgraph.loader.single_dep import schema from taskgraph.transforms.base import TransformSequence from taskgraph.util.attributes import copy_attributes_from_dependent_job from taskgraph.util.schema import resolve_keyed_by, optionally_keyed_by +from taskgraph.util.treeherder import inherit_treeherder_from_dep from taskgraph.transforms.task import task_description_schema from voluptuous import Any, Required @@ -103,15 +104,10 @@ def make_task_description(config, jobs): for job in jobs: dep_job = job['primary-dependency'] - treeherder = job.get('treeherder', {}) + treeherder = inherit_treeherder_from_dep(job, dep_job) treeherder.setdefault('symbol', 'langpack(SnP{})'.format( job['attributes'].get('l10n_chunk', '') )) - dep_th_platform = dep_job.task.get('extra', {}).get( - 'treeherder', {}).get('machine', {}).get('platform', '') - treeherder.setdefault('platform', '{}/opt'.format(dep_th_platform)) - treeherder.setdefault('tier', 1) - treeherder.setdefault('kind', 'build') job['description'] = job['description'].format( locales='/'.join(job['attributes']['chunk_locales']), diff --git a/taskcluster/taskgraph/transforms/update_verify.py b/taskcluster/taskgraph/transforms/update_verify.py index 9940b27aa3b4..5080f543719a 100644 --- a/taskcluster/taskgraph/transforms/update_verify.py +++ b/taskcluster/taskgraph/transforms/update_verify.py @@ -10,16 +10,28 @@ from __future__ import absolute_import, print_function, unicode_literals from copy import deepcopy from taskgraph.transforms.base import TransformSequence -from taskgraph.util.schema import resolve_keyed_by -from taskgraph.util.treeherder import add_suffix +from taskgraph.util.treeherder import add_suffix, inherit_treeherder_from_dep transforms = TransformSequence() @transforms.add def add_command(config, tasks): + config_tasks = {} + for dep in config.kind_dependencies_tasks: + if 'update-verify-config' in dep.kind: + config_tasks[dep.name] = dep + for task in tasks: + config_task = config_tasks[task['name']] total_chunks = task["extra"]["chunks"] + task['worker'].setdefault('env', {}).update( + CHANNEL=config_task.task['extra']['channel'], + ) + task.setdefault('fetches', {})[config_task.label] = [ + "update-verify.cfg", + ] + task['treeherder'] = inherit_treeherder_from_dep(task, config_task) for this_chunk in range(1, total_chunks+1): chunked = deepcopy(task) @@ -40,23 +52,5 @@ def add_command(config, tasks): ), 'sparse-profile': 'update-verify', } - for thing in ("CHANNEL", "VERIFY_CONFIG"): - thing = "worker.env.{}".format(thing) - resolve_keyed_by( - chunked, thing, thing, - **{ - 'project': config.params['project'], - 'release-type': config.params['release_type'], - } - ) - - for upstream in chunked.get("dependencies", {}).keys(): - if 'update-verify-config' in upstream: - chunked.setdefault('fetches', {})[upstream] = [ - "update-verify.cfg", - ] - break - else: - raise Exception("Couldn't find upate verify config") yield chunked diff --git a/taskcluster/taskgraph/util/attributes.py b/taskcluster/taskgraph/util/attributes.py index 1196e1658a6f..6691d4b8bf68 100644 --- a/taskcluster/taskgraph/util/attributes.py +++ b/taskcluster/taskgraph/util/attributes.py @@ -19,9 +19,11 @@ RELEASE_PROJECTS = { 'mozilla-beta', 'mozilla-release', 'mozilla-esr60', + 'mozilla-esr68', 'comm-central', 'comm-beta', 'comm-esr60', + 'comm-esr68', 'oak', } diff --git a/taskcluster/taskgraph/util/scriptworker.py b/taskcluster/taskgraph/util/scriptworker.py index 04899ddbb840..4236bcc76fc1 100644 --- a/taskcluster/taskgraph/util/scriptworker.py +++ b/taskcluster/taskgraph/util/scriptworker.py @@ -58,6 +58,7 @@ SIGNING_SCOPE_ALIAS_TO_PROJECT = [[ 'mozilla-beta', 'mozilla-release', 'mozilla-esr60', + 'mozilla-esr68', 'comm-beta', 'comm-esr60', ]) @@ -95,8 +96,10 @@ BEETMOVER_SCOPE_ALIAS_TO_PROJECT = [[ 'mozilla-beta', 'mozilla-release', 'mozilla-esr60', + 'mozilla-esr68', 'comm-beta', 'comm-esr60', + 'comm-esr68', ]) ]] @@ -145,8 +148,9 @@ BALROG_SCOPE_ALIAS_TO_PROJECT = [[ 'comm-esr60', ]) ], [ - 'esr', set([ - 'mozilla-esr52', + 'esr68', set([ + 'mozilla-esr68', + 'comm-esr68', ]) ]] @@ -157,8 +161,8 @@ BALROG_SERVER_SCOPES = { 'aurora': 'balrog:server:aurora', 'beta': 'balrog:server:beta', 'release': 'balrog:server:release', - 'esr': 'balrog:server:esr', 'esr60': 'balrog:server:esr', + 'esr68': 'balrog:server:esr', 'default': 'balrog:server:dep', } diff --git a/taskcluster/taskgraph/util/workertypes.py b/taskcluster/taskgraph/util/workertypes.py index 957011ccc34e..635f68833796 100644 --- a/taskcluster/taskgraph/util/workertypes.py +++ b/taskcluster/taskgraph/util/workertypes.py @@ -6,7 +6,9 @@ from __future__ import absolute_import, print_function, unicode_literals from mozbuild.util import memoize +from .taskcluster import get_root_url from .keyed_by import evaluate_keyed_by +from .attributes import keymatch WORKER_TYPES = { 'gce/gecko-1-b-linux': ('docker-worker', 'linux'), @@ -30,41 +32,69 @@ WORKER_TYPES = { } +@memoize +def _get(graph_config, alias, level): + """Get the configuration for this worker_type alias: {provisioner, + worker-type, implementation, os}""" + level = str(level) + + # handle the legacy (non-alias) format + if '/' in alias: + alias = alias.format(level=level) + provisioner, worker_type = alias.split("/", 1) + try: + implementation, os = WORKER_TYPES[alias] + return { + 'provisioner': provisioner, + 'worker-type': worker_type, + 'implementation': implementation, + 'os': os, + } + except KeyError: + return { + 'provisioner': provisioner, + 'worker-type': worker_type, + } + + matches = keymatch(graph_config['workers']['aliases'], alias) + if len(matches) > 1: + raise KeyError("Multiple matches for worker-type alias " + alias) + elif not matches: + raise KeyError("No matches for worker-type alias " + alias) + worker_config = matches[0].copy() + + worker_config['worker-type'] = evaluate_keyed_by( + worker_config['worker-type'], + "worker-type alias {} field worker-type".format(alias), + {"level": level}).format(level=level, alias=alias) + + return worker_config + + @memoize def worker_type_implementation(graph_config, worker_type): """Get the worker implementation and OS for the given workerType, where the OS represents the host system, not the target OS, in the case of cross-compiles.""" - if '/' in worker_type: - worker_type = worker_type.replace('{level}', '1') - return WORKER_TYPES[worker_type] - else: - worker_config = evaluate_keyed_by( - {"by-worker-type": graph_config["workers"]["aliases"]}, - "worker-types.yml", - {'worker-type': worker_type}, - ) - return worker_config['implementation'], worker_config['os'] + worker_config = _get(graph_config, worker_type, '1') + return worker_config['implementation'], worker_config['os'] @memoize def get_worker_type(graph_config, worker_type, level): """ - Get the worker type based, evaluating aliases from the graph config. + Get the worker type provisioner and worker-type, optionally evaluating + aliases from the graph config. """ - level = str(level) - if '/' in worker_type: - worker_type = worker_type.format(level=level) - return worker_type.split("/", 1) - else: - worker_config = evaluate_keyed_by( - {"by-worker-type": graph_config["workers"]["aliases"]}, - "worker-types.yml", - {"worker-type": worker_type}, - ) - worker_type = evaluate_keyed_by( - worker_config["worker-type"], - worker_type, - {"level": level}, - ).format(level=level, alias=worker_type) - return worker_config["provisioner"], worker_type + worker_config = _get(graph_config, worker_type, level) + + # translate the provisionerId to 'ec2' everywhere but the original + # https://taskcluster.net deployment. Once that deployment is no longer in + # use, this can be removed and all corresponding provisioners changed to + # `ec2` + root_url = get_root_url(False) + provisioner = worker_config["provisioner"] + if root_url != 'https://taskcluster.net' and provisioner == 'aws-provisioner-v1': + provisioner = 'ec2' + + return provisioner, worker_config['worker-type'] diff --git a/testing/mochitest/runtests.py b/testing/mochitest/runtests.py index 84edc6d006ba..9745de592496 100644 --- a/testing/mochitest/runtests.py +++ b/testing/mochitest/runtests.py @@ -622,6 +622,9 @@ class SSLTunnel: if option in ( 'tls1', + 'tls1_1', + 'tls1_2', + 'tls1_3', 'ssl3', 'rc4', 'failHandshake'): diff --git a/testing/mochitest/runtestsremote.py b/testing/mochitest/runtestsremote.py index 2251eed8f5fd..ac117153abca 100644 --- a/testing/mochitest/runtestsremote.py +++ b/testing/mochitest/runtestsremote.py @@ -382,7 +382,7 @@ def run_test_harness(parser, options): retVal = 1 if not device_exception and options.log_mach is None and not options.verify: - mochitest.printDeviceInfo(printLogcat=True) + mochitest.printDeviceInfo(printLogcat=(retVal != 0)) mochitest.archiveMozLogs() mochitest.message_logger.finish() diff --git a/testing/mochitest/ssltunnel/ssltunnel.cpp b/testing/mochitest/ssltunnel/ssltunnel.cpp index a224ac98a9d9..b8ce759de541 100644 --- a/testing/mochitest/ssltunnel/ssltunnel.cpp +++ b/testing/mochitest/ssltunnel/ssltunnel.cpp @@ -142,6 +142,9 @@ typedef struct { PLHashTable* host_redir_table; PLHashTable* host_ssl3_table; PLHashTable* host_tls1_table; + PLHashTable* host_tls11_table; + PLHashTable* host_tls12_table; + PLHashTable* host_tls13_table; PLHashTable* host_rc4_table; PLHashTable* host_failhandshake_table; } server_info_t; @@ -243,7 +246,10 @@ enum { USE_SSL3 = 1 << 0, USE_RC4 = 1 << 1, FAIL_HANDSHAKE = 1 << 2, - USE_TLS1 = 1 << 4 + USE_TLS1 = 1 << 3, + USE_TLS1_1 = 1 << 4, + USE_TLS1_2 = 1 << 5, + USE_TLS1_3 = 1 << 6 }; bool ReadConnectRequest(server_info_t* server_info, relayBuffer& buffer, @@ -307,6 +313,18 @@ bool ReadConnectRequest(server_info_t* server_info, relayBuffer& buffer, *flags |= USE_TLS1; } + if (PL_HashTableLookup(server_info->host_tls11_table, token)) { + *flags |= USE_TLS1_1; + } + + if (PL_HashTableLookup(server_info->host_tls12_table, token)) { + *flags |= USE_TLS1_2; + } + + if (PL_HashTableLookup(server_info->host_tls13_table, token)) { + *flags |= USE_TLS1_3; + } + if (PL_HashTableLookup(server_info->host_failhandshake_table, token)) { *flags |= FAIL_HANDSHAKE; } @@ -368,15 +386,34 @@ bool ConfigureSSLServerSocket(PRFileDesc* socket, server_info_t* si, SSL_OptionSet(ssl_socket, SSL_REQUIRE_CERTIFICATE, clientAuth == caRequire); } + SSLVersionRange range = {SSL_LIBRARY_VERSION_TLS_1_3, + SSL_LIBRARY_VERSION_3_0}; if (flags & USE_SSL3) { - SSLVersionRange range = {SSL_LIBRARY_VERSION_3_0, SSL_LIBRARY_VERSION_3_0}; - SSL_VersionRangeSet(ssl_socket, &range); + range.min = PR_MIN(range.min, SSL_LIBRARY_VERSION_3_0); + range.max = PR_MAX(range.max, SSL_LIBRARY_VERSION_3_0); } - if (flags & USE_TLS1) { - SSLVersionRange range = {SSL_LIBRARY_VERSION_TLS_1_0, - SSL_LIBRARY_VERSION_TLS_1_0}; - SSL_VersionRangeSet(ssl_socket, &range); + range.min = PR_MIN(range.min, SSL_LIBRARY_VERSION_TLS_1_0); + range.max = PR_MAX(range.max, SSL_LIBRARY_VERSION_TLS_1_0); + } + if (flags & USE_TLS1_1) { + range.min = PR_MIN(range.min, SSL_LIBRARY_VERSION_TLS_1_1); + range.max = PR_MAX(range.max, SSL_LIBRARY_VERSION_TLS_1_1); + } + if (flags & USE_TLS1_2) { + range.min = PR_MIN(range.min, SSL_LIBRARY_VERSION_TLS_1_2); + range.max = PR_MAX(range.max, SSL_LIBRARY_VERSION_TLS_1_2); + } + if (flags & USE_TLS1_3) { + range.min = PR_MIN(range.min, SSL_LIBRARY_VERSION_TLS_1_3); + range.max = PR_MAX(range.max, SSL_LIBRARY_VERSION_TLS_1_3); + } + // Set the valid range, if any were specified (if not, skip + // when the default range is invalid, i.e. max > min) + if (range.min <= range.max && + SSL_VersionRangeSet(ssl_socket, &range) != SECSuccess) { + LOG_ERROR(("Error configuring SSL socket version range\n")); + return false; } if (flags & USE_RC4) { @@ -701,6 +738,12 @@ void HandleConnection(void* data) { match_hostname, &match); PL_HashTableEnumerateEntries(ci->server_info->host_tls1_table, match_hostname, &match); + PL_HashTableEnumerateEntries(ci->server_info->host_tls11_table, + match_hostname, &match); + PL_HashTableEnumerateEntries(ci->server_info->host_tls12_table, + match_hostname, &match); + PL_HashTableEnumerateEntries(ci->server_info->host_tls13_table, + match_hostname, &match); PL_HashTableEnumerateEntries(ci->server_info->host_rc4_table, match_hostname, &match); PL_HashTableEnumerateEntries( @@ -960,6 +1003,18 @@ PLHashTable* get_tls1_table(server_info_t* server) { return server->host_tls1_table; } +PLHashTable* get_tls11_table(server_info_t* server) { + return server->host_tls11_table; +} + +PLHashTable* get_tls12_table(server_info_t* server) { + return server->host_tls12_table; +} + +PLHashTable* get_tls13_table(server_info_t* server) { + return server->host_tls13_table; +} + PLHashTable* get_rc4_table(server_info_t* server) { return server->host_rc4_table; } @@ -1016,7 +1071,6 @@ int processConfigLine(char* configLine) { char* _caret; char* keyword = strtok2(configLine, ":", &_caret); - // Configure usage of http/ssl tunneling proxy behavior if (!strcmp(keyword, "httpproxy")) { char* value = strtok2(_caret, ":", &_caret); @@ -1136,7 +1190,7 @@ int processConfigLine(char* configLine) { server.host_ssl3_table = PL_NewHashTable(0, PL_HashString, PL_CompareStrings, PL_CompareStrings, nullptr, nullptr); - ; + if (!server.host_ssl3_table) { LOG_ERROR(("Internal, could not create hash table\n")); return 1; @@ -1145,12 +1199,39 @@ int processConfigLine(char* configLine) { server.host_tls1_table = PL_NewHashTable(0, PL_HashString, PL_CompareStrings, PL_CompareStrings, nullptr, nullptr); - ; + if (!server.host_tls1_table) { LOG_ERROR(("Internal, could not create hash table\n")); return 1; } + server.host_tls11_table = + PL_NewHashTable(0, PL_HashString, PL_CompareStrings, + PL_CompareStrings, nullptr, nullptr); + + if (!server.host_tls11_table) { + LOG_ERROR(("Internal, could not create hash table\n")); + return 1; + } + + server.host_tls12_table = + PL_NewHashTable(0, PL_HashString, PL_CompareStrings, + PL_CompareStrings, nullptr, nullptr); + + if (!server.host_tls12_table) { + LOG_ERROR(("Internal, could not create hash table\n")); + return 1; + } + + server.host_tls13_table = + PL_NewHashTable(0, PL_HashString, PL_CompareStrings, + PL_CompareStrings, nullptr, nullptr); + + if (!server.host_tls13_table) { + LOG_ERROR(("Internal, could not create hash table\n")); + return 1; + } + server.host_rc4_table = PL_NewHashTable(0, PL_HashString, PL_CompareStrings, PL_CompareStrings, nullptr, nullptr); @@ -1293,6 +1374,15 @@ int processConfigLine(char* configLine) { if (!strcmp(keyword, "tls1")) { return parseWeakCryptoConfig(keyword, _caret, get_tls1_table); } + if (!strcmp(keyword, "tls1_1")) { + return parseWeakCryptoConfig(keyword, _caret, get_tls11_table); + } + if (!strcmp(keyword, "tls1_2")) { + return parseWeakCryptoConfig(keyword, _caret, get_tls12_table); + } + if (!strcmp(keyword, "tls1_3")) { + return parseWeakCryptoConfig(keyword, _caret, get_tls13_table); + } if (!strcmp(keyword, "rc4")) { return parseWeakCryptoConfig(keyword, _caret, get_rc4_table); @@ -1384,7 +1474,7 @@ int freeSSL3HashItems(PLHashEntry* he, int i, void* arg) { return HT_ENUMERATE_REMOVE; } -int freeTLS1HashItems(PLHashEntry* he, int i, void* arg) { +int freeTLSHashItems(PLHashEntry* he, int i, void* arg) { delete[](char*) he->key; return HT_ENUMERATE_REMOVE; } @@ -1536,7 +1626,13 @@ int main(int argc, char** argv) { freeHostRedirHashItems, nullptr); PL_HashTableEnumerateEntries(server.host_ssl3_table, freeSSL3HashItems, nullptr); - PL_HashTableEnumerateEntries(server.host_tls1_table, freeTLS1HashItems, + PL_HashTableEnumerateEntries(server.host_tls1_table, freeTLSHashItems, + nullptr); + PL_HashTableEnumerateEntries(server.host_tls11_table, freeTLSHashItems, + nullptr); + PL_HashTableEnumerateEntries(server.host_tls12_table, freeTLSHashItems, + nullptr); + PL_HashTableEnumerateEntries(server.host_tls13_table, freeTLSHashItems, nullptr); PL_HashTableEnumerateEntries(server.host_rc4_table, freeRC4HashItems, nullptr); @@ -1547,6 +1643,9 @@ int main(int argc, char** argv) { PL_HashTableDestroy(server.host_redir_table); PL_HashTableDestroy(server.host_ssl3_table); PL_HashTableDestroy(server.host_tls1_table); + PL_HashTableDestroy(server.host_tls11_table); + PL_HashTableDestroy(server.host_tls12_table); + PL_HashTableDestroy(server.host_tls13_table); PL_HashTableDestroy(server.host_rc4_table); PL_HashTableDestroy(server.host_failhandshake_table); } diff --git a/testing/web-platform/meta/css/CSS2/linebox/vertical-align-109.xht.ini b/testing/web-platform/meta/css/CSS2/linebox/vertical-align-109.xht.ini new file mode 100644 index 000000000000..58cf8577092f --- /dev/null +++ b/testing/web-platform/meta/css/CSS2/linebox/vertical-align-109.xht.ini @@ -0,0 +1,3 @@ +[vertical-align-109.xht] + disabled: + if (os == "android") and e10s: bug 1550895 (frequently fails on geckoview) diff --git a/testing/web-platform/meta/css/css-backgrounds/background-size/background-size-cover-svg.html.ini b/testing/web-platform/meta/css/css-backgrounds/background-size/background-size-cover-svg.html.ini new file mode 100644 index 000000000000..da48a868e781 --- /dev/null +++ b/testing/web-platform/meta/css/css-backgrounds/background-size/background-size-cover-svg.html.ini @@ -0,0 +1,3 @@ +[background-size-cover-svg.html] + disabled: + if (os == "android") and e10s: bug 1550895 (frequently fails on geckoview) diff --git a/testing/web-platform/meta/css/css-grid/grid-model/grid-areas-overflowing-grid-container-001.html.ini b/testing/web-platform/meta/css/css-grid/grid-model/grid-areas-overflowing-grid-container-001.html.ini new file mode 100644 index 000000000000..ff87ce929851 --- /dev/null +++ b/testing/web-platform/meta/css/css-grid/grid-model/grid-areas-overflowing-grid-container-001.html.ini @@ -0,0 +1,3 @@ +[grid-areas-overflowing-grid-container-001.html] + disabled: + if (os == "android") and e10s: bug 1550895 (frequently fails on geckoview) diff --git a/testing/web-platform/meta/css/css-text-decor/text-emphasis-style-006.html.ini b/testing/web-platform/meta/css/css-text-decor/text-emphasis-style-006.html.ini new file mode 100644 index 000000000000..793080fd905b --- /dev/null +++ b/testing/web-platform/meta/css/css-text-decor/text-emphasis-style-006.html.ini @@ -0,0 +1,3 @@ +[text-emphasis-style-006.html] + disabled: + if (os == "android") and e10s: bug 1550895 (frequently fails on geckoview) diff --git a/testing/web-platform/meta/css/vendor-imports/mozilla/mozilla-central-reftests/background/background-repeat-round-3.html.ini b/testing/web-platform/meta/css/vendor-imports/mozilla/mozilla-central-reftests/background/background-repeat-round-3.html.ini new file mode 100644 index 000000000000..5cfa81cc2694 --- /dev/null +++ b/testing/web-platform/meta/css/vendor-imports/mozilla/mozilla-central-reftests/background/background-repeat-round-3.html.ini @@ -0,0 +1,3 @@ +[background-repeat-round-3.html] + disabled: + if (os == "android") and e10s: bug 1550895 (frequently fails on geckoview) diff --git a/testing/web-platform/meta/css/vendor-imports/mozilla/mozilla-central-reftests/background/background-repeat-round-4.html.ini b/testing/web-platform/meta/css/vendor-imports/mozilla/mozilla-central-reftests/background/background-repeat-round-4.html.ini new file mode 100644 index 000000000000..85f251745195 --- /dev/null +++ b/testing/web-platform/meta/css/vendor-imports/mozilla/mozilla-central-reftests/background/background-repeat-round-4.html.ini @@ -0,0 +1,3 @@ +[background-repeat-round-4.html] + disabled: + if (os == "android") and e10s: bug 1550895 (frequently fails on geckoview) diff --git a/testing/web-platform/meta/css/vendor-imports/mozilla/mozilla-central-reftests/text3/segment-break-transformation-rules-007.html.ini b/testing/web-platform/meta/css/vendor-imports/mozilla/mozilla-central-reftests/text3/segment-break-transformation-rules-007.html.ini new file mode 100644 index 000000000000..c474c3d66de1 --- /dev/null +++ b/testing/web-platform/meta/css/vendor-imports/mozilla/mozilla-central-reftests/text3/segment-break-transformation-rules-007.html.ini @@ -0,0 +1,3 @@ +[segment-break-transformation-rules-007.html] + disabled: + if (os == "android") and e10s: bug 1550895 (frequently fails on geckoview) diff --git a/testing/web-platform/meta/html/browsers/history/the-location-interface/security_location_0.htm.ini b/testing/web-platform/meta/html/browsers/history/the-location-interface/security_location_0.htm.ini new file mode 100644 index 000000000000..057e26f96631 --- /dev/null +++ b/testing/web-platform/meta/html/browsers/history/the-location-interface/security_location_0.htm.ini @@ -0,0 +1,3 @@ +[security_location_0.htm] + disabled: + if (os == "android") and e10s: bug 1550895 (frequently fails on geckoview) diff --git a/testing/web-platform/meta/svg/embedded/image-embedding-svg-with-viewport-units-inline-style.svg.ini b/testing/web-platform/meta/svg/embedded/image-embedding-svg-with-viewport-units-inline-style.svg.ini deleted file mode 100644 index 597c4b8fd589..000000000000 --- a/testing/web-platform/meta/svg/embedded/image-embedding-svg-with-viewport-units-inline-style.svg.ini +++ /dev/null @@ -1,2 +0,0 @@ -[image-embedding-svg-with-viewport-units-inline-style.svg] - expected: FAIL diff --git a/testing/web-platform/meta/svg/embedded/image-embedding-svg-with-viewport-units.svg.ini b/testing/web-platform/meta/svg/embedded/image-embedding-svg-with-viewport-units.svg.ini deleted file mode 100644 index e9ec81d339af..000000000000 --- a/testing/web-platform/meta/svg/embedded/image-embedding-svg-with-viewport-units.svg.ini +++ /dev/null @@ -1,2 +0,0 @@ -[image-embedding-svg-with-viewport-units.svg] - expected: FAIL diff --git a/testing/web-platform/meta/svg/extensibility/foreignObject/properties.svg.ini b/testing/web-platform/meta/svg/extensibility/foreignObject/properties.svg.ini index dbd21b3c2daa..47e87e6c5a27 100644 --- a/testing/web-platform/meta/svg/extensibility/foreignObject/properties.svg.ini +++ b/testing/web-platform/meta/svg/extensibility/foreignObject/properties.svg.ini @@ -1,19 +1,6 @@ [properties.svg] - [Untitled] - expected: FAIL - [width and height default to auto] expected: FAIL - [style rules are applied] - expected: FAIL - - [attributes set properties] - expected: FAIL - - [style rules override attributes] - expected: FAIL - [width and height default to auto (which computes to "0px")] expected: FAIL - diff --git a/testing/web-platform/meta/svg/geometry/parsing/cx-valid.svg.ini b/testing/web-platform/meta/svg/geometry/parsing/cx-valid.svg.ini deleted file mode 100644 index 5b58d8e37e7c..000000000000 --- a/testing/web-platform/meta/svg/geometry/parsing/cx-valid.svg.ini +++ /dev/null @@ -1,16 +0,0 @@ -[cx-valid.svg] - [e.style['cx'\] = "4%" should set the property value] - expected: FAIL - - [e.style['cx'\] = "-1px" should set the property value] - expected: FAIL - - [e.style['cx'\] = "calc(2em + 3ex)" should set the property value] - expected: FAIL - - [e.style['cx'\] = "0" should set the property value] - expected: FAIL - - [e.style['cx'\] = "5ch" should set the property value] - expected: FAIL - diff --git a/testing/web-platform/meta/svg/geometry/parsing/cy-valid.svg.ini b/testing/web-platform/meta/svg/geometry/parsing/cy-valid.svg.ini deleted file mode 100644 index c4744a1488a0..000000000000 --- a/testing/web-platform/meta/svg/geometry/parsing/cy-valid.svg.ini +++ /dev/null @@ -1,16 +0,0 @@ -[cy-valid.svg] - [e.style['cy'\] = "0" should set the property value] - expected: FAIL - - [e.style['cy'\] = "calc(2em + 3ex)" should set the property value] - expected: FAIL - - [e.style['cy'\] = "4%" should set the property value] - expected: FAIL - - [e.style['cy'\] = "-1px" should set the property value] - expected: FAIL - - [e.style['cy'\] = "5rem" should set the property value] - expected: FAIL - diff --git a/testing/web-platform/meta/svg/geometry/parsing/height-computed.svg.ini b/testing/web-platform/meta/svg/geometry/parsing/height-computed.svg.ini index 4848d99c6fd0..842862002126 100644 --- a/testing/web-platform/meta/svg/geometry/parsing/height-computed.svg.ini +++ b/testing/web-platform/meta/svg/geometry/parsing/height-computed.svg.ini @@ -5,15 +5,9 @@ [SVG Geometry Properties: getComputedStyle().height, initial] expected: FAIL - [SVG Geometry Properties: getComputedStyle().height, presentation attribute] - expected: FAIL - [SVG Geometry Properties: getComputedStyle().height, inline style (auto)] expected: FAIL - [SVG Geometry Properties: getComputedStyle().height, presentation attribute] - expected: FAIL - [SVG Geometry Properties: getComputedStyle().height, initial] expected: FAIL @@ -44,6 +38,3 @@ [SVG Geometry Properties: getComputedStyle().height, inline style (percentage)] expected: FAIL - [SVG Geometry Properties: getComputedStyle().height, presentation attribute] - expected: FAIL - diff --git a/testing/web-platform/meta/svg/geometry/parsing/r-valid.svg.ini b/testing/web-platform/meta/svg/geometry/parsing/r-valid.svg.ini deleted file mode 100644 index cd8adc55faf5..000000000000 --- a/testing/web-platform/meta/svg/geometry/parsing/r-valid.svg.ini +++ /dev/null @@ -1,16 +0,0 @@ -[r-valid.svg] - [e.style['r'\] = "1px" should set the property value] - expected: FAIL - - [e.style['r'\] = "0" should set the property value] - expected: FAIL - - [e.style['r'\] = "calc(2em + 3ex)" should set the property value] - expected: FAIL - - [e.style['r'\] = "4%" should set the property value] - expected: FAIL - - [e.style['r'\] = "5vmin" should set the property value] - expected: FAIL - diff --git a/testing/web-platform/meta/svg/geometry/parsing/rx-valid.svg.ini b/testing/web-platform/meta/svg/geometry/parsing/rx-valid.svg.ini deleted file mode 100644 index 58135a0a4aaa..000000000000 --- a/testing/web-platform/meta/svg/geometry/parsing/rx-valid.svg.ini +++ /dev/null @@ -1,19 +0,0 @@ -[rx-valid.svg] - [e.style['rx'\] = "auto" should set the property value] - expected: FAIL - - [e.style['rx'\] = "4%" should set the property value] - expected: FAIL - - [e.style['rx'\] = "calc(2em + 3ex)" should set the property value] - expected: FAIL - - [e.style['rx'\] = "0" should set the property value] - expected: FAIL - - [e.style['rx'\] = "1px" should set the property value] - expected: FAIL - - [e.style['rx'\] = "5vw" should set the property value] - expected: FAIL - diff --git a/testing/web-platform/meta/svg/geometry/parsing/ry-valid.svg.ini b/testing/web-platform/meta/svg/geometry/parsing/ry-valid.svg.ini deleted file mode 100644 index 89f5671cddc7..000000000000 --- a/testing/web-platform/meta/svg/geometry/parsing/ry-valid.svg.ini +++ /dev/null @@ -1,37 +0,0 @@ -[ry-valid.svg] - [e.style['rx'\] = "auto" should set the property value] - expected: FAIL - - [e.style['rx'\] = "4%" should set the property value] - expected: FAIL - - [e.style['rx'\] = "calc(2em + 3ex)" should set the property value] - expected: FAIL - - [e.style['rx'\] = "0" should set the property value] - expected: FAIL - - [e.style['rx'\] = "1px" should set the property value] - expected: FAIL - - [e.style['rx'\] = "5vh" should set the property value] - expected: FAIL - - [e.style['ry'\] = "auto" should set the property value] - expected: FAIL - - [e.style['ry'\] = "0" should set the property value] - expected: FAIL - - [e.style['ry'\] = "calc(2em + 3ex)" should set the property value] - expected: FAIL - - [e.style['ry'\] = "4%" should set the property value] - expected: FAIL - - [e.style['ry'\] = "1px" should set the property value] - expected: FAIL - - [e.style['ry'\] = "5vh" should set the property value] - expected: FAIL - diff --git a/testing/web-platform/meta/svg/geometry/parsing/width-computed.svg.ini b/testing/web-platform/meta/svg/geometry/parsing/width-computed.svg.ini index 80daaebbd629..a7b3f5b1ce8d 100644 --- a/testing/web-platform/meta/svg/geometry/parsing/width-computed.svg.ini +++ b/testing/web-platform/meta/svg/geometry/parsing/width-computed.svg.ini @@ -14,18 +14,12 @@ [SVG Geometry Properties: getComputedStyle().width, initial] expected: FAIL - [SVG Geometry Properties: getComputedStyle().width, presentation attribute] - expected: FAIL - [SVG Geometry Properties: getComputedStyle().width, inline style (percentage)] expected: FAIL [SVG Geometry Properties: getComputedStyle().width, presentation attribute] expected: FAIL - [SVG Geometry Properties: getComputedStyle().width, presentation attribute] - expected: FAIL - [SVG Geometry Properties: getComputedStyle().width, inline style (percentage)] expected: FAIL @@ -44,6 +38,3 @@ [SVG Geometry Properties: getComputedStyle().width, inline style (auto)] expected: FAIL - [SVG Geometry Properties: getComputedStyle().width, presentation attribute] - expected: FAIL - diff --git a/testing/web-platform/meta/svg/geometry/parsing/x-valid.svg.ini b/testing/web-platform/meta/svg/geometry/parsing/x-valid.svg.ini deleted file mode 100644 index 3e60baf71b36..000000000000 --- a/testing/web-platform/meta/svg/geometry/parsing/x-valid.svg.ini +++ /dev/null @@ -1,16 +0,0 @@ -[x-valid.svg] - [e.style['x'\] = "-1px" should set the property value] - expected: FAIL - - [e.style['x'\] = "0" should set the property value] - expected: FAIL - - [e.style['x'\] = "calc(2em + 3ex)" should set the property value] - expected: FAIL - - [e.style['x'\] = "4%" should set the property value] - expected: FAIL - - [e.style['x'\] = "5cm" should set the property value] - expected: FAIL - diff --git a/testing/web-platform/meta/svg/geometry/parsing/y-valid.svg.ini b/testing/web-platform/meta/svg/geometry/parsing/y-valid.svg.ini deleted file mode 100644 index ee1d0181cdd1..000000000000 --- a/testing/web-platform/meta/svg/geometry/parsing/y-valid.svg.ini +++ /dev/null @@ -1,16 +0,0 @@ -[y-valid.svg] - [e.style['y'\] = "-1px" should set the property value] - expected: FAIL - - [e.style['y'\] = "4%" should set the property value] - expected: FAIL - - [e.style['y'\] = "0" should set the property value] - expected: FAIL - - [e.style['y'\] = "calc(2em + 3ex)" should set the property value] - expected: FAIL - - [e.style['y'\] = "5mm" should set the property value] - expected: FAIL - diff --git a/testing/web-platform/meta/svg/geometry/reftests/percentage.svg.ini b/testing/web-platform/meta/svg/geometry/reftests/percentage.svg.ini deleted file mode 100644 index 70f9924f1d4a..000000000000 --- a/testing/web-platform/meta/svg/geometry/reftests/percentage.svg.ini +++ /dev/null @@ -1,2 +0,0 @@ -[percentage.svg] - expected: FAIL diff --git a/testing/web-platform/meta/svg/shapes/ellipse-01.svg.ini b/testing/web-platform/meta/svg/shapes/ellipse-01.svg.ini deleted file mode 100644 index 3cc588394397..000000000000 --- a/testing/web-platform/meta/svg/shapes/ellipse-01.svg.ini +++ /dev/null @@ -1,4 +0,0 @@ -[ellipse-01.svg] - expected: - if (not (os == "win")): FAIL - if (os == "win"): FAIL diff --git a/testing/web-platform/meta/svg/shapes/ellipse-02.svg.ini b/testing/web-platform/meta/svg/shapes/ellipse-02.svg.ini deleted file mode 100644 index 8f9286256f01..000000000000 --- a/testing/web-platform/meta/svg/shapes/ellipse-02.svg.ini +++ /dev/null @@ -1,4 +0,0 @@ -[ellipse-02.svg] - expected: - if (not (os == "win")): FAIL - if (os == "win"): FAIL diff --git a/testing/web-platform/meta/svg/shapes/ellipse-03.svg.ini b/testing/web-platform/meta/svg/shapes/ellipse-03.svg.ini deleted file mode 100644 index 00e80ac64424..000000000000 --- a/testing/web-platform/meta/svg/shapes/ellipse-03.svg.ini +++ /dev/null @@ -1,4 +0,0 @@ -[ellipse-03.svg] - expected: - if (not (os == "win")): FAIL - if (os == "win"): FAIL diff --git a/testing/web-platform/meta/svg/shapes/ellipse-05.svg.ini b/testing/web-platform/meta/svg/shapes/ellipse-05.svg.ini deleted file mode 100644 index 3d59eb300620..000000000000 --- a/testing/web-platform/meta/svg/shapes/ellipse-05.svg.ini +++ /dev/null @@ -1,4 +0,0 @@ -[ellipse-05.svg] - expected: - if (not (os == "win")): FAIL - if (os == "win"): FAIL diff --git a/testing/web-platform/meta/svg/shapes/ellipse-06.svg.ini b/testing/web-platform/meta/svg/shapes/ellipse-06.svg.ini deleted file mode 100644 index 55bef13351e4..000000000000 --- a/testing/web-platform/meta/svg/shapes/ellipse-06.svg.ini +++ /dev/null @@ -1,4 +0,0 @@ -[ellipse-06.svg] - expected: - if (not (os == "win")): FAIL - if (os == "win"): FAIL diff --git a/testing/web-platform/meta/svg/shapes/ellipse-07.svg.ini b/testing/web-platform/meta/svg/shapes/ellipse-07.svg.ini deleted file mode 100644 index 92151b2c10b3..000000000000 --- a/testing/web-platform/meta/svg/shapes/ellipse-07.svg.ini +++ /dev/null @@ -1,4 +0,0 @@ -[ellipse-07.svg] - expected: - if (not (os == "win")): FAIL - if (os == "win"): FAIL diff --git a/testing/web-platform/meta/svg/shapes/ellipse-08.svg.ini b/testing/web-platform/meta/svg/shapes/ellipse-08.svg.ini deleted file mode 100644 index b3895ab52c14..000000000000 --- a/testing/web-platform/meta/svg/shapes/ellipse-08.svg.ini +++ /dev/null @@ -1,4 +0,0 @@ -[ellipse-08.svg] - expected: - if (not (os == "win")): FAIL - if (os == "win"): FAIL diff --git a/testing/web-platform/meta/svg/shapes/rx-ry-not-inherited.svg.ini b/testing/web-platform/meta/svg/shapes/rx-ry-not-inherited.svg.ini deleted file mode 100644 index ee42613f47b7..000000000000 --- a/testing/web-platform/meta/svg/shapes/rx-ry-not-inherited.svg.ini +++ /dev/null @@ -1,7 +0,0 @@ -[rx-ry-not-inherited.svg] - [Untitled] - expected: FAIL - - [rx-ry-not-inherited] - expected: FAIL - diff --git a/testing/web-platform/meta/webrtc/RTCPeerConnection-ondatachannel.html.ini b/testing/web-platform/meta/webrtc/RTCPeerConnection-ondatachannel.html.ini index 7a8cf2dc68c0..0db9ade5a016 100644 --- a/testing/web-platform/meta/webrtc/RTCPeerConnection-ondatachannel.html.ini +++ b/testing/web-platform/meta/webrtc/RTCPeerConnection-ondatachannel.html.ini @@ -5,16 +5,21 @@ [Data channel event should fire when new data channel is announced to the remote peer] expected: FAIL + bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1551589 [In-band negotiated channel created on remote peer should match the same (default) configuration as local peer] expected: FAIL + bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1529695 [Open event should not be raised when sending and immediately closing the channel in the datachannel event] expected: FAIL + bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1551589 [Should be able to send data in a datachannel event handler] expected: FAIL + bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1551589 [In-band negotiated channel created on remote peer should match the same configuration as local peer] expected: FAIL + bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1551589 diff --git a/testing/web-platform/tests/intersection-observer/iframe-no-root-with-wrapping-scroller.html b/testing/web-platform/tests/intersection-observer/iframe-no-root-with-wrapping-scroller.html new file mode 100644 index 000000000000..f219ba39c147 --- /dev/null +++ b/testing/web-platform/tests/intersection-observer/iframe-no-root-with-wrapping-scroller.html @@ -0,0 +1,73 @@ + + + + + + + +
+
+ +
+
+ + diff --git a/testing/web-platform/tests/svg/shapes/reftests/disabled-shapes-01.svg b/testing/web-platform/tests/svg/shapes/reftests/disabled-shapes-01.svg index 3091ca7b0152..65364dc08ff5 100644 --- a/testing/web-platform/tests/svg/shapes/reftests/disabled-shapes-01.svg +++ b/testing/web-platform/tests/svg/shapes/reftests/disabled-shapes-01.svg @@ -21,6 +21,7 @@ + @@ -29,22 +30,22 @@ + - - + diff --git a/testing/web-platform/tests/svg/shapes/scripted/disabled-shapes-not-hit.svg b/testing/web-platform/tests/svg/shapes/scripted/disabled-shapes-not-hit.svg index 5a621d9f21dc..21ea9078785e 100644 --- a/testing/web-platform/tests/svg/shapes/scripted/disabled-shapes-not-hit.svg +++ b/testing/web-platform/tests/svg/shapes/scripted/disabled-shapes-not-hit.svg @@ -22,6 +22,7 @@ + @@ -30,22 +31,22 @@ + - - + -