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:
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;