author | Alexandru Michis <malexandru@mozilla.com> |
Thu, 20 Jan 2022 23:42:30 +0200 | |
changeset 605042 | d3a989967dd3775b1b08ec6d3fe046ae7d48c215 |
parent 605022 | f26c5f46bdcd7ba4163f79788f8ba030b0eddd3e (current diff) |
parent 605041 | cf8829a3353a70a5f598f06151437a35adb712c5 (diff) |
child 605043 | 9c925f2d42672f6927659d84089fda81758c0b3e |
child 605075 | 97861a268eda610849210703ba6c6842e00bb9e3 |
push id | 39171 |
push user | malexandru@mozilla.com |
push date | Thu, 20 Jan 2022 21:43:17 +0000 |
treeherder | mozilla-central@d3a989967dd3 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | merge |
milestone | 98.0a1 |
first release with | nightly linux32
d3a989967dd3
/
98.0a1
/
20220120214317
/
files
nightly linux64
d3a989967dd3
/
98.0a1
/
20220120214317
/
files
nightly mac
d3a989967dd3
/
98.0a1
/
20220120214317
/
files
nightly win32
d3a989967dd3
/
98.0a1
/
20220120214317
/
files
nightly win64
d3a989967dd3
/
98.0a1
/
20220120214317
/
files
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
releases | nightly linux32
98.0a1
/
20220120214317
/
pushlog to previous
nightly linux64
98.0a1
/
20220120214317
/
pushlog to previous
nightly mac
98.0a1
/
20220120214317
/
pushlog to previous
nightly win32
98.0a1
/
20220120214317
/
pushlog to previous
nightly win64
98.0a1
/
20220120214317
/
pushlog to previous
|
--- a/browser/base/content/pageinfo/pageInfo.js +++ b/browser/base/content/pageinfo/pageInfo.js @@ -1,15 +1,15 @@ /* 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/. */ -/* import-globals-from ../../../../toolkit/content/globalOverlay.js */ -/* import-globals-from ../../../../toolkit/content/contentAreaUtils.js */ -/* import-globals-from ../../../../toolkit/content/treeUtils.js */ +/* import-globals-from /toolkit/content/globalOverlay.js */ +/* import-globals-from /toolkit/content/contentAreaUtils.js */ +/* import-globals-from /toolkit/content/treeUtils.js */ /* import-globals-from ../utilityOverlay.js */ /* import-globals-from permissions.js */ /* import-globals-from security.js */ XPCOMUtils.defineLazyModuleGetters(this, { E10SUtils: "resource://gre/modules/E10SUtils.jsm", });
--- a/browser/base/content/sanitizeDialog.js +++ b/browser/base/content/sanitizeDialog.js @@ -1,14 +1,14 @@ /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -/* import-globals-from ../../../toolkit/content/preferencesBindings.js */ +/* import-globals-from /toolkit/content/preferencesBindings.js */ var { Sanitizer } = ChromeUtils.import("resource:///modules/Sanitizer.jsm"); var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); Preferences.addAll([ { id: "privacy.cpd.history", type: "bool" }, { id: "privacy.cpd.formdata", type: "bool" }, { id: "privacy.cpd.downloads", type: "bool", disabled: true },
--- a/browser/components/downloads/content/downloadsCommands.js +++ b/browser/components/downloads/content/downloadsCommands.js @@ -1,14 +1,14 @@ /* 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/. */ /* import-globals-from allDownloadsView.js */ -/* import-globals-from ../../../../toolkit/content/globalOverlay.js */ +/* import-globals-from /toolkit/content/globalOverlay.js */ document.addEventListener("DOMContentLoaded", function() { let downloadCommands = document.getElementById("downloadCommands"); downloadCommands.addEventListener("commandupdate", function() { goUpdateDownloadCommands(); }); downloadCommands.addEventListener("command", function(event) { let { id } = event.target;
--- a/browser/components/payments/res/components/address-option.js +++ b/browser/components/payments/res/components/address-option.js @@ -1,13 +1,13 @@ /* 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/. */ -/* import-globals-from ../../../../../browser/extensions/formautofill/content/autofillEditForms.js*/ +/* import-globals-from /browser/extensions/formautofill/content/autofillEditForms.js*/ import ObservedPropertiesMixin from "../mixins/ObservedPropertiesMixin.js"; import RichOption from "./rich-option.js"; /* import-globals-from ../unprivileged-fallbacks.js */ /** * Up to two-line address display. After bug 1475684 this will also be used for * the single-line <option> substitute too. *
--- a/browser/components/payments/res/containers/address-form.js +++ b/browser/components/payments/res/containers/address-form.js @@ -1,13 +1,13 @@ /* 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/. */ -/* import-globals-from ../../../../../browser/extensions/formautofill/content/autofillEditForms.js*/ +/* import-globals-from /browser/extensions/formautofill/content/autofillEditForms.js*/ import LabelledCheckbox from "../components/labelled-checkbox.js"; import PaymentRequestPage from "../components/payment-request-page.js"; import PaymentStateSubscriberMixin from "../mixins/PaymentStateSubscriberMixin.js"; import paymentRequest from "../paymentRequest.js"; import HandleEventMixin from "../mixins/HandleEventMixin.js"; /* import-globals-from ../unprivileged-fallbacks.js */ /**
--- a/browser/components/payments/res/containers/basic-card-form.js +++ b/browser/components/payments/res/containers/basic-card-form.js @@ -1,13 +1,13 @@ /* 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/. */ -/* import-globals-from ../../../../../browser/extensions/formautofill/content/autofillEditForms.js*/ +/* import-globals-from /browser/extensions/formautofill/content/autofillEditForms.js*/ import AcceptedCards from "../components/accepted-cards.js"; import BillingAddressPicker from "./billing-address-picker.js"; import CscInput from "../components/csc-input.js"; import LabelledCheckbox from "../components/labelled-checkbox.js"; import PaymentRequestPage from "../components/payment-request-page.js"; import PaymentStateSubscriberMixin from "../mixins/PaymentStateSubscriberMixin.js"; import paymentRequest from "../paymentRequest.js"; import HandleEventMixin from "../mixins/HandleEventMixin.js";
--- a/browser/components/places/content/controller.js +++ b/browser/components/places/content/controller.js @@ -1,17 +1,17 @@ /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -/* import-globals-from ../../../base/content/utilityOverlay.js */ +/* import-globals-from /browser/base/content/utilityOverlay.js */ /* import-globals-from ../PlacesUIUtils.jsm */ -/* import-globals-from ../../../../toolkit/components/places/PlacesUtils.jsm */ -/* import-globals-from ../../../../toolkit/components/places/PlacesTransactions.jsm */ +/* import-globals-from /toolkit/components/places/PlacesUtils.jsm */ +/* import-globals-from /toolkit/components/places/PlacesTransactions.jsm */ /* import-globals-from ./places.js */ /** * Represents an insertion point within a container where we can insert * items. * @param {object} an object containing the following properties: * - parentId * The identifier of the parent container
--- a/browser/components/places/content/places.js +++ b/browser/components/places/content/places.js @@ -1,16 +1,16 @@ /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* import-globals-from instantEditBookmark.js */ -/* import-globals-from ../../../../toolkit/content/contentAreaUtils.js */ -/* import-globals-from ../../downloads/content/allDownloadsView.js */ +/* import-globals-from /toolkit/content/contentAreaUtils.js */ +/* import-globals-from /browser/components/downloads/content/allDownloadsView.js */ /* Shared Places Import - change other consumers if you change this: */ var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); var { XPCOMUtils } = ChromeUtils.import( "resource://gre/modules/XPCOMUtils.jsm" ); XPCOMUtils.defineLazyModuleGetters(this, { PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
--- a/browser/components/places/tests/browser/interactions/browser_interactions_typing.js +++ b/browser/components/places/tests/browser/interactions/browser_interactions_typing.js @@ -235,32 +235,32 @@ add_task(async function test_typing_and_ const testStartTime = Cu.now(); await BrowserTestUtils.withNewTab(TEST_URL, async browser => { await sendTextToInput(browser, sentenceFragments[0]); info("reload"); browser.reload(); - await BrowserTestUtils.browserLoaded(browser); + await BrowserTestUtils.browserLoaded(browser, false, TEST_URL); // First typing should have been recorded await assertDatabaseValues([ { url: TEST_URL, keypresses: sentenceFragments[0].length, typingTimeIsGreaterThan: 0, }, ]); await sendTextToInput(browser, sentenceFragments[1]); info("reload"); browser.reload(); - await BrowserTestUtils.browserLoaded(browser); + await BrowserTestUtils.browserLoaded(browser, false, TEST_URL); // Second typing should have been recorded await assertDatabaseValues([ { url: TEST_URL, keypresses: sentenceFragments[0].length, typingTimeIsGreaterThan: 0, typingTimeIsLessThan: Cu.now() - testStartTime,
--- a/browser/components/preferences/dialogs/browserLanguages.js +++ b/browser/components/preferences/dialogs/browserLanguages.js @@ -1,13 +1,13 @@ /* 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/. */ -/* import-globals-from ../../../../toolkit/content/preferencesBindings.js */ +/* import-globals-from /toolkit/content/preferencesBindings.js */ var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); // This is exported by preferences.js but we can't import that in a subdialog. let { getAvailableLocales } = window.top; ChromeUtils.defineModuleGetter( this,
--- a/browser/components/preferences/dialogs/colors.js +++ b/browser/components/preferences/dialogs/colors.js @@ -1,13 +1,13 @@ /* 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/. */ -/* import-globals-from ../../../../toolkit/content/preferencesBindings.js */ +/* import-globals-from /toolkit/content/preferencesBindings.js */ document .getElementById("ColorsDialog") .addEventListener("dialoghelp", window.top.openPrefsHelp); Preferences.addAll([ { id: "browser.display.document_color_use", type: "int" }, { id: "browser.anchor_color", type: "string" },
--- a/browser/components/preferences/dialogs/connection.js +++ b/browser/components/preferences/dialogs/connection.js @@ -1,15 +1,15 @@ /* -*- indent-tabs-mode: nil; js-indent-level: 4 -*- */ /* 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/. */ -/* import-globals-from ../../../base/content/utilityOverlay.js */ -/* import-globals-from ../../../../toolkit/content/preferencesBindings.js */ +/* import-globals-from /browser/base/content/utilityOverlay.js */ +/* import-globals-from /toolkit/content/preferencesBindings.js */ /* import-globals-from ../extensionControlled.js */ ChromeUtils.defineModuleGetter( this, "DoHConfigController", "resource:///modules/DoHConfig.jsm" );
--- a/browser/components/preferences/dialogs/fonts.js +++ b/browser/components/preferences/dialogs/fonts.js @@ -1,15 +1,15 @@ /* -*- indent-tabs-mode: nil; js-indent-level: 4 -*- */ /* 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/. */ -/* import-globals-from ../../../base/content/utilityOverlay.js */ -/* import-globals-from ../../../../toolkit/mozapps/preferences/fontbuilder.js */ +/* import-globals-from /browser/base/content/utilityOverlay.js */ +/* import-globals-from /toolkit/mozapps/preferences/fontbuilder.js */ // browser.display.languageList LOCK ALL when LOCKED const kDefaultFontType = "font.default.%LANG%"; const kFontNameFmtSerif = "font.name.serif.%LANG%"; const kFontNameFmtSansSerif = "font.name.sans-serif.%LANG%"; const kFontNameFmtMonospace = "font.name.monospace.%LANG%"; const kFontNameListFmtSerif = "font.name-list.serif.%LANG%";
--- a/browser/components/preferences/dialogs/languages.js +++ b/browser/components/preferences/dialogs/languages.js @@ -1,14 +1,14 @@ /* -*- indent-tabs-mode: nil; js-indent-level: 4 -*- */ /* 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/. */ -/* import-globals-from ../../../../toolkit/content/preferencesBindings.js */ +/* import-globals-from /toolkit/content/preferencesBindings.js */ var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); document .getElementById("LanguagesDialog") .addEventListener("dialoghelp", window.top.openPrefsHelp); Preferences.addAll([
--- a/browser/components/preferences/dialogs/sanitize.js +++ b/browser/components/preferences/dialogs/sanitize.js @@ -1,14 +1,14 @@ /* -*- indent-tabs-mode: nil; js-indent-level: 4 -*- */ /* 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/. */ -/* import-globals-from ../../../../toolkit/content/preferencesBindings.js */ +/* import-globals-from /toolkit/content/preferencesBindings.js */ document .querySelector("dialog") .addEventListener("dialoghelp", window.top.openPrefsHelp); Preferences.addAll([ { id: "privacy.clearOnShutdown.history", type: "bool" }, { id: "privacy.clearOnShutdown.formdata", type: "bool" },
--- a/browser/components/preferences/dialogs/syncChooseWhatToSync.js +++ b/browser/components/preferences/dialogs/syncChooseWhatToSync.js @@ -1,13 +1,13 @@ /* 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/. */ -/* import-globals-from ../../../../toolkit/content/preferencesBindings.js */ +/* import-globals-from /toolkit/content/preferencesBindings.js */ const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); Preferences.addAll([ { id: "services.sync.engine.addons", type: "bool" }, { id: "services.sync.engine.bookmarks", type: "bool" }, { id: "services.sync.engine.history", type: "bool" }, { id: "services.sync.engine.tabs", type: "bool" },
--- a/browser/components/preferences/main.js +++ b/browser/components/preferences/main.js @@ -1,16 +1,16 @@ /* 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/. */ /* import-globals-from extensionControlled.js */ /* import-globals-from preferences.js */ -/* import-globals-from ../../../toolkit/mozapps/preferences/fontbuilder.js */ -/* import-globals-from ../../base/content/aboutDialog-appUpdater.js */ +/* import-globals-from /toolkit/mozapps/preferences/fontbuilder.js */ +/* import-globals-from /browser/base/content/aboutDialog-appUpdater.js */ /* global MozXULElement */ XPCOMUtils.defineLazyModuleGetters(this, { BackgroundUpdate: "resource://gre/modules/BackgroundUpdate.jsm", }); // Constants & Enumeration Values const TYPE_PDF = "application/pdf";
--- a/browser/components/preferences/preferences.js +++ b/browser/components/preferences/preferences.js @@ -7,18 +7,18 @@ /* import-globals-from home.js */ /* import-globals-from search.js */ /* import-globals-from containers.js */ /* import-globals-from privacy.js */ /* import-globals-from sync.js */ /* import-globals-from experimental.js */ /* import-globals-from moreFromMozilla.js */ /* import-globals-from findInPage.js */ -/* import-globals-from ../../base/content/utilityOverlay.js */ -/* import-globals-from ../../../toolkit/content/preferencesBindings.js */ +/* import-globals-from /browser/base/content/utilityOverlay.js */ +/* import-globals-from /toolkit/content/preferencesBindings.js */ "use strict"; var { AppConstants } = ChromeUtils.import( "resource://gre/modules/AppConstants.jsm" ); var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
--- a/browser/components/shell/content/setDesktopBackground.js +++ b/browser/components/shell/content/setDesktopBackground.js @@ -1,13 +1,13 @@ /* 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/. */ -/* import-globals-from ../../../base/content/utilityOverlay.js */ +/* import-globals-from /browser/base/content/utilityOverlay.js */ var gSetBackground = { _position: AppConstants.platform == "macosx" ? "STRETCH" : "", _backgroundColor: AppConstants.platform != "macosx" ? 0 : undefined, _screenWidth: 0, _screenHeight: 0, _image: null, _canvas: null,
--- a/dom/canvas/ImageBitmap.cpp +++ b/dom/canvas/ImageBitmap.cpp @@ -19,16 +19,17 @@ #include "mozilla/dom/Promise.h" #include "mozilla/dom/StructuredCloneTags.h" #include "mozilla/dom/SVGImageElement.h" #include "mozilla/dom/WorkerPrivate.h" #include "mozilla/dom/WorkerRef.h" #include "mozilla/dom/WorkerRunnable.h" #include "mozilla/gfx/2D.h" #include "mozilla/gfx/Logging.h" +#include "mozilla/gfx/Scale.h" #include "mozilla/gfx/Swizzle.h" #include "mozilla/Mutex.h" #include "mozilla/ScopeExit.h" #include "nsGlobalWindowInner.h" #include "nsIAsyncInputStream.h" #include "nsNetUtil.h" #include "nsLayoutUtils.h" #include "nsStreamUtils.h" @@ -263,16 +264,93 @@ static already_AddRefed<DataSourceSurfac srcBufferPtr += srcMap.GetStride(); dstBufferPtr += dstMap.GetStride(); } } return dstDataSurface.forget(); } +/* + * This helper function scales the data of the given DataSourceSurface, + * _aSurface_, in the given area, _aCropRect_, into a new DataSourceSurface. + * This might return null if it can not create a new SourceSurface or it cannot + * read data from the given _aSurface_. + * + */ +static already_AddRefed<DataSourceSurface> ScaleDataSourceSurface( + DataSourceSurface* aSurface, const ImageBitmapOptions& aOptions) { + MOZ_ASSERT(aSurface); + + const SurfaceFormat format = aSurface->GetFormat(); + const int bytesPerPixel = BytesPerPixel(format); + + const IntSize srcSize = aSurface->GetSize(); + int32_t tmp; + + CheckedInt<int32_t> checked; + CheckedInt<int32_t> dstWidth( + aOptions.mResizeWidth.WasPassed() ? aOptions.mResizeWidth.Value() : 0); + CheckedInt<int32_t> dstHeight( + aOptions.mResizeHeight.WasPassed() ? aOptions.mResizeHeight.Value() : 0); + + if (!dstWidth.isValid() || !dstHeight.isValid()) { + return nullptr; + } + + if (!dstWidth.value()) { + checked = srcSize.width * dstHeight; + if (!checked.isValid()) { + return nullptr; + } + + tmp = ceil(checked.value() / double(srcSize.height)); + dstWidth = tmp; + } else if (!dstHeight.value()) { + checked = srcSize.height * dstWidth; + if (!checked.isValid()) { + return nullptr; + } + + tmp = ceil(checked.value() / double(srcSize.width)); + dstHeight = tmp; + } + + const IntSize dstSize(dstWidth.value(), dstHeight.value()); + const int32_t dstStride = dstSize.width * bytesPerPixel; + + // Create a new SourceSurface. + RefPtr<DataSourceSurface> dstDataSurface = + Factory::CreateDataSourceSurfaceWithStride(dstSize, format, dstStride, + true); + + if (NS_WARN_IF(!dstDataSurface)) { + return nullptr; + } + + // Copy the raw data into the newly created DataSourceSurface. + DataSourceSurface::ScopedMap srcMap(aSurface, DataSourceSurface::READ); + DataSourceSurface::ScopedMap dstMap(dstDataSurface, DataSourceSurface::WRITE); + if (NS_WARN_IF(!srcMap.IsMapped()) || NS_WARN_IF(!dstMap.IsMapped())) { + return nullptr; + } + + uint8_t* srcBufferPtr = srcMap.GetData(); + uint8_t* dstBufferPtr = dstMap.GetData(); + + bool res = Scale(srcBufferPtr, srcSize.width, srcSize.height, + srcMap.GetStride(), dstBufferPtr, dstSize.width, + dstSize.height, dstMap.GetStride(), aSurface->GetFormat()); + if (!res) { + return nullptr; + } + + return dstDataSurface.forget(); +} + static DataSourceSurface* FlipYDataSourceSurface(DataSourceSurface* aSurface) { MOZ_ASSERT(aSurface); // Invert in y direction. DataSourceSurface::ScopedMap srcMap(aSurface, DataSourceSurface::READ_WRITE); if (NS_WARN_IF(!srcMap.IsMapped())) { return nullptr; } @@ -369,16 +447,24 @@ static already_AddRefed<SourceSurface> C if (aOptions.mImageOrientation == ImageOrientation::FlipY) { result = FlipYDataSourceSurface(result); if (NS_WARN_IF(!result)) { return nullptr; } } + if (aOptions.mResizeWidth.WasPassed() || aOptions.mResizeHeight.WasPassed()) { + dataSurface = result->GetDataSurface(); + result = ScaleDataSourceSurface(dataSurface, aOptions); + if (NS_WARN_IF(!result)) { + return nullptr; + } + } + if (aOptions.mPremultiplyAlpha == PremultiplyAlpha::Premultiply) { result = AlphaPremultiplyDataSourceSurface(result); if (NS_WARN_IF(!result)) { return nullptr; } } @@ -820,32 +906,49 @@ already_AddRefed<ImageBitmap> ImageBitma dataSurface = CropAndCopyDataSourceSurface(dataSurface, cropRect); if (NS_WARN_IF(!dataSurface)) { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return nullptr; } surface = dataSurface; - cropRect.MoveTo(0, 0); + cropRect.SetRect(0, 0, dataSurface->GetSize().width, + dataSurface->GetSize().height); needToReportMemoryAllocation = true; } // flip image in Y direction if (aOptions.mImageOrientation == ImageOrientation::FlipY) { if (!dataSurface) { dataSurface = surface->GetDataSurface(); } surface = FlipYDataSourceSurface(dataSurface); if (NS_WARN_IF(!surface)) { return nullptr; } } + // resize if required + if (aOptions.mResizeWidth.WasPassed() || aOptions.mResizeHeight.WasPassed()) { + if (!dataSurface) { + dataSurface = surface->GetDataSurface(); + }; + + surface = ScaleDataSourceSurface(dataSurface, aOptions); + if (NS_WARN_IF(!surface)) { + aRv.ThrowInvalidStateError("Failed to create resized image"); + return nullptr; + } + + needToReportMemoryAllocation = true; + cropRect.SetRect(0, 0, surface->GetSize().width, surface->GetSize().height); + } + if (requiresPremultiply || requiresUnpremultiply) { if (!dataSurface) { dataSurface = surface->GetDataSurface(); } surface = AlphaPremultiplyDataSourceSurface(dataSurface, requiresPremultiply); if (NS_WARN_IF(!surface)) { @@ -1330,17 +1433,16 @@ class CreateImageBitmapFromBlob final : const ImageBitmapOptions& aOptions) : DiscardableRunnable("dom::CreateImageBitmapFromBlob"), mMutex("dom::CreateImageBitmapFromBlob::mMutex"), mPromise(aPromise), mGlobalObject(aGlobal), mInputStream(std::move(aInputStream)), mCropRect(aCropRect), - mOriginalCropRect(aCropRect), mMainThreadEventTarget(aMainThreadEventTarget), mOptions(aOptions), mThread(PR_GetCurrentThread()) {} virtual ~CreateImageBitmapFromBlob() = default; bool IsCurrentThread() const { return mThread == PR_GetCurrentThread(); } @@ -1378,18 +1480,16 @@ class CreateImageBitmapFromBlob final : // Touched only on the owning thread. RefPtr<Promise> mPromise; // Touched only on the owning thread. nsCOMPtr<nsIGlobalObject> mGlobalObject; nsCOMPtr<nsIInputStream> mInputStream; Maybe<IntRect> mCropRect; - Maybe<IntRect> mOriginalCropRect; - IntSize mSourceSize; nsCOMPtr<nsIEventTarget> mMainThreadEventTarget; const ImageBitmapOptions mOptions; void* mThread; }; NS_IMPL_ISUPPORTS_INHERITED(CreateImageBitmapFromBlob, DiscardableRunnable, imgIContainerCallback, nsIInputStreamCallback) @@ -1462,16 +1562,29 @@ already_AddRefed<Promise> ImageBitmap::C if (aCropRect->Height() == 0) { aRv.ThrowRangeError( "The crop rect height passed to createImageBitmap must be nonzero"); return promise.forget(); } } + if (aOptions.mResizeWidth.WasPassed() && aOptions.mResizeWidth.Value() == 0) { + aRv.ThrowInvalidStateError( + "The resizeWidth passed to createImageBitmap must be nonzero"); + return promise.forget(); + } + + if (aOptions.mResizeHeight.WasPassed() && + aOptions.mResizeHeight.Value() == 0) { + aRv.ThrowInvalidStateError( + "The resizeHeight passed to createImageBitmap must be nonzero"); + return promise.forget(); + } + RefPtr<ImageBitmap> imageBitmap; if (aSrc.IsHTMLImageElement()) { MOZ_ASSERT( NS_IsMainThread(), "Creating ImageBitmap from HTMLImageElement off the main thread."); imageBitmap = CreateInternal(aGlobal, aSrc.GetAsHTMLImageElement(), aCropRect, aOptions, aRv); @@ -1840,20 +1953,16 @@ CreateImageBitmapFromBlob::OnImageReady( aImgContainer->GetFrame(whichFrame, frameFlags); if (NS_WARN_IF(!surface)) { MimeTypeAndDecodeAndCropBlobCompletedMainThread( nullptr, NS_ERROR_DOM_INVALID_STATE_ERR); return NS_OK; } - // Store the sourceSize value for the - // MimeTypeAndDecodeAndCropBlobCompletedMainThread call. - mSourceSize = surface->GetSize(); - // Crop the source surface if needed. RefPtr<SourceSurface> croppedSurface = surface; RefPtr<DataSourceSurface> dataSurface = surface->GetDataSurface(); // force a copy into unprotected memory as a side effect of // CropAndCopyDataSourceSurface bool copyRequired = mCropRect.isSome() || mOptions.mImageOrientation == ImageOrientation::FlipY; @@ -1880,24 +1989,39 @@ CreateImageBitmapFromBlob::OnImageReady( MimeTypeAndDecodeAndCropBlobCompletedMainThread( nullptr, NS_ERROR_DOM_INVALID_STATE_ERR); return NS_OK; } dataSurface = croppedSurface->GetDataSurface(); if (mCropRect.isSome()) { - mCropRect->MoveTo(0, 0); + mCropRect->SetRect(0, 0, dataSurface->GetSize().width, + dataSurface->GetSize().height); } } if (mOptions.mImageOrientation == ImageOrientation::FlipY) { croppedSurface = FlipYDataSourceSurface(dataSurface); } + if (mOptions.mResizeWidth.WasPassed() || mOptions.mResizeHeight.WasPassed()) { + dataSurface = croppedSurface->GetDataSurface(); + croppedSurface = ScaleDataSourceSurface(dataSurface, mOptions); + if (NS_WARN_IF(!croppedSurface)) { + MimeTypeAndDecodeAndCropBlobCompletedMainThread( + nullptr, NS_ERROR_DOM_INVALID_STATE_ERR); + return NS_OK; + } + if (mCropRect.isSome()) { + mCropRect->SetRect(0, 0, croppedSurface->GetSize().width, + croppedSurface->GetSize().height); + } + } + if (NS_WARN_IF(!croppedSurface)) { MimeTypeAndDecodeAndCropBlobCompletedMainThread( nullptr, NS_ERROR_DOM_INVALID_STATE_ERR); return NS_OK; } // Create an Image from the source surface. RefPtr<layers::Image> image = CreateImageFromSurface(croppedSurface);
--- a/dom/ipc/SharedMessageBody.cpp +++ b/dom/ipc/SharedMessageBody.cpp @@ -252,16 +252,19 @@ bool SharedMessageBody::FromSharedToMess return true; } /* static */ already_AddRefed<SharedMessageBody> SharedMessageBody::FromMessageToSharedParent( MessageData& aMessage, StructuredCloneHolder::TransferringSupport aSupportsTransferring) { + // TODO: This alloc is not fallible and there is no codepath that returns + // nullptr. But the caller checks for nullptr and handles array allocations + // for these items as fallible. See bug 1750497. RefPtr<SharedMessageBody> data = new SharedMessageBody(aSupportsTransferring, aMessage.agentClusterId()); if (aMessage.data().type() == MessageDataType::TClonedMessageData) { data->mCloneData = MakeUnique<ipc::StructuredCloneData>( JS::StructuredCloneScope::UnknownDestination, aSupportsTransferring); data->mCloneData->StealFromClonedMessageDataForBackgroundParent( aMessage.data().get_ClonedMessageData());
--- a/dom/media/gmp/GMPContentChild.cpp +++ b/dom/media/gmp/GMPContentChild.cpp @@ -57,51 +57,48 @@ already_AddRefed<PChromiumCDMChild> GMPC mozilla::ipc::IPCResult GMPContentChild::RecvPGMPVideoDecoderConstructor( PGMPVideoDecoderChild* aActor) { auto vdc = static_cast<GMPVideoDecoderChild*>(aActor); void* vd = nullptr; GMPErr err = mGMPChild->GetAPI(GMP_API_VIDEO_DECODER, &vdc->Host(), &vd); if (err != GMPNoErr || !vd) { - NS_WARNING("GMPGetAPI call failed trying to construct decoder."); - return IPC_FAIL_NO_REASON(this); + return IPC_FAIL(this, "GMPGetAPI call failed trying to construct decoder."); } vdc->Init(static_cast<GMPVideoDecoder*>(vd)); return IPC_OK(); } mozilla::ipc::IPCResult GMPContentChild::RecvPGMPVideoEncoderConstructor( PGMPVideoEncoderChild* aActor) { auto vec = static_cast<GMPVideoEncoderChild*>(aActor); void* ve = nullptr; GMPErr err = mGMPChild->GetAPI(GMP_API_VIDEO_ENCODER, &vec->Host(), &ve); if (err != GMPNoErr || !ve) { - NS_WARNING("GMPGetAPI call failed trying to construct encoder."); - return IPC_FAIL_NO_REASON(this); + return IPC_FAIL(this, "GMPGetAPI call failed trying to construct encoder."); } vec->Init(static_cast<GMPVideoEncoder*>(ve)); return IPC_OK(); } mozilla::ipc::IPCResult GMPContentChild::RecvPChromiumCDMConstructor( PChromiumCDMChild* aActor, const nsCString& aKeySystem) { ChromiumCDMChild* child = static_cast<ChromiumCDMChild*>(aActor); cdm::Host_10* host10 = child; void* cdm = nullptr; GMPErr err = mGMPChild->GetAPI(CHROMIUM_CDM_API, host10, &cdm, aKeySystem); if (err != GMPNoErr || !cdm) { - NS_WARNING("GMPGetAPI call failed trying to get CDM."); - return IPC_FAIL_NO_REASON(this); + return IPC_FAIL(this, "GMPGetAPI call failed trying to get CDM."); } child->Init(static_cast<cdm::ContentDecryptionModule_10*>(cdm), mGMPChild->mStorageId); return IPC_OK(); }
--- a/dom/media/gmp/GMPParent.cpp +++ b/dom/media/gmp/GMPParent.cpp @@ -696,18 +696,21 @@ bool GMPParent::DeallocPGMPStorageParent p->Shutdown(); mStorage.RemoveElement(p); return true; } mozilla::ipc::IPCResult GMPParent::RecvPGMPStorageConstructor( PGMPStorageParent* aActor) { GMPStorageParent* p = (GMPStorageParent*)aActor; - if (NS_WARN_IF(NS_FAILED(p->Init()))) { - return IPC_FAIL_NO_REASON(this); + if (NS_FAILED(p->Init())) { + // TODO: Verify if this is really a good reason to IPC_FAIL. + // There might be shutdown edge cases here. + return IPC_FAIL(this, + "GMPParent::RecvPGMPStorageConstructor: p->Init() failed."); } return IPC_OK(); } mozilla::ipc::IPCResult GMPParent::RecvPGMPTimerConstructor( PGMPTimerParent* actor) { return IPC_OK(); }
--- a/dom/media/gmp/GMPServiceParent.cpp +++ b/dom/media/gmp/GMPServiceParent.cpp @@ -1821,17 +1821,19 @@ mozilla::ipc::IPCResult GMPServiceParent return IPC_OK(); } mozilla::ipc::IPCResult GMPServiceParent::RecvGetGMPNodeId( const nsString& aOrigin, const nsString& aTopLevelOrigin, const nsString& aGMPName, nsCString* aID) { nsresult rv = mService->GetNodeId(aOrigin, aTopLevelOrigin, aGMPName, *aID); if (!NS_SUCCEEDED(rv)) { - return IPC_FAIL_NO_REASON(this); + return IPC_FAIL( + this, + "GMPServiceParent::RecvGetGMPNodeId: mService->GetNodeId failed."); } return IPC_OK(); } class OpenPGMPServiceParent : public mozilla::Runnable { public: OpenPGMPServiceParent(RefPtr<GMPServiceParent>&& aGMPServiceParent, ipc::Endpoint<PGMPServiceParent>&& aEndpoint,
--- a/dom/media/gmp/GMPStorageParent.cpp +++ b/dom/media/gmp/GMPStorageParent.cpp @@ -55,17 +55,18 @@ nsresult GMPStorageParent::Init() { } mozilla::ipc::IPCResult GMPStorageParent::RecvOpen( const nsCString& aRecordName) { LOGD( ("GMPStorageParent[%p]::RecvOpen(record='%s')", this, aRecordName.get())); if (mShutdown) { - return IPC_FAIL_NO_REASON(this); + // Shutdown is an expected state, so we do not IPC_FAIL. + return IPC_OK(); } if (mNodeId.EqualsLiteral("null")) { // Refuse to open storage if the page is opened from local disk, // or shared across origin. LOGD(("GMPStorageParent[%p]::RecvOpen(record='%s') failed; null nodeId", this, aRecordName.get())); Unused << SendOpenComplete(aRecordName, GMPGenericErr); @@ -97,17 +98,18 @@ mozilla::ipc::IPCResult GMPStorageParent } mozilla::ipc::IPCResult GMPStorageParent::RecvRead( const nsCString& aRecordName) { LOGD( ("GMPStorageParent[%p]::RecvRead(record='%s')", this, aRecordName.get())); if (mShutdown) { - return IPC_FAIL_NO_REASON(this); + // Shutdown is an expected state, so we do not IPC_FAIL. + return IPC_OK(); } nsTArray<uint8_t> data; if (!mStorage->IsOpen(aRecordName)) { LOGD(("GMPStorageParent[%p]::RecvRead(record='%s') failed; record not open", this, aRecordName.get())); Unused << SendReadComplete(aRecordName, GMPClosedErr, data); } else { @@ -123,17 +125,18 @@ mozilla::ipc::IPCResult GMPStorageParent } mozilla::ipc::IPCResult GMPStorageParent::RecvWrite( const nsCString& aRecordName, nsTArray<uint8_t>&& aBytes) { LOGD(("GMPStorageParent[%p]::RecvWrite(record='%s') %zu bytes", this, aRecordName.get(), aBytes.Length())); if (mShutdown) { - return IPC_FAIL_NO_REASON(this); + // Shutdown is an expected state, so we do not IPC_FAIL. + return IPC_OK(); } if (!mStorage->IsOpen(aRecordName)) { LOGD(("GMPStorageParent[%p]::RecvWrite(record='%s') failed record not open", this, aRecordName.get())); Unused << SendWriteComplete(aRecordName, GMPClosedErr); return IPC_OK(); }
--- a/dom/media/gmp/GMPVideoDecoderChild.cpp +++ b/dom/media/gmp/GMPVideoDecoderChild.cpp @@ -87,31 +87,31 @@ void GMPVideoDecoderChild::Error(GMPErr SendError(aError); } mozilla::ipc::IPCResult GMPVideoDecoderChild::RecvInitDecode( const GMPVideoCodec& aCodecSettings, nsTArray<uint8_t>&& aCodecSpecific, const int32_t& aCoreCount) { if (!mVideoDecoder) { - return IPC_FAIL_NO_REASON(this); + return IPC_FAIL(this, "!mVideoDecoder"); } // Ignore any return code. It is OK for this to fail without killing the // process. mVideoDecoder->InitDecode(aCodecSettings, aCodecSpecific.Elements(), aCodecSpecific.Length(), this, aCoreCount); return IPC_OK(); } mozilla::ipc::IPCResult GMPVideoDecoderChild::RecvDecode( const GMPVideoEncodedFrameData& aInputFrame, const bool& aMissingFrames, nsTArray<uint8_t>&& aCodecSpecificInfo, const int64_t& aRenderTimeMs) { if (!mVideoDecoder) { - return IPC_FAIL_NO_REASON(this); + return IPC_FAIL(this, "!mVideoDecoder"); } auto f = new GMPVideoEncodedFrameImpl(aInputFrame, &mVideoHost); // Ignore any return code. It is OK for this to fail without killing the // process. mVideoDecoder->Decode(f, aMissingFrames, aCodecSpecificInfo.Elements(), aCodecSpecificInfo.Length(), aRenderTimeMs); @@ -125,29 +125,29 @@ mozilla::ipc::IPCResult GMPVideoDecoderC mVideoHost.SharedMemMgr()->MgrDeallocShmem(GMPSharedMem::kGMPFrameData, aFrameBuffer); } return IPC_OK(); } mozilla::ipc::IPCResult GMPVideoDecoderChild::RecvReset() { if (!mVideoDecoder) { - return IPC_FAIL_NO_REASON(this); + return IPC_FAIL(this, "!mVideoDecoder"); } // Ignore any return code. It is OK for this to fail without killing the // process. mVideoDecoder->Reset(); return IPC_OK(); } mozilla::ipc::IPCResult GMPVideoDecoderChild::RecvDrain() { if (!mVideoDecoder) { - return IPC_FAIL_NO_REASON(this); + return IPC_FAIL(this, "!mVideoDecoder"); } // Ignore any return code. It is OK for this to fail without killing the // process. mVideoDecoder->Drain(); return IPC_OK(); }
--- a/dom/media/gmp/GMPVideoDecoderParent.cpp +++ b/dom/media/gmp/GMPVideoDecoderParent.cpp @@ -282,145 +282,107 @@ void GMPVideoDecoderParent::ActorDestroy mozilla::ipc::IPCResult GMPVideoDecoderParent::RecvDecoded( const GMPVideoi420FrameData& aDecodedFrame) { --mFrameCount; GMP_LOG_VERBOSE("GMPVideoDecoderParent[%p]::RecvDecoded() timestamp=%" PRId64 " frameCount=%d", this, aDecodedFrame.mTimestamp(), mFrameCount); - if (!mCallback) { - return IPC_FAIL_NO_REASON(this); - } + if (mCallback) { + if (GMPVideoi420FrameImpl::CheckFrameData(aDecodedFrame)) { + auto f = new GMPVideoi420FrameImpl(aDecodedFrame, &mVideoHost); - if (!GMPVideoi420FrameImpl::CheckFrameData(aDecodedFrame)) { - GMP_LOG_ERROR( - "GMPVideoDecoderParent[%p]::RecvDecoded() " - "timestamp=%" PRId64 " decoded frame corrupt, ignoring", - this, aDecodedFrame.mTimestamp()); - return IPC_FAIL_NO_REASON(this); + mCallback->Decoded(f); + } else { + GMP_LOG_ERROR( + "GMPVideoDecoderParent[%p]::RecvDecoded() " + "timestamp=%" PRId64 " decoded frame corrupt, ignoring", + this, aDecodedFrame.mTimestamp()); + // TODO: Verify if we should take more serious the arrival of + // a corrupted frame, see bug 1750506. + } } - auto f = new GMPVideoi420FrameImpl(aDecodedFrame, &mVideoHost); - - // Ignore any return code. It is OK for this to fail without killing the - // process. - mCallback->Decoded(f); return IPC_OK(); } mozilla::ipc::IPCResult GMPVideoDecoderParent::RecvReceivedDecodedReferenceFrame( const uint64_t& aPictureId) { - if (!mCallback) { - return IPC_FAIL_NO_REASON(this); + if (mCallback) { + mCallback->ReceivedDecodedReferenceFrame(aPictureId); } - // Ignore any return code. It is OK for this to fail without killing the - // process. - mCallback->ReceivedDecodedReferenceFrame(aPictureId); - return IPC_OK(); } mozilla::ipc::IPCResult GMPVideoDecoderParent::RecvReceivedDecodedFrame( const uint64_t& aPictureId) { - if (!mCallback) { - return IPC_FAIL_NO_REASON(this); + if (mCallback) { + mCallback->ReceivedDecodedFrame(aPictureId); } - // Ignore any return code. It is OK for this to fail without killing the - // process. - mCallback->ReceivedDecodedFrame(aPictureId); - return IPC_OK(); } mozilla::ipc::IPCResult GMPVideoDecoderParent::RecvInputDataExhausted() { GMP_LOG_VERBOSE("GMPVideoDecoderParent[%p]::RecvInputDataExhausted()", this); - if (!mCallback) { - return IPC_FAIL_NO_REASON(this); + if (mCallback) { + mCallback->InputDataExhausted(); } - // Ignore any return code. It is OK for this to fail without killing the - // process. - mCallback->InputDataExhausted(); - return IPC_OK(); } mozilla::ipc::IPCResult GMPVideoDecoderParent::RecvDrainComplete() { GMP_LOG_DEBUG("GMPVideoDecoderParent[%p]::RecvDrainComplete() frameCount=%d", this, mFrameCount); nsAutoString msg; msg.AppendLiteral( "GMPVideoDecoderParent::RecvDrainComplete() outstanding frames="); msg.AppendInt(mFrameCount); LogToBrowserConsole(msg); - if (!mCallback) { - // We anticipate shutting down in the middle of a drain in the - // `UnblockResetAndDrain` method, which is called when we shutdown, so - // everything is sunny. - return IPC_OK(); - } + if (mCallback && mIsAwaitingDrainComplete) { + mIsAwaitingDrainComplete = false; - if (!mIsAwaitingDrainComplete) { - return IPC_OK(); + mCallback->DrainComplete(); } - mIsAwaitingDrainComplete = false; - - // Ignore any return code. It is OK for this to fail without killing the - // process. - mCallback->DrainComplete(); return IPC_OK(); } mozilla::ipc::IPCResult GMPVideoDecoderParent::RecvResetComplete() { GMP_LOG_DEBUG("GMPVideoDecoderParent[%p]::RecvResetComplete()", this); CancelResetCompleteTimeout(); - if (!mCallback) { - // We anticipate shutting down in the middle of a reset in the - // `UnblockResetAndDrain` method, which is called when we shutdown, so - // everything is good if we reach here. - return IPC_OK(); - } + if (mCallback && mIsAwaitingResetComplete) { + mIsAwaitingResetComplete = false; + mFrameCount = 0; - if (!mIsAwaitingResetComplete) { - return IPC_OK(); + mCallback->ResetComplete(); } - mIsAwaitingResetComplete = false; - mFrameCount = 0; - - // Ignore any return code. It is OK for this to fail without killing the - // process. - mCallback->ResetComplete(); return IPC_OK(); } mozilla::ipc::IPCResult GMPVideoDecoderParent::RecvError(const GMPErr& aError) { GMP_LOG_DEBUG("GMPVideoDecoderParent[%p]::RecvError(error=%d)", this, aError); - if (!mCallback) { - return IPC_FAIL_NO_REASON(this); - } + if (mCallback) { + // Ensure if we've received an error while waiting for a ResetComplete + // or DrainComplete notification, we'll unblock the caller before processing + // the error. + UnblockResetAndDrain(); - // Ensure if we've received an error while waiting for a ResetComplete - // or DrainComplete notification, we'll unblock the caller before processing - // the error. - UnblockResetAndDrain(); - - // Ignore any return code. It is OK for this to fail without killing the - // process. - mCallback->Error(aError); + mCallback->Error(aError); + } return IPC_OK(); } mozilla::ipc::IPCResult GMPVideoDecoderParent::RecvShutdown() { GMP_LOG_DEBUG("GMPVideoDecoderParent[%p]::RecvShutdown()", this); Shutdown(); @@ -440,17 +402,17 @@ mozilla::ipc::IPCResult GMPVideoDecoderP const uint32_t& aFrameBufferSize, Shmem* aMem) { ipc::Shmem mem; if (!mVideoHost.SharedMemMgr()->MgrAllocShmem( GMPSharedMem::kGMPFrameData, aFrameBufferSize, ipc::SharedMemory::TYPE_BASIC, &mem)) { GMP_LOG_ERROR("%s: Failed to get a shared mem buffer for Child! size %u", __FUNCTION__, aFrameBufferSize); - return IPC_FAIL_NO_REASON(this); + return IPC_FAIL(this, "Failed to get a shared mem buffer for Child!"); } *aMem = mem; mem = ipc::Shmem(); return IPC_OK(); } mozilla::ipc::IPCResult GMPVideoDecoderParent::Recv__delete__() { GMP_LOG_DEBUG("GMPVideoDecoderParent[%p]::Recv__delete__()", this);
--- a/dom/media/gmp/GMPVideoEncoderChild.cpp +++ b/dom/media/gmp/GMPVideoEncoderChild.cpp @@ -57,34 +57,34 @@ void GMPVideoEncoderChild::Error(GMPErr SendError(aError); } mozilla::ipc::IPCResult GMPVideoEncoderChild::RecvInitEncode( const GMPVideoCodec& aCodecSettings, nsTArray<uint8_t>&& aCodecSpecific, const int32_t& aNumberOfCores, const uint32_t& aMaxPayloadSize) { if (!mVideoEncoder) { - return IPC_FAIL_NO_REASON(this); + return IPC_FAIL(this, "!mVideoDecoder"); } // Ignore any return code. It is OK for this to fail without killing the // process. mVideoEncoder->InitEncode(aCodecSettings, aCodecSpecific.Elements(), aCodecSpecific.Length(), this, aNumberOfCores, aMaxPayloadSize); return IPC_OK(); } mozilla::ipc::IPCResult GMPVideoEncoderChild::RecvEncode( const GMPVideoi420FrameData& aInputFrame, nsTArray<uint8_t>&& aCodecSpecificInfo, nsTArray<GMPVideoFrameType>&& aFrameTypes) { if (!mVideoEncoder) { - return IPC_FAIL_NO_REASON(this); + return IPC_FAIL(this, "!mVideoDecoder"); } auto f = new GMPVideoi420FrameImpl(aInputFrame, &mVideoHost); // Ignore any return code. It is OK for this to fail without killing the // process. mVideoEncoder->Encode(f, aCodecSpecificInfo.Elements(), aCodecSpecificInfo.Length(), aFrameTypes.Elements(), @@ -100,43 +100,43 @@ mozilla::ipc::IPCResult GMPVideoEncoderC aEncodedBuffer); } return IPC_OK(); } mozilla::ipc::IPCResult GMPVideoEncoderChild::RecvSetChannelParameters( const uint32_t& aPacketLoss, const uint32_t& aRTT) { if (!mVideoEncoder) { - return IPC_FAIL_NO_REASON(this); + return IPC_FAIL(this, "!mVideoDecoder"); } // Ignore any return code. It is OK for this to fail without killing the // process. mVideoEncoder->SetChannelParameters(aPacketLoss, aRTT); return IPC_OK(); } mozilla::ipc::IPCResult GMPVideoEncoderChild::RecvSetRates( const uint32_t& aNewBitRate, const uint32_t& aFrameRate) { if (!mVideoEncoder) { - return IPC_FAIL_NO_REASON(this); + return IPC_FAIL(this, "!mVideoDecoder"); } // Ignore any return code. It is OK for this to fail without killing the // process. mVideoEncoder->SetRates(aNewBitRate, aFrameRate); return IPC_OK(); } mozilla::ipc::IPCResult GMPVideoEncoderChild::RecvSetPeriodicKeyFrames( const bool& aEnable) { if (!mVideoEncoder) { - return IPC_FAIL_NO_REASON(this); + return IPC_FAIL(this, "!mVideoDecoder"); } // Ignore any return code. It is OK for this to fail without killing the // process. mVideoEncoder->SetPeriodicKeyFrames(aEnable); return IPC_OK(); } @@ -149,18 +149,19 @@ mozilla::ipc::IPCResult GMPVideoEncoderC // return a frame they can use. Don't call the GMP's EncodingComplete() // now and don't delete the GMPVideoEncoderChild, defer processing the // EncodingComplete() until once the Alloc() finishes. mPendingEncodeComplete = true; return IPC_OK(); } if (!mVideoEncoder) { + // There is not much to clean up anymore. Unused << Send__delete__(this); - return IPC_FAIL_NO_REASON(this); + return IPC_OK(); } // Ignore any return code. It is OK for this to fail without killing the // process. mVideoEncoder->EncodingComplete(); mVideoHost.DoneWithAPI();
--- a/dom/media/gmp/GMPVideoEncoderParent.cpp +++ b/dom/media/gmp/GMPVideoEncoderParent.cpp @@ -229,37 +229,29 @@ void GMPVideoEncoderParent::ActorDestroy } mVideoHost.ActorDestroyed(); // same as DoneWithAPI MaybeDisconnect(aWhy == AbnormalShutdown); } mozilla::ipc::IPCResult GMPVideoEncoderParent::RecvEncoded( const GMPVideoEncodedFrameData& aEncodedFrame, nsTArray<uint8_t>&& aCodecSpecificInfo) { - if (!mCallback) { - return IPC_FAIL_NO_REASON(this); + if (mCallback) { + auto f = new GMPVideoEncodedFrameImpl(aEncodedFrame, &mVideoHost); + mCallback->Encoded(f, aCodecSpecificInfo); + f->Destroy(); } - - auto f = new GMPVideoEncodedFrameImpl(aEncodedFrame, &mVideoHost); - // Ignore any return code. It is OK for this to fail without killing the - // process. This can be called on any thread (or more than one) - mCallback->Encoded(f, aCodecSpecificInfo); - f->Destroy(); return IPC_OK(); } mozilla::ipc::IPCResult GMPVideoEncoderParent::RecvError(const GMPErr& aError) { - if (!mCallback) { - return IPC_FAIL_NO_REASON(this); + if (mCallback) { + mCallback->Error(aError); } - // Ignore any return code. It is OK for this to fail without killing the - // process. - mCallback->Error(aError); - return IPC_OK(); } mozilla::ipc::IPCResult GMPVideoEncoderParent::RecvShutdown() { Shutdown(); return IPC_OK(); } @@ -289,17 +281,17 @@ mozilla::ipc::IPCResult GMPVideoEncoderP // in ::Shutdown, but doesn't hurt if (!mVideoHost.SharedMemMgr() || !mVideoHost.SharedMemMgr()->MgrAllocShmem( GMPSharedMem::kGMPEncodedData, aEncodedBufferSize, ipc::SharedMemory::TYPE_BASIC, &mem)) { GMP_LOG_ERROR( "%s::%s: Failed to get a shared mem buffer for Child! size %u", __CLASS__, __FUNCTION__, aEncodedBufferSize); - return IPC_FAIL_NO_REASON(this); + return IPC_FAIL(this, "Failed to get a shared mem buffer for Child!"); } *aMem = mem; mem = ipc::Shmem(); return IPC_OK(); } mozilla::ipc::IPCResult GMPVideoEncoderParent::Recv__delete__() { if (mPlugin) {
--- a/dom/messagechannel/MessagePortParent.cpp +++ b/dom/messagechannel/MessagePortParent.cpp @@ -34,62 +34,79 @@ bool MessagePortParent::Entangle(const n MOZ_ASSERT(!mEntangled); return mService->RequestEntangling(this, aDestinationUUID, aSequenceID); } mozilla::ipc::IPCResult MessagePortParent::RecvPostMessages( nsTArray<MessageData>&& aMessages) { + if (!mService) { + NS_WARNING("PostMessages is called after a shutdown!"); + // This implies most probably that CloseAndDelete() has been already called + // such that we have no better option than to silently ignore this call. + return IPC_OK(); + } + + if (!mEntangled) { + // If we were shut down, the above condition already bailed out. So this + // should actually never happen and returning a failure is fine. + return IPC_FAIL(this, "RecvPostMessages not entangled"); + } + // This converts the object in a data struct where we have BlobImpls. FallibleTArray<RefPtr<SharedMessageBody>> messages; if (NS_WARN_IF(!SharedMessageBody::FromMessagesToSharedParent(aMessages, messages))) { - return IPC_FAIL_NO_REASON(this); - } - - if (!mEntangled) { - return IPC_FAIL_NO_REASON(this); - } - - if (!mService) { - NS_WARNING("Entangle is called after a shutdown!"); - return IPC_FAIL_NO_REASON(this); + // FromMessagesToSharedParent() returns false only if the array allocation + // failed. + // See bug 1750497 for further discussion if this is the wanted behavior. + return IPC_FAIL(this, "SharedMessageBody::FromMessagesToSharedParent"); } if (messages.IsEmpty()) { - return IPC_FAIL_NO_REASON(this); + // An empty payload can be safely ignored. + return IPC_OK(); } if (!mService->PostMessages(this, std::move(messages))) { - return IPC_FAIL_NO_REASON(this); + // TODO: Verify if all failure conditions of PostMessages() merit an + // IPC_FAIL. See bug 1750499. + return IPC_FAIL(this, "RecvPostMessages->PostMessages"); } return IPC_OK(); } mozilla::ipc::IPCResult MessagePortParent::RecvDisentangle( nsTArray<MessageData>&& aMessages) { + if (!mService) { + NS_WARNING("Entangle is called after a shutdown!"); + // This implies most probably that CloseAndDelete() has been already called + // such that we can silently ignore this call. + return IPC_OK(); + } + + if (!mEntangled) { + // If we were shut down, the above condition already bailed out. So this + // should actually never happen and returning a failure is fine. + return IPC_FAIL(this, "RecvDisentangle not entangled"); + } + // This converts the object in a data struct where we have BlobImpls. FallibleTArray<RefPtr<SharedMessageBody>> messages; if (NS_WARN_IF(!SharedMessageBody::FromMessagesToSharedParent(aMessages, messages))) { - return IPC_FAIL_NO_REASON(this); - } - - if (!mEntangled) { - return IPC_FAIL_NO_REASON(this); - } - - if (!mService) { - NS_WARNING("Entangle is called after a shutdown!"); - return IPC_FAIL_NO_REASON(this); + // TODO: Verify if failed allocations merit an IPC_FAIL. See bug 1750497. + return IPC_FAIL(this, "SharedMessageBody::FromMessagesToSharedParent"); } if (!mService->DisentanglePort(this, std::move(messages))) { - return IPC_FAIL_NO_REASON(this); + // TODO: Verify if all failure conditions of DisentanglePort() merit an + // IPC_FAIL. See bug 1750501. + return IPC_FAIL(this, "RecvDisentangle->DisentanglePort"); } CloseAndDelete(); return IPC_OK(); } mozilla::ipc::IPCResult MessagePortParent::RecvStopSendingData() { if (!mEntangled) { @@ -101,17 +118,17 @@ mozilla::ipc::IPCResult MessagePortParen return IPC_OK(); } mozilla::ipc::IPCResult MessagePortParent::RecvClose() { if (mService) { MOZ_ASSERT(mEntangled); if (!mService->ClosePort(this)) { - return IPC_FAIL_NO_REASON(this); + return IPC_FAIL(this, "RecvClose->ClosePort"); } Close(); } MOZ_ASSERT(!mEntangled); Unused << Send__delete__(this);
--- a/dom/security/nsContentSecurityManager.cpp +++ b/dom/security/nsContentSecurityManager.cpp @@ -675,16 +675,20 @@ static void LogHTTPSOnlyInfo(nsILoadInfo } if (httpsOnlyStatus & nsILoadInfo::HTTPS_ONLY_EXEMPT) { MOZ_LOG(sCSMLog, LogLevel::Verbose, (" - HTTPS_ONLY_EXEMPT")); } if (httpsOnlyStatus & nsILoadInfo::HTTPS_ONLY_TOP_LEVEL_LOAD_IN_PROGRESS) { MOZ_LOG(sCSMLog, LogLevel::Verbose, (" - HTTPS_ONLY_TOP_LEVEL_LOAD_IN_PROGRESS")); } + if (httpsOnlyStatus & nsILoadInfo::HTTPS_ONLY_DOWNLOAD_IN_PROGRESS) { + MOZ_LOG(sCSMLog, LogLevel::Verbose, + (" - HTTPS_ONLY_DOWNLOAD_IN_PROGRESS")); + } if (httpsOnlyStatus & nsILoadInfo::HTTPS_ONLY_DO_NOT_LOG_TO_CONSOLE) { MOZ_LOG(sCSMLog, LogLevel::Verbose, (" - HTTPS_ONLY_DO_NOT_LOG_TO_CONSOLE")); } if (httpsOnlyStatus & nsILoadInfo::HTTPS_ONLY_UPGRADED_HTTPS_FIRST) { MOZ_LOG(sCSMLog, LogLevel::Verbose, (" - HTTPS_ONLY_UPGRADED_HTTPS_FIRST")); }
--- a/dom/security/nsHTTPSOnlyUtils.cpp +++ b/dom/security/nsHTTPSOnlyUtils.cpp @@ -981,18 +981,21 @@ TestHTTPAnswerRunnable::Notify(nsITimer* mTimer = nullptr; } // If the original channel has already started loading at this point // then there is no need to do the dance. nsCOMPtr<nsIChannel> origChannel = mDocumentLoadListener->GetChannel(); nsCOMPtr<nsILoadInfo> origLoadInfo = origChannel->LoadInfo(); uint32_t origHttpsOnlyStatus = origLoadInfo->GetHttpsOnlyStatus(); - if ((origHttpsOnlyStatus & - nsILoadInfo::HTTPS_ONLY_TOP_LEVEL_LOAD_IN_PROGRESS)) { + uint32_t topLevelLoadInProgress = + origHttpsOnlyStatus & nsILoadInfo::HTTPS_ONLY_TOP_LEVEL_LOAD_IN_PROGRESS; + uint32_t downloadInProgress = + origHttpsOnlyStatus & nsILoadInfo::HTTPS_ONLY_DOWNLOAD_IN_PROGRESS; + if (topLevelLoadInProgress || downloadInProgress) { return NS_OK; } mozilla::OriginAttributes attrs = origLoadInfo->GetOriginAttributes(); RefPtr<nsIPrincipal> nullPrincipal = mozilla::NullPrincipal::CreateWithInheritedAttributes(attrs); uint32_t loadFlags =
--- a/dom/security/test/https-first/browser.ini +++ b/dom/security/test/https-first/browser.ini @@ -16,8 +16,12 @@ support-files = file_httpsfirst_speculat support-files = file_download_attribute.html file_download_attribute.sjs [browser_mixed_content_download.js] skip-if = win10_2004 && debug # Bug 1723573 support-files = download_page.html download_server.sjs +[browser_slow_download.js] +support-files = + file_slow_download.html + file_slow_download.sjs
new file mode 100644 --- /dev/null +++ b/dom/security/test/https-first/browser_slow_download.js @@ -0,0 +1,162 @@ +"use strict"; + +XPCOMUtils.defineLazyModuleGetters(this, { + BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.jsm", +}); +// Create a uri for an https site +const testPath = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + "https://example.com" +); +const TEST_URI = testPath + "file_slow_download.html"; +const EXPECTED_DOWNLOAD_URL = + "example.com/browser/dom/security/test/https-first/file_slow_download.sjs"; + +// Since the server send the complete download file after 3 seconds we need an longer timeout +requestLongerTimeout(4); + +function promisePanelOpened() { + if (DownloadsPanel.panel && DownloadsPanel.panel.state == "open") { + return Promise.resolve(); + } + return BrowserTestUtils.waitForEvent(DownloadsPanel.panel, "popupshown"); +} + +/** + * Waits for a download to finish, in case it has not finished already. + * + * @param aDownload + * The Download object to wait upon. + * + * @return {Promise} + * @resolves When the download has finished successfully. + * @rejects JavaScript exception if the download failed. + */ +function promiseDownloadStopped(aDownload) { + if (!aDownload.stopped) { + // The download is in progress, wait for the current attempt to finish and + // report any errors that may occur. + return aDownload.start(); + } + + if (aDownload.succeeded) { + return Promise.resolve(); + } + + // The download failed or was canceled. + return Promise.reject(aDownload.error || new Error("Download canceled.")); +} + +// Verifys that no background request was send +let requestCounter = 0; +function examiner() { + SpecialPowers.addObserver(this, "specialpowers-http-notify-request"); +} + +examiner.prototype = { + observe(subject, topic, data) { + if (topic !== "specialpowers-http-notify-request") { + return; + } + // On Android we have other requests appear here as well. Let's make + // sure we only evaluate requests triggered by the test. + if ( + !data.startsWith("http://example.com") && + !data.startsWith("https://example.com") + ) { + return; + } + ++requestCounter; + if (requestCounter == 1) { + is(data, TEST_URI, "Download start page is https"); + return; + } + if (requestCounter == 2) { + // The specialpowers-http-notify-request fires before the internal redirect( /upgrade) to + // https happens. + is( + data, + "http://" + EXPECTED_DOWNLOAD_URL, + "First download request is http (internal)" + ); + return; + } + if (requestCounter == 3) { + is( + data, + "https://" + EXPECTED_DOWNLOAD_URL, + "Download got upgraded to https" + ); + return; + } + ok(false, "we should never get here, but just in case"); + }, + remove() { + SpecialPowers.removeObserver(this, "specialpowers-http-notify-request"); + }, +}; + +// Test description: +// 1. Open https://example.com +// 2. Start download - location of download is http +// 3. https-first upgrades to https +// 4. Server send first part of download and after 3 seconds the rest +// 5. Complete download of text file +add_task(async function test_slow_download() { + await SpecialPowers.pushPrefEnv({ + set: [ + ["dom.security.https_first", true], + // ensure that download panel gets opened + ["browser.download.improvements_to_download_panel", true], + ], + }); + + // remove all previous downloads + let downloadsList = await Downloads.getList(Downloads.PUBLIC); + await downloadsList.removeFinished(); + + // add observer to ensure that the background request gets canceled for the upgraded Download + this.examiner = new examiner(); + + let downloadsPanelPromise = promisePanelOpened(); + let downloadsPromise = Downloads.getList(Downloads.PUBLIC); + BrowserTestUtils.loadURI(gBrowser, TEST_URI); + // wait for downloadsPanel to open before continuing with test + await downloadsPanelPromise; + let downloadList = await downloadsPromise; + is(DownloadsPanel.isPanelShowing, true, "DownloadsPanel should be open."); + is(downloadList._downloads.length, 1, "File should be downloaded."); + let [download] = downloadList._downloads; + // wait for download to finish (with success or error) + await promiseDownloadStopped(download); + is(download.contentType, "text/plain", "File contentType should be correct."); + // ensure https-first did upgrade the scheme. + is( + download.source.url, + "https://" + EXPECTED_DOWNLOAD_URL, + "Scheme should be https." + ); + // ensure that no background request was send + is( + requestCounter, + 3, + "three requests total (download page, download http, download https/ upgraded)" + ); + // ensure that downloaded is complete + is(download.target.size, 25, "Download size is correct"); + //clean up + this.examiner.remove(); + info("cleaning up downloads"); + try { + if (Services.appinfo.OS === "WINNT") { + // We need to make the file writable to delete it on Windows. + await IOUtils.setPermissions(download.target.path, 0o600); + } + await IOUtils.remove(download.target.path); + } catch (error) { + info("The file " + download.target.path + " is not removed, " + error); + } + + await downloadList.remove(download); + await download.finalize(); +});
new file mode 100644 --- /dev/null +++ b/dom/security/test/https-first/file_slow_download.html @@ -0,0 +1,14 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test slow download from an http site that gets upgraded to https</title> +</head> +<body> + <a href="http://example.com/browser/dom/security/test/https-first/file_slow_download.sjs" download="large-dummy-file.txt" id="testlink">download by attribute</a> + <script> + // click the link to start download + let testlink = document.getElementById("testlink"); + testlink.click(); + </script> + </body> +</html>
new file mode 100644 --- /dev/null +++ b/dom/security/test/https-first/file_slow_download.sjs @@ -0,0 +1,26 @@ +"use strict"; +let timer; + +// Send a part of the file then wait for 3 second before sending the rest. +// If download isn't exempt from background timer of https-only/-first then the download +// gets cancelled before it completed. +const DELAY_MS = 3500; +function handleRequest(request, response) { + response.processAsync(); + timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); + response.setHeader("Cache-Control", "no-cache", false); + response.setHeader( + "Content-Disposition", + "attachment; filename=large-dummy-file.txt" + ); + response.setHeader("Content-Type", "text/plain"); + response.write("Begin the file"); + timer.init( + () => { + response.write("End of file"); + response.finish(); + }, + DELAY_MS, + Ci.nsITimer.TYPE_ONE_SHOT + ); +}
--- a/dom/webgpu/Queue.cpp +++ b/dom/webgpu/Queue.cpp @@ -111,44 +111,23 @@ void Queue::WriteTexture(const dom::GPUI if (aData.IsArrayBuffer()) { const auto& ab = aData.GetAsArrayBuffer(); ab.ComputeState(); availableSize = ab.Length(); data = ab.Data(); } MOZ_ASSERT(data != nullptr); - const auto bpb = aDestination.mTexture->mBytesPerBlock; - if (!bpb) { - aRv.ThrowAbortError(nsPrintfCString("Invalid texture format")); - return; - } - if (extent.width == 0 || extent.height == 0 || - extent.depth_or_array_layers == 0) { - aRv.ThrowAbortError(nsPrintfCString("Invalid copy size")); + const auto checkedSize = + CheckedInt<size_t>(availableSize) - aDataLayout.mOffset; + if (!checkedSize.isValid()) { + aRv.ThrowAbortError(nsPrintfCString("Offset is higher than the size")); return; } - - // TODO: support block-compressed formats - const auto fullRows = (CheckedInt<size_t>(extent.depth_or_array_layers - 1) * - aDataLayout.mRowsPerImage + - extent.height - 1); - const auto checkedSize = fullRows * aDataLayout.mBytesPerRow + - CheckedInt<size_t>(extent.width) * bpb.value(); - if (!checkedSize.isValid()) { - aRv.ThrowRangeError("Mapped size is too large"); - return; - } - - const auto& size = checkedSize.value(); - if (availableSize < aDataLayout.mOffset || - size > (availableSize - aDataLayout.mOffset)) { - aRv.ThrowAbortError(nsPrintfCString("Wrong data size %" PRIuPTR, size)); - return; - } + const auto size = checkedSize.value(); ipc::Shmem shmem; if (!mBridge->AllocShmem(size, ipc::Shmem::SharedMemory::TYPE_BASIC, &shmem)) { aRv.ThrowAbortError( nsPrintfCString("Unable to allocate shmem of size %" PRIuPTR, size)); return; }
--- a/dom/webidl/ImageBitmap.webidl +++ b/dom/webidl/ImageBitmap.webidl @@ -392,12 +392,12 @@ enum PremultiplyAlpha { "none", "premult enum ColorSpaceConversion { "none", "default" }; //enum ResizeQuality { "pixelated", "low", "medium", "high" }; dictionary ImageBitmapOptions { ImageOrientation imageOrientation = "none"; PremultiplyAlpha premultiplyAlpha = "default"; // options to be added bugs: 1363861 ColorSpaceConversion colorSpaceConversion = "default"; - //[EnforceRange] unsigned long resizeWidth; - //[EnforceRange] unsigned long resizeHeight; + [EnforceRange] unsigned long resizeWidth; + [EnforceRange] unsigned long resizeHeight; //ResizeQuality resizeQuality = "low"; };
--- a/gfx/wgpu_bindings/src/server.rs +++ b/gfx/wgpu_bindings/src/server.rs @@ -613,17 +613,17 @@ pub unsafe extern "C" fn wgpu_server_que ) { let action: QueueWriteAction = bincode::deserialize(byte_buf.as_slice()).unwrap(); let data = slice::from_raw_parts(data, data_length); let result = match action { QueueWriteAction::Buffer { dst, offset } => { gfx_select!(self_id => global.queue_write_buffer(self_id, dst, offset, data)) } QueueWriteAction::Texture { dst, layout, size } => { - gfx_select!(self_id => global.queue_write_texture(self_id, &dst, &data, &layout, &size)) + gfx_select!(self_id => global.queue_write_texture(self_id, &dst, data, &layout, &size)) } }; if let Err(err) = result { error_buf.init(err); } } #[no_mangle]
--- a/ipc/glue/ProtocolUtils.cpp +++ b/ipc/glue/ProtocolUtils.cpp @@ -57,16 +57,21 @@ MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLAT namespace ipc { IPCResult IPCResult::Fail(NotNull<IProtocol*> actor, const char* where, const char* why) { // Calls top-level protocol to handle the error. nsPrintfCString errorMsg("%s %s\n", where, why); actor->GetIPCChannel()->Listener()->ProcessingError( HasResultCodes::MsgProcessingError, errorMsg.get()); + + MOZ_ASSERT_UNLESS_FUZZING(false, + "Please ensure to IPC_FAIL only when in an " + "unrecoverable, unexpected state."); + return IPCResult(false); } void AnnotateSystemError() { int64_t error = 0; #if defined(XP_WIN) error = ::GetLastError(); #elif defined(OS_POSIX)
--- a/js/src/jit-test/tests/wasm/simd/avx2-x64-ion-codegen.js +++ b/js/src/jit-test/tests/wasm/simd/avx2-x64-ion-codegen.js @@ -18,16 +18,30 @@ function codegenTestX64_v128xv128_v128_a (func (export "f") (param v128 v128 v128) (result v128) (${op} (local.get 1) (local.get 2)))`), 'f', expected, options); } } +// Utility function to test SIMD operations encoding, where the input argument +// has the specified type (T). +// inputs: [[type, complete-opname, expected-pattern], ...] +function codegenTestX64_T_v128_avxhack(inputs, options = {}) { + for ( let [ty, op, expected] of inputs ) { + codegenTestX64_adhoc(wrap(options, ` + (func (export "f") (param ${ty}) (result v128) + (${op} (local.get 0)))`), + 'f', + expected, + options); + } +} + // Simple binary ops: e.g. add, sub, mul codegenTestX64_v128xv128_v128_avxhack( [['i32x4.add', `c5 f1 fe c2 vpaddd %xmm2, %xmm1, %xmm0`], ['i32x4.sub', `c5 f1 fa c2 vpsubd %xmm2, %xmm1, %xmm0`], ['i32x4.mul', `c4 e2 71 40 c2 vpmulld %xmm2, %xmm1, %xmm0`], ['f32x4.add', `c5 f0 58 c2 vaddps %xmm2, %xmm1, %xmm0`], ['f32x4.sub', `c5 f0 5c c2 vsubps %xmm2, %xmm1, %xmm0`], ['f32x4.mul', `c5 f0 59 c2 vmulps %xmm2, %xmm1, %xmm0`], @@ -65,8 +79,30 @@ codegenTestX64_v128xv128_v128_avxhack( codegenTestX64_adhoc(`(module (func (export "f") (param v128 v128 i64) (result v128) (i64x2.replace_lane 1 (local.get 1) (local.get 2))))`, 'f', ` c4 .. f1 22 .. 01 vpinsrq \\$0x01, %r\\w+, %xmm1, %xmm0` ); // rdi (Linux) or r8 (Win) +if (isAvxPresent(2)) { + // First i32 arg is: edi on Linux, and ecx on Windows. + codegenTestX64_T_v128_avxhack( + [['i32', 'i8x16.splat', ` +c5 f9 6e .. vmovd %e\\w+, %xmm0 +c4 e2 79 78 c0 vpbroadcastb %xmm0, %xmm0`], + ['i32', 'i16x8.splat', ` +c5 f9 6e .. vmovd %e\\w+, %xmm0 +c4 e2 79 79 c0 vpbroadcastw %xmm0, %xmm0`], + ['i32', 'i32x4.splat', ` +c5 f9 6e .. vmovd %e\\w+, %xmm0 +c4 e2 79 58 c0 vpbroadcastd %xmm0, %xmm0`], + ['f32', 'f32x4.splat', `c4 e2 79 18 c0 vbroadcastss %xmm0, %xmm0`]]); + + codegenTestX64_T_v128_avxhack( + [['i32', 'v128.load8_splat', + 'c4 c2 79 78 04 .. vpbroadcastbb \\(%r15,%r\\w+,1\\), %xmm0'], + ['i32', 'v128.load16_splat', + 'c4 c2 79 79 04 .. vpbroadcastww \\(%r15,%r\\w+,1\\), %xmm0'], + ['i32', 'v128.load32_splat', + 'c4 c2 79 18 04 .. vbroadcastssl \\(%r15,%r\\w+,1\\), %xmm0']], {memory: 1}); +}
--- a/js/src/jit-test/tests/wasm/simd/splat-x64-ion-codegen.js +++ b/js/src/jit-test/tests/wasm/simd/splat-x64-ion-codegen.js @@ -2,17 +2,17 @@ // Test that there are no extraneous moves or other instructions for splat and // other splat-like operations that can reuse its input for its output and/or // has a specializable code path. See README-codegen.md for general information // about this type of test case. codegenTestX64_PTYPE_v128( [['f32x4.splat', 'f32', `0f c6 c0 00 shufps \\$0x00, %xmm0, %xmm0`], - ['f64x2.splat', 'f64', `66 0f c6 c0 00 shufpd \\$0x00, %xmm0, %xmm0`]] ); + ['f64x2.splat', 'f64', `f2 0f 12 c0 movddup %xmm0, %xmm0`]] , {log:true}); // Skip these on Win64 because the ABI differs and there's a different parameter // register, this changes not just the name slightly but the binary encoding in // larger ways. if (!getBuildConfiguration().windows) { codegenTestX64_PTYPE_v128( [['v128.load32_splat', 'i32', `
--- a/js/src/jit/shared/Assembler-shared.h +++ b/js/src/jit/shared/Assembler-shared.h @@ -557,17 +557,18 @@ class MemoryAccessDesc { void setZeroExtendSimd128Load() { MOZ_ASSERT(type() == Scalar::Float32 || type() == Scalar::Float64); MOZ_ASSERT(!isAtomic()); MOZ_ASSERT(loadOp_ == Plain); loadOp_ = ZeroExtend; } void setSplatSimd128Load() { - MOZ_ASSERT(type() == Scalar::Float64); + MOZ_ASSERT(type() == Scalar::Uint8 || type() == Scalar::Uint16 || + type() == Scalar::Float32 || type() == Scalar::Float64); MOZ_ASSERT(!isAtomic()); MOZ_ASSERT(loadOp_ == Plain); loadOp_ = Splat; } void setWidenSimd128Load(wasm::SimdOp op) { MOZ_ASSERT(type() == Scalar::Float64); MOZ_ASSERT(!isAtomic());
--- a/js/src/jit/x64/MacroAssembler-x64.cpp +++ b/js/src/jit/x64/MacroAssembler-x64.cpp @@ -922,40 +922,55 @@ void MacroAssembler::PushBoxed(FloatRegi void MacroAssembler::wasmLoad(const wasm::MemoryAccessDesc& access, Operand srcAddr, AnyRegister out) { memoryBarrierBefore(access.sync()); MOZ_ASSERT_IF( access.isZeroExtendSimd128Load(), access.type() == Scalar::Float32 || access.type() == Scalar::Float64); - MOZ_ASSERT_IF(access.isSplatSimd128Load(), access.type() == Scalar::Float64); + MOZ_ASSERT_IF( + access.isSplatSimd128Load(), + access.type() == Scalar::Uint8 || access.type() == Scalar::Uint16 || + access.type() == Scalar::Float32 || access.type() == Scalar::Float64); MOZ_ASSERT_IF(access.isWidenSimd128Load(), access.type() == Scalar::Float64); append(access, size()); switch (access.type()) { case Scalar::Int8: movsbl(srcAddr, out.gpr()); break; case Scalar::Uint8: - movzbl(srcAddr, out.gpr()); + if (access.isSplatSimd128Load()) { + vbroadcastb(srcAddr, out.fpu()); + } else { + movzbl(srcAddr, out.gpr()); + } break; case Scalar::Int16: movswl(srcAddr, out.gpr()); break; case Scalar::Uint16: - movzwl(srcAddr, out.gpr()); + if (access.isSplatSimd128Load()) { + vbroadcastw(srcAddr, out.fpu()); + } else { + movzwl(srcAddr, out.gpr()); + } break; case Scalar::Int32: case Scalar::Uint32: movl(srcAddr, out.gpr()); break; case Scalar::Float32: - // vmovss does the right thing also for access.isZeroExtendSimd128Load() - vmovss(srcAddr, out.fpu()); + if (access.isSplatSimd128Load()) { + vbroadcastss(srcAddr, out.fpu()); + } else { + // vmovss does the right thing also for access.isZeroExtendSimd128Load() + vmovss(srcAddr, out.fpu()); + } break; case Scalar::Float64: if (access.isSplatSimd128Load()) { vmovddup(srcAddr, out.fpu()); } else if (access.isWidenSimd128Load()) { switch (access.widenSimdOp()) { case wasm::SimdOp::V128Load8x8S: vpmovsxbw(srcAddr, out.fpu());
--- a/js/src/jit/x86-shared/Assembler-x86-shared.h +++ b/js/src/jit/x86-shared/Assembler-x86-shared.h @@ -4673,16 +4673,102 @@ class AssemblerX86Shared : public Assemb case Operand::MEM_REG_DISP: masm.fstp32_m(src.disp(), src.base()); break; default: MOZ_CRASH("unexpected operand kind"); } } + void vbroadcastb(const Operand& src, FloatRegister dest) { + MOZ_ASSERT(HasAVX2()); + switch (src.kind()) { + case Operand::FPREG: + masm.vbroadcastb_rr(src.fpu(), dest.encoding()); + break; + case Operand::MEM_REG_DISP: + masm.vbroadcastb_mr(src.disp(), src.base(), dest.encoding()); + break; + case Operand::MEM_SCALE: + masm.vbroadcastb_mr(src.disp(), src.base(), src.index(), src.scale(), + dest.encoding()); + break; + default: + MOZ_CRASH("unexpected operand kind"); + } + } + void vbroadcastw(const Operand& src, FloatRegister dest) { + MOZ_ASSERT(HasAVX2()); + switch (src.kind()) { + case Operand::FPREG: + masm.vbroadcastw_rr(src.fpu(), dest.encoding()); + break; + case Operand::MEM_REG_DISP: + masm.vbroadcastw_mr(src.disp(), src.base(), dest.encoding()); + break; + case Operand::MEM_SCALE: + masm.vbroadcastw_mr(src.disp(), src.base(), src.index(), src.scale(), + dest.encoding()); + break; + default: + MOZ_CRASH("unexpected operand kind"); + } + } + void vbroadcastd(const Operand& src, FloatRegister dest) { + MOZ_ASSERT(HasAVX2()); + switch (src.kind()) { + case Operand::FPREG: + masm.vbroadcastd_rr(src.fpu(), dest.encoding()); + break; + case Operand::MEM_REG_DISP: + masm.vbroadcastd_mr(src.disp(), src.base(), dest.encoding()); + break; + case Operand::MEM_SCALE: + masm.vbroadcastd_mr(src.disp(), src.base(), src.index(), src.scale(), + dest.encoding()); + break; + default: + MOZ_CRASH("unexpected operand kind"); + } + } + void vbroadcastq(const Operand& src, FloatRegister dest) { + MOZ_ASSERT(HasAVX2()); + switch (src.kind()) { + case Operand::FPREG: + masm.vbroadcastq_rr(src.fpu(), dest.encoding()); + break; + case Operand::MEM_REG_DISP: + masm.vbroadcastq_mr(src.disp(), src.base(), dest.encoding()); + break; + case Operand::MEM_SCALE: + masm.vbroadcastq_mr(src.disp(), src.base(), src.index(), src.scale(), + dest.encoding()); + break; + default: + MOZ_CRASH("unexpected operand kind"); + } + } + void vbroadcastss(const Operand& src, FloatRegister dest) { + MOZ_ASSERT(HasAVX2()); + switch (src.kind()) { + case Operand::FPREG: + masm.vbroadcastss_rr(src.fpu(), dest.encoding()); + break; + case Operand::MEM_REG_DISP: + masm.vbroadcastss_mr(src.disp(), src.base(), dest.encoding()); + break; + case Operand::MEM_SCALE: + masm.vbroadcastss_mr(src.disp(), src.base(), src.index(), src.scale(), + dest.encoding()); + break; + default: + MOZ_CRASH("unexpected operand kind"); + } + } + void flushBuffer() {} // Patching. static size_t PatchWrite_NearCallSize() { return 5; } static uintptr_t GetPointer(uint8_t* instPtr) { uintptr_t* ptr = ((uintptr_t*)instPtr) - 1; return *ptr;
--- a/js/src/jit/x86-shared/BaseAssembler-x86-shared.h +++ b/js/src/jit/x86-shared/BaseAssembler-x86-shared.h @@ -4266,16 +4266,82 @@ class BaseAssembler : public GenericAsse void vpaddq_rr(XMMRegisterID src1, XMMRegisterID src0, XMMRegisterID dst) { twoByteOpSimd("vpaddq", VEX_PD, OP2_PADDQ_VdqWdq, src1, src0, dst); } void vpsubq_rr(XMMRegisterID src1, XMMRegisterID src0, XMMRegisterID dst) { twoByteOpSimd("vpsubq", VEX_PD, OP2_PSUBQ_VdqWdq, src1, src0, dst); } + void vbroadcastb_rr(XMMRegisterID src, XMMRegisterID dst) { + threeByteOpSimd("vbroadcastb", VEX_PD, OP3_VBROADCASTB_VxWx, ESCAPE_38, src, + invalid_xmm, dst); + } + void vbroadcastb_mr(int32_t offset, RegisterID base, XMMRegisterID dst) { + threeByteOpSimd("vbroadcastb", VEX_PD, OP3_VBROADCASTB_VxWx, ESCAPE_38, + offset, base, invalid_xmm, dst); + } + void vbroadcastb_mr(int32_t offset, RegisterID base, RegisterID index, + int32_t scale, XMMRegisterID dst) { + threeByteOpSimd("vbroadcastb", VEX_PD, OP3_VBROADCASTB_VxWx, ESCAPE_38, + offset, base, index, scale, invalid_xmm, dst); + } + void vbroadcastw_rr(XMMRegisterID src, XMMRegisterID dst) { + threeByteOpSimd("vbroadcastw", VEX_PD, OP3_VBROADCASTW_VxWx, ESCAPE_38, src, + invalid_xmm, dst); + } + void vbroadcastw_mr(int32_t offset, RegisterID base, XMMRegisterID dst) { + threeByteOpSimd("vbroadcastw", VEX_PD, OP3_VBROADCASTW_VxWx, ESCAPE_38, + offset, base, invalid_xmm, dst); + } + void vbroadcastw_mr(int32_t offset, RegisterID base, RegisterID index, + int32_t scale, XMMRegisterID dst) { + threeByteOpSimd("vbroadcastw", VEX_PD, OP3_VBROADCASTW_VxWx, ESCAPE_38, + offset, base, index, scale, invalid_xmm, dst); + } + void vbroadcastd_rr(XMMRegisterID src, XMMRegisterID dst) { + threeByteOpSimd("vbroadcastd", VEX_PD, OP3_VBROADCASTD_VxWx, ESCAPE_38, src, + invalid_xmm, dst); + } + void vbroadcastd_mr(int32_t offset, RegisterID base, XMMRegisterID dst) { + threeByteOpSimd("vbroadcastd", VEX_PD, OP3_VBROADCASTD_VxWx, ESCAPE_38, + offset, base, invalid_xmm, dst); + } + void vbroadcastd_mr(int32_t offset, RegisterID base, RegisterID index, + int32_t scale, XMMRegisterID dst) { + threeByteOpSimd("vbroadcastd", VEX_PD, OP3_VBROADCASTD_VxWx, ESCAPE_38, + offset, base, index, scale, invalid_xmm, dst); + } + void vbroadcastq_rr(XMMRegisterID src, XMMRegisterID dst) { + threeByteOpSimd("vbroadcastq", VEX_PD, OP3_VBROADCASTQ_VxWx, ESCAPE_38, src, + invalid_xmm, dst); + } + void vbroadcastq_mr(int32_t offset, RegisterID base, XMMRegisterID dst) { + threeByteOpSimd("vbroadcastq", VEX_PD, OP3_VBROADCASTQ_VxWx, ESCAPE_38, + offset, base, invalid_xmm, dst); + } + void vbroadcastq_mr(int32_t offset, RegisterID base, RegisterID index, + int32_t scale, XMMRegisterID dst) { + threeByteOpSimd("vbroadcastq", VEX_PD, OP3_VBROADCASTQ_VxWx, ESCAPE_38, + offset, base, index, scale, invalid_xmm, dst); + } + void vbroadcastss_rr(XMMRegisterID src, XMMRegisterID dst) { + threeByteOpSimd("vbroadcastss", VEX_PD, OP3_VBROADCASTSS_VxWd, ESCAPE_38, + src, invalid_xmm, dst); + } + void vbroadcastss_mr(int32_t offset, RegisterID base, XMMRegisterID dst) { + threeByteOpSimd("vbroadcastss", VEX_PD, OP3_VBROADCASTSS_VxWd, ESCAPE_38, + offset, base, invalid_xmm, dst); + } + void vbroadcastss_mr(int32_t offset, RegisterID base, RegisterID index, + int32_t scale, XMMRegisterID dst) { + threeByteOpSimd("vbroadcastss", VEX_PD, OP3_VBROADCASTSS_VxWd, ESCAPE_38, + offset, base, index, scale, invalid_xmm, dst); + } + // BMI instructions: void sarxl_rrr(RegisterID src, RegisterID shift, RegisterID dst) { spew("sarxl %s, %s, %s", GPReg32Name(src), GPReg32Name(shift), GPReg32Name(dst)); RegisterID rm = src; XMMRegisterID src0 = static_cast<XMMRegisterID>(shift);
--- a/js/src/jit/x86-shared/Encoding-x86-shared.h +++ b/js/src/jit/x86-shared/Encoding-x86-shared.h @@ -355,16 +355,17 @@ enum ThreeByteOpcodeID { OP3_PBLENDVB_VdqWdq = 0x10, OP3_BLENDVPS_VdqWdq = 0x14, OP3_PEXTRB_EvVdqIb = 0x14, OP3_PEXTRW_EwVdqIb = 0x15, OP3_PEXTRD_EvVdqIb = 0x16, OP3_PEXTRQ_EvVdqIb = 0x16, OP3_PTEST_VdVd = 0x17, OP3_EXTRACTPS_EdVdqIb = 0x17, + OP3_VBROADCASTSS_VxWd = 0x18, OP3_PABSB_VdqWdq = 0x1C, OP3_PABSW_VdqWdq = 0x1D, OP3_PABSD_VdqWdq = 0x1E, OP3_PINSRB_VdqEvIb = 0x20, OP3_PMOVSXBW_VdqWdq = 0x20, OP3_INSERTPS_VpsUps = 0x21, OP3_PINSRD_VdqEvIb = 0x22, OP3_PINSRQ_VdqEvIb = 0x22, @@ -382,16 +383,20 @@ enum ThreeByteOpcodeID { OP3_PMINUW_VdqWdq = 0x3A, OP3_PMINUD_VdqWdq = 0x3B, OP3_PMAXSB_VdqWdq = 0x3C, OP3_PMAXSD_VdqWdq = 0x3D, OP3_PMAXUW_VdqWdq = 0x3E, OP3_PMAXUD_VdqWdq = 0x3F, OP3_PMULLD_VdqWdq = 0x40, OP3_VBLENDVPS_VdqWdq = 0x4A, + OP3_VBROADCASTD_VxWx = 0x58, + OP3_VBROADCASTQ_VxWx = 0x59, + OP3_VBROADCASTB_VxWx = 0x78, + OP3_VBROADCASTW_VxWx = 0x79, OP3_SHLX_GyEyBy = 0xF7, OP3_SARX_GyEyBy = 0xF7, OP3_SHRX_GyEyBy = 0xF7, }; // Test whether the given opcode should be printed with its operands reversed. inline bool IsXMMReversedOperands(TwoByteOpcodeID opcode) { switch (opcode) {
--- a/js/src/jit/x86-shared/MacroAssembler-x86-shared-SIMD.cpp +++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared-SIMD.cpp @@ -16,43 +16,58 @@ using mozilla::DebugOnly; using mozilla::FloatingPoint; using mozilla::Maybe; using mozilla::SpecificNaN; void MacroAssemblerX86Shared::splatX16(Register input, FloatRegister output) { ScratchSimd128Scope scratch(asMasm()); vmovd(input, output); + if (HasAVX2()) { + vbroadcastb(Operand(output), output); + return; + } zeroSimd128Int(scratch); vpshufb(scratch, output, output); } void MacroAssemblerX86Shared::splatX8(Register input, FloatRegister output) { vmovd(input, output); + if (HasAVX2()) { + vbroadcastw(Operand(output), output); + return; + } vpshuflw(0, output, output); vpshufd(0, output, output); } void MacroAssemblerX86Shared::splatX4(Register input, FloatRegister output) { vmovd(input, output); + if (HasAVX2()) { + vbroadcastd(Operand(output), output); + return; + } vpshufd(0, output, output); } void MacroAssemblerX86Shared::splatX4(FloatRegister input, FloatRegister output) { MOZ_ASSERT(input.isSingle() && output.isSimd128()); + if (HasAVX2()) { + vbroadcastss(Operand(input), output); + return; + } asMasm().moveSimd128Float(input.asSimd128(), output); vshufps(0, output, output, output); } void MacroAssemblerX86Shared::splatX2(FloatRegister input, FloatRegister output) { MOZ_ASSERT(input.isDouble() && output.isSimd128()); - asMasm().moveSimd128Float(input.asSimd128(), output); - vshufpd(0, output, output, output); + vmovddup(Operand(input.asSimd128()), output); } void MacroAssemblerX86Shared::extractLaneInt32x4(FloatRegister input, Register output, unsigned lane) { if (lane == 0) { // The value we want to extract is in the low double-word moveLowInt32(input, output);
--- a/js/src/jit/x86/MacroAssembler-x86.cpp +++ b/js/src/jit/x86/MacroAssembler-x86.cpp @@ -947,42 +947,57 @@ template void MacroAssembler::storeUnbox void MacroAssembler::wasmLoad(const wasm::MemoryAccessDesc& access, Operand srcAddr, AnyRegister out) { MOZ_ASSERT(srcAddr.kind() == Operand::MEM_REG_DISP || srcAddr.kind() == Operand::MEM_SCALE); MOZ_ASSERT_IF( access.isZeroExtendSimd128Load(), access.type() == Scalar::Float32 || access.type() == Scalar::Float64); - MOZ_ASSERT_IF(access.isSplatSimd128Load(), access.type() == Scalar::Float64); + MOZ_ASSERT_IF( + access.isSplatSimd128Load(), + access.type() == Scalar::Uint8 || access.type() == Scalar::Uint16 || + access.type() == Scalar::Float32 || access.type() == Scalar::Float64); MOZ_ASSERT_IF(access.isWidenSimd128Load(), access.type() == Scalar::Float64); memoryBarrierBefore(access.sync()); append(access, size()); switch (access.type()) { case Scalar::Int8: movsbl(srcAddr, out.gpr()); break; case Scalar::Uint8: - movzbl(srcAddr, out.gpr()); + if (access.isSplatSimd128Load()) { + vbroadcastb(srcAddr, out.fpu()); + } else { + movzbl(srcAddr, out.gpr()); + } break; case Scalar::Int16: movswl(srcAddr, out.gpr()); break; case Scalar::Uint16: - movzwl(srcAddr, out.gpr()); + if (access.isSplatSimd128Load()) { + vbroadcastw(srcAddr, out.fpu()); + } else { + movzwl(srcAddr, out.gpr()); + } break; case Scalar::Int32: case Scalar::Uint32: movl(srcAddr, out.gpr()); break; case Scalar::Float32: - // vmovss does the right thing also for access.isZeroExtendSimd128Load() - vmovss(srcAddr, out.fpu()); + if (access.isSplatSimd128Load()) { + vbroadcastss(srcAddr, out.fpu()); + } else { + // vmovss does the right thing also for access.isZeroExtendSimd128Load() + vmovss(srcAddr, out.fpu()); + } break; case Scalar::Float64: if (access.isSplatSimd128Load()) { vmovddup(srcAddr, out.fpu()); } else if (access.isWidenSimd128Load()) { switch (access.widenSimdOp()) { case wasm::SimdOp::V128Load8x8S: vpmovsxbw(srcAddr, out.fpu());
--- a/js/src/wasm/WasmIonCompile.cpp +++ b/js/src/wasm/WasmIonCompile.cpp @@ -1602,17 +1602,24 @@ class FunctionCompiler { if (inDeadCode()) { return nullptr; } MemoryAccessDesc access(viewType, addr.align, addr.offset, bytecodeIfNotAsmJS()); // Generate better code (on x86) - if (viewType == Scalar::Float64) { + // If AVX2 is enabled, more broadcast operators are available. + if (viewType == Scalar::Float64 +# if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86) + || (js::jit::CPUInfo::IsAVX2Present() && + (viewType == Scalar::Uint8 || viewType == Scalar::Uint16 || + viewType == Scalar::Float32)) +# endif + ) { access.setSplatSimd128Load(); return load(addr.base, &access, ValType::V128); } ValType resultType = ValType::I32; if (viewType == Scalar::Float32) { resultType = ValType::F32; splatOp = wasm::SimdOp::F32x4Splat;
--- a/layout/forms/nsFieldSetFrame.cpp +++ b/layout/forms/nsFieldSetFrame.cpp @@ -23,16 +23,17 @@ #include "nsIFrameInlines.h" #include "nsIScrollableFrame.h" #include "nsLayoutUtils.h" #include "nsStyleConsts.h" using namespace mozilla; using namespace mozilla::gfx; using namespace mozilla::layout; +using image::ImgDrawResult; nsContainerFrame* NS_NewFieldSetFrame(PresShell* aPresShell, ComputedStyle* aStyle) { return new (aPresShell) nsFieldSetFrame(aStyle, aPresShell->GetPresContext()); } NS_IMPL_FRAMEARENA_HELPERS(nsFieldSetFrame) NS_QUERYFRAME_HEAD(nsFieldSetFrame) @@ -121,19 +122,18 @@ class nsDisplayFieldSetBorder final : pu nsDisplayListBuilder* aDisplayListBuilder) override; virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const override; NS_DISPLAY_DECL_NAME("FieldSetBorder", TYPE_FIELDSET_BORDER_BACKGROUND) }; void nsDisplayFieldSetBorder::Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) { - image::ImgDrawResult result = - static_cast<nsFieldSetFrame*>(mFrame)->PaintBorder( - aBuilder, *aCtx, ToReferenceFrame(), GetPaintRect(aBuilder, aCtx)); + ImgDrawResult result = static_cast<nsFieldSetFrame*>(mFrame)->PaintBorder( + aBuilder, *aCtx, ToReferenceFrame(), GetPaintRect(aBuilder, aCtx)); nsDisplayItemGenericImageGeometry::UpdateDrawResult(this, result); } nsDisplayItemGeometry* nsDisplayFieldSetBorder::AllocateGeometry( nsDisplayListBuilder* aBuilder) { return new nsDisplayItemGenericImageGeometry(this, aBuilder); } @@ -167,22 +167,23 @@ nsRect nsDisplayFieldSetBorder::GetBound bool nsDisplayFieldSetBorder::CreateWebRenderCommands( mozilla::wr::DisplayListBuilder& aBuilder, mozilla::wr::IpcResourceUpdateQueue& aResources, const StackingContextHelper& aSc, mozilla::layers::RenderRootStateManager* aManager, nsDisplayListBuilder* aDisplayListBuilder) { auto frame = static_cast<nsFieldSetFrame*>(mFrame); auto offset = ToReferenceFrame(); - nsRect rect; Maybe<wr::SpaceAndClipChainHelper> clipOut; + nsRect rect = frame->VisualBorderRectRelativeToSelf() + offset; + nsDisplayBoxShadowInner::CreateInsetBoxShadowWebRenderCommands( + aBuilder, aSc, rect, mFrame, rect); + if (nsIFrame* legend = frame->GetLegend()) { - rect = frame->VisualBorderRectRelativeToSelf() + offset; - nsRect legendRect = legend->GetNormalRect() + offset; // Make sure we clip all of the border in case the legend is smaller. nscoord borderTopWidth = frame->GetUsedBorder().top; if (legendRect.height < borderTopWidth) { legendRect.height = borderTopWidth; legendRect.y = offset.y; } @@ -270,19 +271,20 @@ void nsFieldSetFrame::BuildDisplayList(n } // Put the inner frame's display items on the master list. Note that this // moves its border/background display items to our BorderBackground() list, // which isn't really correct, but it's OK because the inner frame is // anonymous and can't have its own border and background. contentDisplayItems.MoveTo(aLists); } -image::ImgDrawResult nsFieldSetFrame::PaintBorder( - nsDisplayListBuilder* aBuilder, gfxContext& aRenderingContext, nsPoint aPt, - const nsRect& aDirtyRect) { +ImgDrawResult nsFieldSetFrame::PaintBorder(nsDisplayListBuilder* aBuilder, + gfxContext& aRenderingContext, + nsPoint aPt, + const nsRect& aDirtyRect) { // If the border is smaller than the legend, move the border down // to be centered on the legend. We call VisualBorderRectRelativeToSelf() to // compute the border positioning. // FIXME: This means border-radius clamping is incorrect; we should // override nsIFrame::GetBorderRadii. nsRect rect = VisualBorderRectRelativeToSelf() + aPt; nsPresContext* presContext = PresContext();
--- a/layout/generic/nsTextFrame.cpp +++ b/layout/generic/nsTextFrame.cpp @@ -3558,17 +3558,18 @@ void nsTextFrame::PropertyProvider::GetS } } // aX and the result are in whole appunits. static gfxFloat AdvanceToNextTab(gfxFloat aX, gfxFloat aTabWidth, gfxFloat aMinAdvance) { // Advance aX to the next multiple of aTabWidth. We must advance // by at least aMinAdvance. - return ceil((aX + aMinAdvance) / aTabWidth) * aTabWidth; + gfxFloat nextPos = aX + aMinAdvance; + return aTabWidth > 0.0 ? ceil(nextPos / aTabWidth) * aTabWidth : nextPos; } void nsTextFrame::PropertyProvider::CalcTabWidths(Range aRange, gfxFloat aTabWidth) const { MOZ_ASSERT(aTabWidth > 0); if (!mTabWidths) { if (mReflowing && !mLineContainer) {
--- a/layout/reftests/box-shadow/reftest.list +++ b/layout/reftests/box-shadow/reftest.list @@ -36,14 +36,14 @@ fuzzy(0-26,0-3610) fuzzy-if(d2d,0-26,0-5 fuzzy(12-15,9400-13267) == boxshadow-inset-large-offset.html boxshadow-inset-large-offset-ref.html == overflow-not-scrollable-1.html overflow-not-scrollable-1-ref.html == overflow-not-scrollable-1.html overflow-not-scrollable-1-ref2.html == overflow-not-scrollable-2.html overflow-not-scrollable-2-ref.html fuzzy(0-1,0-655) == 611574-1.html 611574-1-ref.html fuzzy(0-4,0-144) fuzzy-if(d2d,0-1,0-36) == 611574-2.html 611574-2-ref.html fuzzy(0-16,0-10) == fieldset.html fieldset-ref.html # minor anti-aliasing problem on Windows -fuzzy(0-16,0-10) fails-if(!useDrawSnapshot) == fieldset-inset.html fieldset-inset-ref.html # minor anti-aliasing problem on Windows +fuzzy(0-16,0-10) == fieldset-inset.html fieldset-inset-ref.html # minor anti-aliasing problem on Windows == 1178575.html 1178575-ref.html == 1178575-2.html 1178575-2-ref.html fuzzy(0-159,0-2) fails-if(!dwrite||!nativeThemePref) == 1212823-1.html 1212823-1-ref.html fuzzy(0-93,0-8) fails-if(nativeThemePref) == 1212823-2.html 1212823-2-ref.html == boxshadow-large-offset.html boxshadow-large-offset-ref.html
--- a/netwerk/base/nsILoadInfo.idl +++ b/netwerk/base/nsILoadInfo.idl @@ -459,27 +459,35 @@ interface nsILoadInfo : nsISupports /** * This flag can only ever be set on top-level loads. It indicates * that the top-level https connection succeeded. This flag is mostly * used to counter time-outs which allows to cancel the channel * if the https load has not started. */ const unsigned long HTTPS_ONLY_TOP_LEVEL_LOAD_IN_PROGRESS = (1 << 4); - /** - * This flag indicates that the request should not be logged to the - * console. + /** + * This flag can only ever be set on downloads. It indicates + * that the download https connection succeeded. This flag is mostly + * used to counter time-outs which allows to cancel the channel + * if the https load has not started. */ - const unsigned long HTTPS_ONLY_DO_NOT_LOG_TO_CONSOLE = (1 << 5); + const unsigned long HTTPS_ONLY_DOWNLOAD_IN_PROGRESS = (1 << 5); /** * This flag indicates that the request should not be logged to the * console. */ - const unsigned long HTTPS_ONLY_UPGRADED_HTTPS_FIRST = (1 << 6); + const unsigned long HTTPS_ONLY_DO_NOT_LOG_TO_CONSOLE = (1 << 6); + + /** + * This flag indicates that the request should not be logged to the + * console. + */ + const unsigned long HTTPS_ONLY_UPGRADED_HTTPS_FIRST = (1 << 7); /** * Upgrade state of HTTPS-Only Mode. The flag HTTPS_ONLY_EXEMPT can get * set on requests that should be excempt from an upgrade. */ [infallible] attribute unsigned long httpsOnlyStatus; /**
--- a/testing/web-platform/meta/html/canvas/element/manual/imagebitmap/createImageBitmap-drawImage.html.ini +++ b/testing/web-platform/meta/html/canvas/element/manual/imagebitmap/createImageBitmap-drawImage.html.ini @@ -1,117 +1,42 @@ [createImageBitmap-drawImage.html] [createImageBitmap from an OffscreenCanvas resized, and drawImage on the created ImageBitmap] expected: FAIL - [createImageBitmap from a vector HTMLImageElement resized, and drawImage on the created ImageBitmap] - expected: FAIL - [createImageBitmap from an OffscreenCanvas, and drawImage on the created ImageBitmap] expected: FAIL - [createImageBitmap from a bitmap HTMLImageElement resized, and drawImage on the created ImageBitmap] - expected: FAIL - [createImageBitmap from an HTMLVideoElement from a data URL scaled down, and drawImage on the created ImageBitmap] expected: FAIL - [createImageBitmap from an ImageData scaled down, and drawImage on the created ImageBitmap] - expected: FAIL - [createImageBitmap from an OffscreenCanvas scaled down, and drawImage on the created ImageBitmap] expected: FAIL - [createImageBitmap from a bitmap SVGImageElement resized, and drawImage on the created ImageBitmap] - expected: FAIL - - [createImageBitmap from an HTMLCanvasElement scaled down, and drawImage on the created ImageBitmap] - expected: FAIL - - [createImageBitmap from an ImageData scaled up, and drawImage on the created ImageBitmap] - expected: FAIL - - [createImageBitmap from a bitmap SVGImageElement scaled up, and drawImage on the created ImageBitmap] - expected: FAIL - - [createImageBitmap from a vector SVGImageElement resized, and drawImage on the created ImageBitmap] - expected: FAIL - - [createImageBitmap from a bitmap HTMLImageElement scaled up, and drawImage on the created ImageBitmap] - expected: FAIL - - [createImageBitmap from a vector SVGImageElement scaled down, and drawImage on the created ImageBitmap] - expected: FAIL - - [createImageBitmap from a bitmap HTMLImageElement scaled down, and drawImage on the created ImageBitmap] - expected: FAIL - [createImageBitmap from an HTMLVideoElement scaled down, and drawImage on the created ImageBitmap] expected: FAIL - [createImageBitmap from a Blob scaled down, and drawImage on the created ImageBitmap] - expected: FAIL - - [createImageBitmap from an ImageData resized, and drawImage on the created ImageBitmap] - expected: FAIL - - [createImageBitmap from a vector HTMLImageElement scaled down, and drawImage on the created ImageBitmap] - expected: FAIL - - [createImageBitmap from a vector SVGImageElement scaled up, and drawImage on the created ImageBitmap] - expected: FAIL - - [createImageBitmap from a Blob scaled up, and drawImage on the created ImageBitmap] - expected: FAIL - - [createImageBitmap from a bitmap SVGImageElement scaled down, and drawImage on the created ImageBitmap] - expected: FAIL - [createImageBitmap from an HTMLVideoElement scaled up, and drawImage on the created ImageBitmap] expected: FAIL - [createImageBitmap from an HTMLCanvasElement resized, and drawImage on the created ImageBitmap] - expected: FAIL - [createImageBitmap from an HTMLVideoElement resized, and drawImage on the created ImageBitmap] expected: FAIL [createImageBitmap from an HTMLVideoElement from a data URL scaled up, and drawImage on the created ImageBitmap] expected: FAIL - [createImageBitmap from an ImageBitmap scaled down, and drawImage on the created ImageBitmap] - expected: FAIL - - [createImageBitmap from a Blob with negative sw/sh, and drawImage on the created ImageBitmap] - expected: FAIL - - [createImageBitmap from an ImageBitmap scaled up, and drawImage on the created ImageBitmap] - expected: FAIL - - [createImageBitmap from an ImageBitmap resized, and drawImage on the created ImageBitmap] - expected: FAIL - [createImageBitmap from an OffscreenCanvas scaled up, and drawImage on the created ImageBitmap] expected: FAIL - [createImageBitmap from an HTMLCanvasElement scaled up, and drawImage on the created ImageBitmap] - expected: FAIL - - [createImageBitmap from a Blob resized, and drawImage on the created ImageBitmap] - expected: FAIL - [createImageBitmap from an HTMLVideoElement from a data URL resized, and drawImage on the created ImageBitmap] expected: FAIL [createImageBitmap from an OffscreenCanvas with negative sw/sh, and drawImage on the created ImageBitmap] expected: FAIL - [createImageBitmap from a vector HTMLImageElement scaled up, and drawImage on the created ImageBitmap] - expected: FAIL - [createImageBitmap from an HTMLVideoElement, and drawImage on the created ImageBitmap] expected: FAIL [createImageBitmap from an HTMLVideoElement with negative sw/sh, and drawImage on the created ImageBitmap] expected: FAIL [createImageBitmap from an HTMLVideoElement from a data URL, and drawImage on the created ImageBitmap] expected: FAIL
new file mode 100644 --- /dev/null +++ b/testing/web-platform/tests/css/css-backgrounds/fieldset-inset-shadow-ref.html @@ -0,0 +1,11 @@ +<!doctype html> +<title>CSS Test Reference</title> +<style> + div { + width: 100px; + height: 100px; + box-sizing: border-box; + box-shadow: 0 0 0 10px inset black; + } +</style> +<div></div>
new file mode 100644 --- /dev/null +++ b/testing/web-platform/tests/css/css-backgrounds/fieldset-inset-shadow.html @@ -0,0 +1,18 @@ +<!doctype html> +<title>inset box shadow works on fieldset</title> +<link rel=help href="https://drafts.csswg.org/css-backgrounds/#box-shadow"> +<link rel=help href="https://bugzilla.mozilla.org/show_bug.cgi?id=1750276"> +<link rel=author title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io"> +<link rel=author title="Mozilla" href="https://mozilla.org"> +<link rel=match href="fieldset-inset-shadow-ref.html"> +<style> + fieldset { + width: 100px; + height: 100px; + border: none; + margin: 0; + box-sizing: border-box; + box-shadow: 0 0 0 10px inset black; + } +</style> +<fieldset></fieldset>
--- a/toolkit/components/nimbus/ExperimentAPI.jsm +++ b/toolkit/components/nimbus/ExperimentAPI.jsm @@ -441,18 +441,17 @@ class _ExperimentFeature { const branch = ExperimentAPI.activateBranch({ featureId: this.featureId }); const featureValue = featuresCompat(branch).find( ({ featureId }) => featureId === this.featureId )?.value; return { ...this.prefGetters, ...defaultValues, - ...this.getRollout()?.value, - ...(featureValue || null), + ...(featureValue ? featureValue : this.getRollout()?.value), ...userPrefs, }; } getVariable(variable) { const prefName = this.getPreferenceName(variable); const prefValue = prefName ? this.prefGetters[variable] : undefined;
--- a/toolkit/components/nimbus/test/unit/test_ExperimentAPI_ExperimentFeature_getAllVariables.js +++ b/toolkit/components/nimbus/test/unit/test_ExperimentAPI_ExperimentFeature_getAllVariables.js @@ -23,16 +23,19 @@ async function setupForExperimentFeature const FEATURE_ID = "aboutwelcome"; const TEST_FALLBACK_PREF = "browser.aboutwelcome.screens"; const FAKE_FEATURE_MANIFEST = { variables: { screens: { type: "json", fallbackPref: TEST_FALLBACK_PREF, }, + source: { + type: "string", + }, }, }; add_task( async function test_ExperimentFeature_getAllVariables_prefsOverDefaults() { const { sandbox } = await setupForExperimentFeature(); const featureInstance = new ExperimentFeature( @@ -113,16 +116,81 @@ add_task( Services.prefs.clearUserPref(TEST_FALLBACK_PREF); await doExperimentCleanup(); sandbox.restore(); } ); add_task( + async function test_ExperimentFeature_getAllVariables_experimentOverRemote() { + Services.prefs.clearUserPref(TEST_FALLBACK_PREF); + const { manager } = await setupForExperimentFeature(); + const { doExperimentCleanup } = ExperimentFakes.enrollmentHelper( + undefined, + { + manager, + } + ); + const featureInstance = new ExperimentFeature( + FEATURE_ID, + FAKE_FEATURE_MANIFEST + ); + const recipe = ExperimentFakes.experiment("aw-experiment", { + branch: { + slug: "treatment", + features: [ + { + featureId: FEATURE_ID, + value: { screens: ["test-value"] }, + }, + ], + }, + }); + const rollout = ExperimentFakes.rollout("aw-rollout", { + branch: { + slug: "treatment", + features: [ + { featureId: FEATURE_ID, value: { screens: [], source: "rollout" } }, + ], + }, + }); + // We're using the store in this test we need to wait for it to load + await manager.store.ready(); + + const rolloutPromise = new Promise(resolve => + featureInstance.onUpdate((feature, reason) => { + if (reason === "rollout-updated") { + resolve(); + } + }) + ); + const experimentPromise = new Promise(resolve => + featureInstance.onUpdate((feature, reason) => { + if (reason === "experiment-updated") { + resolve(); + } + }) + ); + manager.store.addEnrollment(recipe); + manager.store.addEnrollment(rollout); + await rolloutPromise; + await experimentPromise; + + let allVariables = featureInstance.getAllVariables(); + + Assert.equal(allVariables.screens.length, 1, "Returns experiment value"); + Assert.ok(!allVariables.source, "Does not include rollout value"); + + await doExperimentCleanup(); + cleanupStorePrefCache(); + } +); + +add_task( async function test_ExperimentFeature_getAllVariables_remoteOverPrefDefaults() { const { manager } = await setupForExperimentFeature(); const featureInstance = new ExperimentFeature( FEATURE_ID, FAKE_FEATURE_MANIFEST ); const rollout = ExperimentFakes.rollout("foo-aw", { branch: {
--- a/toolkit/components/telemetry/app/ClientID.jsm +++ b/toolkit/components/telemetry/app/ClientID.jsm @@ -145,59 +145,40 @@ var ClientIDImpl = { // If there's a removal in progress, let's wait for it await this._removeClientIdTask; // Try to load the client id from the DRS state file. let hasCurrentClientID = false; try { let state = await IOUtils.readJSON(gStateFilePath); if (state) { - try { - if (Services.prefs.prefHasUserValue(PREF_CACHED_CLIENTID)) { - let cachedID = Services.prefs.getStringPref( - PREF_CACHED_CLIENTID, - null - ); - if (cachedID && cachedID != state.clientID) { - Services.telemetry.scalarAdd( - "telemetry.loaded_client_id_doesnt_match_pref", - 1 - ); - } - } - } catch (e) { - // This data collection's not that important. - } hasCurrentClientID = this.updateClientID(state.clientID); if (hasCurrentClientID) { this._log.trace(`_doLoadClientID: Client IDs loaded from state.`); return { clientID: this._clientID, }; } } } catch (e) { - Services.telemetry.scalarAdd("telemetry.state_file_read_errors", 1); // fall through to next option } // Absent or broken state file? Check prefs as last resort. if (!hasCurrentClientID) { const cachedID = this.getCachedClientID(); // Calling `updateClientID` with `null` logs an error, which breaks tests. if (cachedID) { - Services.telemetry.scalarAdd("telemetry.using_pref_client_id", 1); hasCurrentClientID = this.updateClientID(cachedID); } } // We're missing the ID from the DRS state file and prefs. // Generate a new one. if (!hasCurrentClientID) { - Services.telemetry.scalarSet("telemetry.generated_new_client_id", true); this.updateClientID(CommonUtils.generateUUID()); } this._saveClientIdTask = this._saveClientID(); // Wait on persisting the id. Otherwise failure to save the ID would result in // the client creating and subsequently sending multiple IDs to the server. // This would appear as multiple clients submitting similar data, which would // result in orphaning. @@ -221,18 +202,16 @@ var ClientIDImpl = { clientID: this._clientID, }; await IOUtils.makeDirectory(gDatareportingPath); await IOUtils.writeJSON(gStateFilePath, obj, { tmpPath: `${gStateFilePath}.tmp`, }); this._saveClientIdTask = null; } catch (ex) { - Services.telemetry.scalarAdd("telemetry.state_file_save_errors", 1); - if (!(ex instanceof DOMException) || ex.name !== "AbortError") { throw ex; } } }, /** * This returns a promise resolving to the the stable client ID we use for @@ -336,17 +315,16 @@ var ClientIDImpl = { await this._saveClientIdTask; // Remove the client-id-containing state file from disk await IOUtils.remove(gStateFilePath); }, async removeClientID() { this._log.trace("removeClientID"); - Services.telemetry.scalarAdd("telemetry.removed_client_ids", 1); // Wait for the removal. // Asynchronous calls to getClientID will also be blocked on this. this._removeClientIdTask = this._doRemoveClientID(); let clear = () => (this._removeClientIdTask = null); this._removeClientIdTask.then(clear, clear); await this._removeClientIdTask;
--- a/toolkit/crashreporter/CrashAnnotations.yaml +++ b/toolkit/crashreporter/CrashAnnotations.yaml @@ -617,16 +617,22 @@ MacMemoryPressureSysctl: type: integer MacAvailableMemorySysctl: description: > The value of the available memory sysctl 'kern.memorystatus_level'. Expected to be a percentage integer value. type: integer +LinuxUnderMemoryPressure: + description: > + Set to true if the memory pressure watcher was under memory pressure when + the crash occurred. + type: boolean + LauncherProcessState: description: > Launcher process enabled state. The integer value of this annotation must match with one of the values in the mozilla::LauncherRegistryInfo::EnableState enum type: integer LowPhysicalMemoryEvents:
--- a/toolkit/mozapps/extensions/content/view-controller.js +++ b/toolkit/mozapps/extensions/content/view-controller.js @@ -1,15 +1,15 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; -/* import-globals-from ../../../content/customElements.js */ +/* import-globals-from /toolkit/content/customElements.js */ /* import-globals-from aboutaddonsCommon.js */ /* exported loadView */ const { AddonManager } = ChromeUtils.import( "resource://gre/modules/AddonManager.jsm" ); ChromeUtils.defineModuleGetter(
--- a/toolkit/mozapps/update/content/updateElevation.js +++ b/toolkit/mozapps/update/content/updateElevation.js @@ -3,17 +3,17 @@ * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* This is temporary until bug 1521632 is fixed */ "use strict"; -/* import-globals-from ../../../content/contentAreaUtils.js */ +/* import-globals-from /toolkit/content/contentAreaUtils.js */ const gUpdateElevationDialog = { openUpdateURL(event) { if (event.button == 0) { openURL(event.target.getAttribute("url")); } }, getAUSString(key, strings) {
--- a/tools/lint/eslint/eslint-plugin-mozilla/lib/globals.js +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/globals.js @@ -115,16 +115,18 @@ GlobalsForNode.prototype = { if (!match) { continue; } let filePath = match[1].trim(); if (!path.isAbsolute(filePath)) { filePath = path.resolve(this.dirname, filePath); + } else { + filePath = path.join(helpers.rootDir, filePath); } globals = globals.concat(module.exports.getGlobalsForFile(filePath)); } return globals; }, ExpressionStatement(node, parents, globalScope) {
--- a/uriloader/exthandler/nsExternalHelperAppService.cpp +++ b/uriloader/exthandler/nsExternalHelperAppService.cpp @@ -91,16 +91,18 @@ #include "nsIRandomGenerator.h" #include "ContentChild.h" #include "nsXULAppAPI.h" #include "nsPIDOMWindow.h" #include "ExternalHelperAppChild.h" +#include "mozilla/dom/nsHTTPSOnlyUtils.h" + #ifdef XP_WIN # include "nsWindowsHelpers.h" #endif #include "mozilla/Components.h" #include "mozilla/ClearOnShutdown.h" #include "mozilla/Preferences.h" #include "mozilla/ipc/URIUtils.h" @@ -1736,16 +1738,27 @@ NS_IMETHODIMP nsExternalAppHandler::OnSt nsresult rv; nsAutoCString MIMEType; if (mMimeInfo) { mMimeInfo->GetMIMEType(MIMEType); } // Now get the URI if (aChannel) { aChannel->GetURI(getter_AddRefs(mSourceUrl)); + // HTTPS-Only/HTTPS-FirstMode tries to upgrade connections to https. Once + // the download is in progress we set that flag so that timeout counter + // measures do not kick in. + nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo(); + bool isPrivateWin = loadInfo->GetOriginAttributes().mPrivateBrowsingId > 0; + if (nsHTTPSOnlyUtils::IsHttpsOnlyModeEnabled(isPrivateWin) || + nsHTTPSOnlyUtils::IsHttpsFirstModeEnabled(isPrivateWin)) { + uint32_t httpsOnlyStatus = loadInfo->GetHttpsOnlyStatus(); + httpsOnlyStatus |= nsILoadInfo::HTTPS_ONLY_DOWNLOAD_IN_PROGRESS; + loadInfo->SetHttpsOnlyStatus(httpsOnlyStatus); + } } if (!mForceSave && StaticPrefs::browser_download_enable_spam_prevention() && IsDownloadSpam(aChannel)) { RecordDownloadTelemetry(aChannel, "spam"); return NS_OK; }
--- a/widget/windows/nsAppShell.cpp +++ b/widget/windows/nsAppShell.cpp @@ -529,17 +529,17 @@ nsresult nsAppShell::Init() { wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = module; wc.hIcon = nullptr; wc.hCursor = nullptr; wc.hbrBackground = (HBRUSH) nullptr; wc.lpszMenuName = (LPCWSTR) nullptr; wc.lpszClassName = kWindowClass; - ATOM wcA = RegisterClassW(&wc); + [[maybe_unused]] ATOM wcA = RegisterClassW(&wc); MOZ_DIAGNOSTIC_ASSERT(wcA, "RegisterClassW for EventWindowClass failed"); } mEventWnd = CreateWindowW(kWindowClass, L"nsAppShell:EventWindow", 0, 0, 0, 10, 10, HWND_MESSAGE, nullptr, module, nullptr); MOZ_DIAGNOSTIC_ASSERT(mEventWnd, "CreateWindowW for EventWindow failed"); NS_ENSURE_STATE(mEventWnd); } else if (XRE_IsContentProcess() && !IsWin32kLockedDown()) {
--- a/xpcom/base/AvailableMemoryWatcherLinux.cpp +++ b/xpcom/base/AvailableMemoryWatcherLinux.cpp @@ -35,16 +35,17 @@ class nsAvailableMemoryWatcher final : p void HandleLowMemory(); void MaybeHandleHighMemory(); private: ~nsAvailableMemoryWatcher() = default; void StartPolling(const MutexAutoLock&); void StopPolling(const MutexAutoLock&); void ShutDown(const MutexAutoLock&); + void UpdateCrashAnnotation(const MutexAutoLock&); static bool IsMemoryLow(); nsCOMPtr<nsITimer> mTimer; nsCOMPtr<nsIThread> mThread; bool mPolling; bool mUnderMemoryPressure; @@ -84,16 +85,19 @@ nsresult nsAvailableMemoryWatcher::Init( NS_WARNING("Couldn't make a thread for nsAvailableMemoryWatcher."); // In this scenario we can't poll for low memory, since we can't dispatch // to our memory watcher thread. return rv; } mThread = thread; MutexAutoLock lock(mMutex); + // Set the crash annotation to its initial state. + UpdateCrashAnnotation(lock); + StartPolling(lock); return NS_OK; } already_AddRefed<nsAvailableMemoryWatcherBase> CreateAvailableMemoryWatcher() { RefPtr watcher(new nsAvailableMemoryWatcher); @@ -177,37 +181,45 @@ nsAvailableMemoryWatcher::Notify(nsITime } return NS_OK; } void nsAvailableMemoryWatcher::HandleLowMemory() { MutexAutoLock lock(mMutex); if (!mUnderMemoryPressure) { mUnderMemoryPressure = true; + UpdateCrashAnnotation(lock); // Poll more frequently under memory pressure. StartPolling(lock); } UpdateLowMemoryTimeStamp(); // We handle low memory offthread, but we want to unload // tabs only from the main thread, so we will dispatch this // back to the main thread. NS_DispatchToMainThread(NS_NewRunnableFunction( "nsAvailableMemoryWatcher::OnLowMemory", [self = RefPtr{this}]() { self->mTabUnloader->UnloadTabAsync(); })); } +void nsAvailableMemoryWatcher::UpdateCrashAnnotation(const MutexAutoLock&) { + CrashReporter::AnnotateCrashReport( + CrashReporter::Annotation::LinuxUnderMemoryPressure, + mUnderMemoryPressure); +} + // If memory is not low, we may need to dispatch an // event for it if we have been under memory pressure. // We can also adjust our polling interval. void nsAvailableMemoryWatcher::MaybeHandleHighMemory() { MutexAutoLock lock(mMutex); if (mUnderMemoryPressure) { RecordTelemetryEventOnHighMemory(); NS_NotifyOfEventualMemoryPressure(MemoryPressureState::NoPressure); mUnderMemoryPressure = false; + UpdateCrashAnnotation(lock); } StartPolling(lock); } // When we change the polling interval, we will need to restart the timer // on the new interval. void nsAvailableMemoryWatcher::StartPolling(const MutexAutoLock& aLock) { uint32_t pollingInterval = mUnderMemoryPressure