Bug 1824595 [wpt PR 39207] - LoAF: Deflake script tests, a=testonly
[gecko.git] / image / DecoderFactory.cpp
blob4ee7fdfd220596d1671edb2c97a07edaf93ff876
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "DecoderFactory.h"
8 #include "nsMimeTypes.h"
9 #include "mozilla/RefPtr.h"
11 #include "AnimationSurfaceProvider.h"
12 #include "Decoder.h"
13 #include "DecodedSurfaceProvider.h"
14 #include "IDecodingTask.h"
15 #include "ImageOps.h"
16 #include "nsPNGDecoder.h"
17 #include "nsGIFDecoder2.h"
18 #include "nsJPEGDecoder.h"
19 #include "nsBMPDecoder.h"
20 #include "nsICODecoder.h"
21 #include "nsIconDecoder.h"
22 #include "nsWebPDecoder.h"
23 #ifdef MOZ_AV1
24 # include "nsAVIFDecoder.h"
25 #endif
26 #ifdef MOZ_JXL
27 # include "nsJXLDecoder.h"
28 #endif
30 namespace mozilla {
32 using namespace gfx;
34 namespace image {
36 /* static */
37 DecoderType DecoderFactory::GetDecoderType(const char* aMimeType) {
38 // By default we don't know.
39 DecoderType type = DecoderType::UNKNOWN;
41 // PNG
42 if (!strcmp(aMimeType, IMAGE_PNG)) {
43 type = DecoderType::PNG;
44 } else if (!strcmp(aMimeType, IMAGE_X_PNG)) {
45 type = DecoderType::PNG;
46 } else if (!strcmp(aMimeType, IMAGE_APNG)) {
47 type = DecoderType::PNG;
49 // GIF
50 } else if (!strcmp(aMimeType, IMAGE_GIF)) {
51 type = DecoderType::GIF;
53 // JPEG
54 } else if (!strcmp(aMimeType, IMAGE_JPEG)) {
55 type = DecoderType::JPEG;
56 } else if (!strcmp(aMimeType, IMAGE_PJPEG)) {
57 type = DecoderType::JPEG;
58 } else if (!strcmp(aMimeType, IMAGE_JPG)) {
59 type = DecoderType::JPEG;
61 // BMP
62 } else if (!strcmp(aMimeType, IMAGE_BMP)) {
63 type = DecoderType::BMP;
64 } else if (!strcmp(aMimeType, IMAGE_BMP_MS)) {
65 type = DecoderType::BMP;
67 // BMP_CLIPBOARD
68 } else if (!strcmp(aMimeType, IMAGE_BMP_MS_CLIPBOARD)) {
69 type = DecoderType::BMP_CLIPBOARD;
71 // ICO
72 } else if (!strcmp(aMimeType, IMAGE_ICO)) {
73 type = DecoderType::ICO;
74 } else if (!strcmp(aMimeType, IMAGE_ICO_MS)) {
75 type = DecoderType::ICO;
77 // Icon
78 } else if (!strcmp(aMimeType, IMAGE_ICON_MS)) {
79 type = DecoderType::ICON;
81 // WebP
82 } else if (!strcmp(aMimeType, IMAGE_WEBP) &&
83 StaticPrefs::image_webp_enabled()) {
84 type = DecoderType::WEBP;
86 // AVIF
88 #ifdef MOZ_AV1
89 else if (!strcmp(aMimeType, IMAGE_AVIF) &&
90 StaticPrefs::image_avif_enabled()) {
91 type = DecoderType::AVIF;
93 #endif
94 #ifdef MOZ_JXL
95 else if (!strcmp(aMimeType, IMAGE_JXL) && StaticPrefs::image_jxl_enabled()) {
96 type = DecoderType::JXL;
98 #endif
100 return type;
103 /* static */
104 DecoderFlags DecoderFactory::GetDefaultDecoderFlagsForType(DecoderType aType) {
105 auto flags = DefaultDecoderFlags();
107 #ifdef MOZ_AV1
108 if (aType == DecoderType::AVIF) {
109 if (StaticPrefs::image_avif_sequence_enabled()) {
110 flags |= DecoderFlags::AVIF_SEQUENCES_ENABLED;
112 if (StaticPrefs::image_avif_sequence_animate_avif_major_branded_images()) {
113 flags |= DecoderFlags::AVIF_ANIMATE_AVIF_MAJOR;
116 #endif
118 return flags;
121 /* static */
122 already_AddRefed<Decoder> DecoderFactory::GetDecoder(DecoderType aType,
123 RasterImage* aImage,
124 bool aIsRedecode) {
125 RefPtr<Decoder> decoder;
127 switch (aType) {
128 case DecoderType::PNG:
129 decoder = new nsPNGDecoder(aImage);
130 break;
131 case DecoderType::GIF:
132 decoder = new nsGIFDecoder2(aImage);
133 break;
134 case DecoderType::JPEG:
135 // If we have all the data we don't want to waste cpu time doing
136 // a progressive decode.
137 decoder = new nsJPEGDecoder(
138 aImage, aIsRedecode ? Decoder::SEQUENTIAL : Decoder::PROGRESSIVE);
139 break;
140 case DecoderType::BMP:
141 decoder = new nsBMPDecoder(aImage);
142 break;
143 case DecoderType::BMP_CLIPBOARD:
144 decoder = new nsBMPDecoder(aImage, /* aForClipboard */ true);
145 break;
146 case DecoderType::ICO:
147 decoder = new nsICODecoder(aImage);
148 break;
149 case DecoderType::ICON:
150 decoder = new nsIconDecoder(aImage);
151 break;
152 case DecoderType::WEBP:
153 decoder = new nsWebPDecoder(aImage);
154 break;
155 #ifdef MOZ_AV1
156 case DecoderType::AVIF:
157 decoder = new nsAVIFDecoder(aImage);
158 break;
159 #endif
160 #ifdef MOZ_JXL
161 case DecoderType::JXL:
162 decoder = new nsJXLDecoder(aImage);
163 break;
164 #endif
165 default:
166 MOZ_ASSERT_UNREACHABLE("Unknown decoder type");
169 return decoder.forget();
172 /* static */
173 nsresult DecoderFactory::CreateDecoder(
174 DecoderType aType, NotNull<RasterImage*> aImage,
175 NotNull<SourceBuffer*> aSourceBuffer, const IntSize& aIntrinsicSize,
176 const IntSize& aOutputSize, DecoderFlags aDecoderFlags,
177 SurfaceFlags aSurfaceFlags, IDecodingTask** aOutTask) {
178 if (aType == DecoderType::UNKNOWN) {
179 return NS_ERROR_INVALID_ARG;
182 // Create an anonymous decoder. Interaction with the SurfaceCache and the
183 // owning RasterImage will be mediated by DecodedSurfaceProvider.
184 RefPtr<Decoder> decoder = GetDecoder(
185 aType, nullptr, bool(aDecoderFlags & DecoderFlags::IS_REDECODE));
186 MOZ_ASSERT(decoder, "Should have a decoder now");
188 // Initialize the decoder.
189 decoder->SetMetadataDecode(false);
190 decoder->SetIterator(aSourceBuffer->Iterator());
191 decoder->SetOutputSize(OrientedIntSize::FromUnknownSize(aOutputSize));
192 decoder->SetDecoderFlags(aDecoderFlags | DecoderFlags::FIRST_FRAME_ONLY);
193 decoder->SetSurfaceFlags(aSurfaceFlags);
195 nsresult rv = decoder->Init();
196 if (NS_FAILED(rv)) {
197 return NS_ERROR_FAILURE;
200 // Create a DecodedSurfaceProvider which will manage the decoding process and
201 // make this decoder's output available in the surface cache.
202 SurfaceKey surfaceKey =
203 RasterSurfaceKey(aOutputSize, aSurfaceFlags, PlaybackType::eStatic);
204 auto provider = MakeNotNull<RefPtr<DecodedSurfaceProvider>>(
205 aImage, surfaceKey, WrapNotNull(decoder));
206 if (aDecoderFlags & DecoderFlags::CANNOT_SUBSTITUTE) {
207 provider->Availability().SetCannotSubstitute();
210 // Attempt to insert the surface provider into the surface cache right away so
211 // we won't trigger any more decoders with the same parameters.
212 switch (SurfaceCache::Insert(provider)) {
213 case InsertOutcome::SUCCESS:
214 break;
215 case InsertOutcome::FAILURE_ALREADY_PRESENT:
216 return NS_ERROR_ALREADY_INITIALIZED;
217 default:
218 return NS_ERROR_FAILURE;
221 // Return the surface provider in its IDecodingTask guise.
222 RefPtr<IDecodingTask> task = provider.get();
223 task.forget(aOutTask);
224 return NS_OK;
227 /* static */
228 nsresult DecoderFactory::CreateAnimationDecoder(
229 DecoderType aType, NotNull<RasterImage*> aImage,
230 NotNull<SourceBuffer*> aSourceBuffer, const IntSize& aIntrinsicSize,
231 DecoderFlags aDecoderFlags, SurfaceFlags aSurfaceFlags,
232 size_t aCurrentFrame, IDecodingTask** aOutTask) {
233 if (aType == DecoderType::UNKNOWN) {
234 return NS_ERROR_INVALID_ARG;
237 MOZ_ASSERT(aType == DecoderType::GIF || aType == DecoderType::PNG ||
238 aType == DecoderType::WEBP || aType == DecoderType::AVIF,
239 "Calling CreateAnimationDecoder for non-animating DecoderType");
241 // Create an anonymous decoder. Interaction with the SurfaceCache and the
242 // owning RasterImage will be mediated by AnimationSurfaceProvider.
243 RefPtr<Decoder> decoder =
244 GetDecoder(aType, nullptr, /* aIsRedecode = */ true);
245 MOZ_ASSERT(decoder, "Should have a decoder now");
247 // Initialize the decoder.
248 decoder->SetMetadataDecode(false);
249 decoder->SetIterator(aSourceBuffer->Iterator());
250 decoder->SetDecoderFlags(aDecoderFlags | DecoderFlags::IS_REDECODE);
251 decoder->SetSurfaceFlags(aSurfaceFlags);
253 nsresult rv = decoder->Init();
254 if (NS_FAILED(rv)) {
255 return NS_ERROR_FAILURE;
258 // Create an AnimationSurfaceProvider which will manage the decoding process
259 // and make this decoder's output available in the surface cache.
260 SurfaceKey surfaceKey =
261 RasterSurfaceKey(aIntrinsicSize, aSurfaceFlags, PlaybackType::eAnimated);
262 auto provider = MakeNotNull<RefPtr<AnimationSurfaceProvider>>(
263 aImage, surfaceKey, WrapNotNull(decoder), aCurrentFrame);
265 // Attempt to insert the surface provider into the surface cache right away so
266 // we won't trigger any more decoders with the same parameters.
267 switch (SurfaceCache::Insert(provider)) {
268 case InsertOutcome::SUCCESS:
269 break;
270 case InsertOutcome::FAILURE_ALREADY_PRESENT:
271 return NS_ERROR_ALREADY_INITIALIZED;
272 default:
273 return NS_ERROR_FAILURE;
276 // Return the surface provider in its IDecodingTask guise.
277 RefPtr<IDecodingTask> task = provider.get();
278 task.forget(aOutTask);
279 return NS_OK;
282 /* static */
283 already_AddRefed<Decoder> DecoderFactory::CloneAnimationDecoder(
284 Decoder* aDecoder) {
285 MOZ_ASSERT(aDecoder);
287 // In an ideal world, we would assert aDecoder->HasAnimation() but we cannot.
288 // The decoder may not have detected it is animated yet (e.g. it did not even
289 // get scheduled yet, or it has only decoded the first frame and has yet to
290 // rediscover it is animated).
291 DecoderType type = aDecoder->GetType();
292 MOZ_ASSERT(type == DecoderType::GIF || type == DecoderType::PNG ||
293 type == DecoderType::WEBP || type == DecoderType::AVIF,
294 "Calling CloneAnimationDecoder for non-animating DecoderType");
296 RefPtr<Decoder> decoder = GetDecoder(type, nullptr, /* aIsRedecode = */ true);
297 MOZ_ASSERT(decoder, "Should have a decoder now");
299 // Initialize the decoder.
300 decoder->SetMetadataDecode(false);
301 decoder->SetIterator(aDecoder->GetSourceBuffer()->Iterator());
302 decoder->SetDecoderFlags(aDecoder->GetDecoderFlags());
303 decoder->SetSurfaceFlags(aDecoder->GetSurfaceFlags());
304 decoder->SetFrameRecycler(aDecoder->GetFrameRecycler());
306 if (NS_FAILED(decoder->Init())) {
307 return nullptr;
310 return decoder.forget();
313 /* static */
314 already_AddRefed<IDecodingTask> DecoderFactory::CreateMetadataDecoder(
315 DecoderType aType, NotNull<RasterImage*> aImage, DecoderFlags aFlags,
316 NotNull<SourceBuffer*> aSourceBuffer) {
317 if (aType == DecoderType::UNKNOWN) {
318 return nullptr;
321 RefPtr<Decoder> decoder =
322 GetDecoder(aType, aImage, /* aIsRedecode = */ false);
323 MOZ_ASSERT(decoder, "Should have a decoder now");
325 // Initialize the decoder.
326 decoder->SetMetadataDecode(true);
327 decoder->SetDecoderFlags(aFlags);
328 decoder->SetIterator(aSourceBuffer->Iterator());
330 if (NS_FAILED(decoder->Init())) {
331 return nullptr;
334 RefPtr<IDecodingTask> task = new MetadataDecodingTask(WrapNotNull(decoder));
335 return task.forget();
338 /* static */
339 already_AddRefed<Decoder> DecoderFactory::CreateDecoderForICOResource(
340 DecoderType aType, SourceBufferIterator&& aIterator,
341 NotNull<nsICODecoder*> aICODecoder, bool aIsMetadataDecode,
342 const Maybe<OrientedIntSize>& aExpectedSize,
343 const Maybe<uint32_t>& aDataOffset
344 /* = Nothing() */) {
345 // Create the decoder.
346 RefPtr<Decoder> decoder;
347 switch (aType) {
348 case DecoderType::BMP:
349 MOZ_ASSERT(aDataOffset);
350 decoder =
351 new nsBMPDecoder(aICODecoder->GetImageMaybeNull(), *aDataOffset);
352 break;
354 case DecoderType::PNG:
355 MOZ_ASSERT(!aDataOffset);
356 decoder = new nsPNGDecoder(aICODecoder->GetImageMaybeNull());
357 break;
359 default:
360 MOZ_ASSERT_UNREACHABLE("Invalid ICO resource decoder type");
361 return nullptr;
364 MOZ_ASSERT(decoder);
366 // Initialize the decoder, copying settings from @aICODecoder.
367 decoder->SetMetadataDecode(aIsMetadataDecode);
368 decoder->SetIterator(std::forward<SourceBufferIterator>(aIterator));
369 if (!aIsMetadataDecode) {
370 decoder->SetOutputSize(aICODecoder->OutputSize());
372 if (aExpectedSize) {
373 decoder->SetExpectedSize(*aExpectedSize);
375 decoder->SetDecoderFlags(aICODecoder->GetDecoderFlags());
376 decoder->SetSurfaceFlags(aICODecoder->GetSurfaceFlags());
377 decoder->SetFinalizeFrames(false);
379 if (NS_FAILED(decoder->Init())) {
380 return nullptr;
383 return decoder.forget();
386 /* static */
387 already_AddRefed<Decoder> DecoderFactory::CreateAnonymousDecoder(
388 DecoderType aType, NotNull<SourceBuffer*> aSourceBuffer,
389 const Maybe<IntSize>& aOutputSize, DecoderFlags aDecoderFlags,
390 SurfaceFlags aSurfaceFlags) {
391 if (aType == DecoderType::UNKNOWN) {
392 return nullptr;
395 RefPtr<Decoder> decoder =
396 GetDecoder(aType, /* aImage = */ nullptr, /* aIsRedecode = */ false);
397 MOZ_ASSERT(decoder, "Should have a decoder now");
399 // Initialize the decoder.
400 decoder->SetMetadataDecode(false);
401 decoder->SetIterator(aSourceBuffer->Iterator());
403 // Anonymous decoders are always transient; we don't want to optimize surfaces
404 // or do any other expensive work that might be wasted.
405 DecoderFlags decoderFlags = DecoderFlags::IMAGE_IS_TRANSIENT;
407 decoder->SetDecoderFlags(aDecoderFlags | decoderFlags);
408 decoder->SetSurfaceFlags(aSurfaceFlags);
410 // Set an output size for downscale-during-decode if requested.
411 if (aOutputSize) {
412 decoder->SetOutputSize(OrientedIntSize::FromUnknownSize(*aOutputSize));
415 if (NS_FAILED(decoder->Init())) {
416 return nullptr;
419 return decoder.forget();
422 /* static */
423 already_AddRefed<Decoder> DecoderFactory::CreateAnonymousMetadataDecoder(
424 DecoderType aType, NotNull<SourceBuffer*> aSourceBuffer) {
425 if (aType == DecoderType::UNKNOWN) {
426 return nullptr;
429 RefPtr<Decoder> decoder =
430 GetDecoder(aType, /* aImage = */ nullptr, /* aIsRedecode = */ false);
431 MOZ_ASSERT(decoder, "Should have a decoder now");
433 // Initialize the decoder.
434 decoder->SetMetadataDecode(true);
435 decoder->SetIterator(aSourceBuffer->Iterator());
436 decoder->SetDecoderFlags(DecoderFlags::FIRST_FRAME_ONLY);
438 if (NS_FAILED(decoder->Init())) {
439 return nullptr;
442 return decoder.forget();
445 } // namespace image
446 } // namespace mozilla