tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit c91fb7a5354d86dd84aed0cb4a41205e245b9290
parent 26b5c9940c6673829ffe30fc43d6970da15c6c9d
Author: Tom Schuster <tschuster@mozilla.com>
Date:   Mon, 10 Nov 2025 09:50:39 +0000

Bug 1996244 - Add [ChromeOnly] ImageTrack.getSizes function. r=aosmond,webidl,smaug

Differential Revision: https://phabricator.services.mozilla.com/D269998

Diffstat:
Mdom/media/webcodecs/ImageTrack.cpp | 8+++++++-
Mdom/media/webcodecs/ImageTrack.h | 8++++++--
Mdom/media/webcodecs/ImageTrackList.cpp | 13+++++++++++--
Mdom/media/webcodecs/test/mochitest.toml | 6+++++-
Adom/media/webcodecs/test/multiple.ico | 0
Adom/media/webcodecs/test/test_track_getNativeSizes.html | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdom/webidl/ImageDecoder.webidl | 9+++++++++
Mimage/ImageUtils.cpp | 2++
Mimage/ImageUtils.h | 2++
9 files changed, 98 insertions(+), 6 deletions(-)

diff --git a/dom/media/webcodecs/ImageTrack.cpp b/dom/media/webcodecs/ImageTrack.cpp @@ -26,10 +26,12 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ImageTrack) NS_INTERFACE_MAP_END ImageTrack::ImageTrack(ImageTrackList* aTrackList, int32_t aIndex, - bool aSelected, bool aAnimated, uint32_t aFrameCount, + nsTArray<ImageSize>&& aNativeSizes, bool aSelected, + bool aAnimated, uint32_t aFrameCount, bool aFrameCountComplete, float aRepetitionCount) : mParent(aTrackList->GetParentObject()), mTrackList(aTrackList), + mNativeSizes(std::move(aNativeSizes)), mFramesTimestamp(image::FrameTimeout::Zero()), mIndex(aIndex), mRepetitionCount(aRepetitionCount), @@ -54,6 +56,10 @@ void ImageTrack::SetSelected(bool aSelected) { } } +void ImageTrack::GetSizes(nsTArray<ImageSize>& aSizes) { + aSizes = mNativeSizes.Clone(); +} + void ImageTrack::OnFrameCountSuccess( const image::DecodeFrameCountResult& aResult) { MOZ_ASSERT_IF(mFrameCountComplete, mFrameCount == aResult.mFrameCount); diff --git a/dom/media/webcodecs/ImageTrack.h b/dom/media/webcodecs/ImageTrack.h @@ -32,8 +32,9 @@ class ImageTrack final : public nsISupports, public nsWrapperCache { NS_DECL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(ImageTrack) public: - ImageTrack(ImageTrackList* aTrackList, int32_t aIndex, bool aSelected, - bool aAnimated, uint32_t aFrameCount, bool aFrameCountComplete, + ImageTrack(ImageTrackList* aTrackList, int32_t aIndex, + nsTArray<ImageSize>&& aNativeSizes, bool aSelected, bool aAnimated, + uint32_t aFrameCount, bool aFrameCountComplete, float aRepetitionCount); protected: @@ -61,6 +62,8 @@ class ImageTrack final : public nsISupports, public nsWrapperCache { void SetSelected(bool aSelected); + void GetSizes(nsTArray<ImageSize>& aSizes); + void ClearSelected() { mSelected = false; } void MarkSelected() { mSelected = true; } @@ -85,6 +88,7 @@ class ImageTrack final : public nsISupports, public nsWrapperCache { nsCOMPtr<nsIGlobalObject> mParent; RefPtr<ImageTrackList> mTrackList; AutoTArray<RefPtr<VideoFrame>, 1> mDecodedFrames; + nsTArray<ImageSize> mNativeSizes; image::FrameTimeout mFramesTimestamp; int32_t mIndex = 0; float mRepetitionCount = 0.0f; diff --git a/dom/media/webcodecs/ImageTrackList.cpp b/dom/media/webcodecs/ImageTrackList.cpp @@ -74,6 +74,14 @@ void ImageTrackList::OnMetadataSuccess( // 4. Let newTrackList be a new list. MOZ_ASSERT(mTracks.IsEmpty()); + // Mozilla-internal-only addition + nsTArray<ImageSize> imageSizes; + for (const OrientedIntSize& nativeSize : aMetadata.mNativeSizes) { + ImageSize* imageSize = imageSizes.AppendElement(); + imageSize->mWidth = nativeSize.width; + imageSize->mHeight = nativeSize.height; + } + // 5. For each image track found in [[encoded data]]: // 5.1. Let newTrack be a new ImageTrack, initialized as follows: // 5.1.1. Assign this to [[ImageDecoder]]. @@ -97,8 +105,9 @@ void ImageTrackList::OnMetadataSuccess( ? std::numeric_limits<float>::infinity() : static_cast<float>(aMetadata.mRepetitions); auto track = MakeRefPtr<ImageTrack>( - this, /* aIndex */ 0, /* aSelected */ true, aMetadata.mAnimated, - aMetadata.mFrameCount, aMetadata.mFrameCountComplete, repetitions); + this, /* aIndex */ 0, std::move(imageSizes), /* aSelected */ true, + aMetadata.mAnimated, aMetadata.mFrameCount, aMetadata.mFrameCountComplete, + repetitions); // 11. Queue a task to perform the following steps: // diff --git a/dom/media/webcodecs/test/mochitest.toml b/dom/media/webcodecs/test/mochitest.toml @@ -7,7 +7,8 @@ prefs = [ ] support-files = [ "bug1921817.jpg", - "green.png" + "green.png", + "multiple.ico" ] ["test_bug1921817.html"] @@ -29,4 +30,7 @@ scheme = "https" ["test_rfp_api_disabling_exemption.html"] scheme = "https" +["test_track_getNativeSizes.html"] +scheme = "https" + ["test_videoFrame_mismatched_codedSize.html"] diff --git a/dom/media/webcodecs/test/multiple.ico b/dom/media/webcodecs/test/multiple.ico Binary files differ. diff --git a/dom/media/webcodecs/test/test_track_getNativeSizes.html b/dom/media/webcodecs/test/test_track_getNativeSizes.html @@ -0,0 +1,56 @@ +<!DOCTYPE HTML> +<html> +<head> + <title></title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<script> + +// Bug 1924775 - ESLint doesn't yet know about `ImageDecoder`. +/* globals ImageDecoder:false */ + +add_task(async function test() { + const imgResponse = await fetch("multiple.ico"); + const data = await imgResponse.bytes(); + + let decoder = new ImageDecoder({ + data, + type: "image/x-icon", + }); + await decoder.tracks.ready; + + is(typeof decoder.tracks[0].getSizes, "undefined", "getSizes should be hidden from normal content"); + let sizes = SpecialPowers.wrap(decoder.tracks[0]).getSizes(); + is(sizes.length, 3, "Should have 3 sizes"); + + let expected = [[16, {r: 205, g: 8, b: 59}], [32, {r: 88, g: 205, b: 103 }], [512, {r:100, g: 205, b: 224}]]; + for (let i = 0; i < expected.length; i++) { + const [size, color] = expected[i]; + + is(sizes[i].width, size, "width matches"); + is(sizes[i].height, size, "height matches"); + + let decoder = new ImageDecoder({ + data, + type: "image/x-icon", + desiredWidth: size, + desiredHeight: size, + }); + + let { image } = await decoder.decode({ completeFramesOnly: true } ); + + let offscreen = new OffscreenCanvas(size, size); + let ctx = offscreen.getContext("2d"); + ctx.drawImage(image, 0, 0); + + let imageData = ctx.getImageData(0, 0, 1, 1); + is(imageData.data[0], color.r, `${size}x${size} red`); + is(imageData.data[1], color.g, `${size}x${size} green`); + is(imageData.data[2], color.b, `${size}x${size} bluee`); + } +}); +</script> +</body> +</html> diff --git a/dom/webidl/ImageDecoder.webidl b/dom/webidl/ImageDecoder.webidl @@ -28,6 +28,11 @@ dictionary ImageDecodeResult { required boolean complete; }; +dictionary ImageSize { + required unsigned long width; + required unsigned long height; +}; + [Exposed=(Window,DedicatedWorker), SecureContext, Func="nsRFPService::ExposeWebCodecsAPIImageDecoder"] @@ -36,6 +41,10 @@ interface ImageTrack { readonly attribute unsigned long frameCount; readonly attribute unrestricted float repetitionCount; attribute boolean selected; + + // Mozilla-internal-only addition + [ChromeOnly] + sequence<ImageSize> getSizes(); }; [Exposed=(Window,DedicatedWorker), diff --git a/image/ImageUtils.cpp b/image/ImageUtils.cpp @@ -292,6 +292,8 @@ class AnonymousDecoderImpl final : public AnonymousDecoder { return; } + mMetadataResult.mNativeSizes = aMetadata->GetNativeSizes().Clone(); + const auto size = aMetadata->GetSize(); mMetadataResult.mWidth = size.width; mMetadataResult.mHeight = size.height; diff --git a/image/ImageUtils.h b/image/ImageUtils.h @@ -7,6 +7,7 @@ #define mozilla_image_ImageUtils_h #include "FrameTimeout.h" +#include "Orientation.h" #include "mozilla/image/SurfaceFlags.h" #include "mozilla/Maybe.h" #include "mozilla/MozPromise.h" @@ -48,6 +49,7 @@ enum class DecoderType { }; struct DecodeMetadataResult { + CopyableTArray<OrientedIntSize> mNativeSizes; int32_t mWidth = 0; int32_t mHeight = 0; int32_t mRepetitions = -1;