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"
13 #include "DecodedSurfaceProvider.h"
14 #include "IDecodingTask.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"
24 # include "nsAVIFDecoder.h"
27 # include "nsJXLDecoder.h"
37 DecoderType
DecoderFactory::GetDecoderType(const char* aMimeType
) {
38 // By default we don't know.
39 DecoderType type
= DecoderType::UNKNOWN
;
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
;
50 } else if (!strcmp(aMimeType
, IMAGE_GIF
)) {
51 type
= DecoderType::GIF
;
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
;
62 } else if (!strcmp(aMimeType
, IMAGE_BMP
)) {
63 type
= DecoderType::BMP
;
64 } else if (!strcmp(aMimeType
, IMAGE_BMP_MS
)) {
65 type
= DecoderType::BMP
;
68 } else if (!strcmp(aMimeType
, IMAGE_BMP_MS_CLIPBOARD
)) {
69 type
= DecoderType::BMP_CLIPBOARD
;
72 } else if (!strcmp(aMimeType
, IMAGE_ICO
)) {
73 type
= DecoderType::ICO
;
74 } else if (!strcmp(aMimeType
, IMAGE_ICO_MS
)) {
75 type
= DecoderType::ICO
;
78 } else if (!strcmp(aMimeType
, IMAGE_ICON_MS
)) {
79 type
= DecoderType::ICON
;
82 } else if (!strcmp(aMimeType
, IMAGE_WEBP
)) {
83 type
= DecoderType::WEBP
;
88 else if (!strcmp(aMimeType
, IMAGE_AVIF
) &&
89 StaticPrefs::image_avif_enabled()) {
90 type
= DecoderType::AVIF
;
94 else if (!strcmp(aMimeType
, IMAGE_JXL
) && StaticPrefs::image_jxl_enabled()) {
95 type
= DecoderType::JXL
;
103 DecoderFlags
DecoderFactory::GetDefaultDecoderFlagsForType(DecoderType aType
) {
104 auto flags
= DefaultDecoderFlags();
107 if (aType
== DecoderType::AVIF
) {
108 if (StaticPrefs::image_avif_sequence_enabled()) {
109 flags
|= DecoderFlags::AVIF_SEQUENCES_ENABLED
;
111 if (StaticPrefs::image_avif_sequence_animate_avif_major_branded_images()) {
112 flags
|= DecoderFlags::AVIF_ANIMATE_AVIF_MAJOR
;
121 already_AddRefed
<Decoder
> DecoderFactory::GetDecoder(DecoderType aType
,
124 RefPtr
<Decoder
> decoder
;
127 case DecoderType::PNG
:
128 decoder
= new nsPNGDecoder(aImage
);
130 case DecoderType::GIF
:
131 decoder
= new nsGIFDecoder2(aImage
);
133 case DecoderType::JPEG
:
134 // If we have all the data we don't want to waste cpu time doing
135 // a progressive decode.
136 decoder
= new nsJPEGDecoder(
137 aImage
, aIsRedecode
? Decoder::SEQUENTIAL
: Decoder::PROGRESSIVE
);
139 case DecoderType::BMP
:
140 decoder
= new nsBMPDecoder(aImage
);
142 case DecoderType::BMP_CLIPBOARD
:
143 decoder
= new nsBMPDecoder(aImage
, /* aForClipboard */ true);
145 case DecoderType::ICO
:
146 decoder
= new nsICODecoder(aImage
);
148 case DecoderType::ICON
:
149 decoder
= new nsIconDecoder(aImage
);
151 case DecoderType::WEBP
:
152 decoder
= new nsWebPDecoder(aImage
);
155 case DecoderType::AVIF
:
156 decoder
= new nsAVIFDecoder(aImage
);
160 case DecoderType::JXL
:
161 decoder
= new nsJXLDecoder(aImage
);
165 MOZ_ASSERT_UNREACHABLE("Unknown decoder type");
168 return decoder
.forget();
172 nsresult
DecoderFactory::CreateDecoder(
173 DecoderType aType
, NotNull
<RasterImage
*> aImage
,
174 NotNull
<SourceBuffer
*> aSourceBuffer
, const IntSize
& aIntrinsicSize
,
175 const IntSize
& aOutputSize
, DecoderFlags aDecoderFlags
,
176 SurfaceFlags aSurfaceFlags
, IDecodingTask
** aOutTask
) {
177 if (aType
== DecoderType::UNKNOWN
) {
178 return NS_ERROR_INVALID_ARG
;
181 // Only can use COUNT_FRAMES with metadata decoders.
182 if (NS_WARN_IF(bool(aDecoderFlags
& DecoderFlags::COUNT_FRAMES
))) {
183 return NS_ERROR_INVALID_ARG
;
186 // Create an anonymous decoder. Interaction with the SurfaceCache and the
187 // owning RasterImage will be mediated by DecodedSurfaceProvider.
188 RefPtr
<Decoder
> decoder
= GetDecoder(
189 aType
, nullptr, bool(aDecoderFlags
& DecoderFlags::IS_REDECODE
));
190 MOZ_ASSERT(decoder
, "Should have a decoder now");
192 // Initialize the decoder.
193 decoder
->SetMetadataDecode(false);
194 decoder
->SetIterator(aSourceBuffer
->Iterator());
195 decoder
->SetOutputSize(OrientedIntSize::FromUnknownSize(aOutputSize
));
196 decoder
->SetDecoderFlags(aDecoderFlags
| DecoderFlags::FIRST_FRAME_ONLY
);
197 decoder
->SetSurfaceFlags(aSurfaceFlags
);
199 nsresult rv
= decoder
->Init();
201 return NS_ERROR_FAILURE
;
204 // Create a DecodedSurfaceProvider which will manage the decoding process and
205 // make this decoder's output available in the surface cache.
206 SurfaceKey surfaceKey
=
207 RasterSurfaceKey(aOutputSize
, aSurfaceFlags
, PlaybackType::eStatic
);
208 auto provider
= MakeNotNull
<RefPtr
<DecodedSurfaceProvider
>>(
209 aImage
, surfaceKey
, WrapNotNull(decoder
));
210 if (aDecoderFlags
& DecoderFlags::CANNOT_SUBSTITUTE
) {
211 provider
->Availability().SetCannotSubstitute();
214 // Attempt to insert the surface provider into the surface cache right away so
215 // we won't trigger any more decoders with the same parameters.
216 switch (SurfaceCache::Insert(provider
)) {
217 case InsertOutcome::SUCCESS
:
219 case InsertOutcome::FAILURE_ALREADY_PRESENT
:
220 return NS_ERROR_ALREADY_INITIALIZED
;
222 return NS_ERROR_FAILURE
;
225 // Return the surface provider in its IDecodingTask guise.
226 RefPtr
<IDecodingTask
> task
= provider
.get();
227 task
.forget(aOutTask
);
232 nsresult
DecoderFactory::CreateAnimationDecoder(
233 DecoderType aType
, NotNull
<RasterImage
*> aImage
,
234 NotNull
<SourceBuffer
*> aSourceBuffer
, const IntSize
& aIntrinsicSize
,
235 DecoderFlags aDecoderFlags
, SurfaceFlags aSurfaceFlags
,
236 size_t aCurrentFrame
, IDecodingTask
** aOutTask
) {
237 if (aType
== DecoderType::UNKNOWN
) {
238 return NS_ERROR_INVALID_ARG
;
241 // Only can use COUNT_FRAMES with metadata decoders.
242 if (NS_WARN_IF(bool(aDecoderFlags
& DecoderFlags::COUNT_FRAMES
))) {
243 return NS_ERROR_INVALID_ARG
;
246 MOZ_ASSERT(aType
== DecoderType::GIF
|| aType
== DecoderType::PNG
||
247 aType
== DecoderType::WEBP
|| aType
== DecoderType::AVIF
,
248 "Calling CreateAnimationDecoder for non-animating DecoderType");
250 // Create an anonymous decoder. Interaction with the SurfaceCache and the
251 // owning RasterImage will be mediated by AnimationSurfaceProvider.
252 RefPtr
<Decoder
> decoder
=
253 GetDecoder(aType
, nullptr, /* aIsRedecode = */ true);
254 MOZ_ASSERT(decoder
, "Should have a decoder now");
256 // Initialize the decoder.
257 decoder
->SetMetadataDecode(false);
258 decoder
->SetIterator(aSourceBuffer
->Iterator());
259 decoder
->SetDecoderFlags(aDecoderFlags
| DecoderFlags::IS_REDECODE
);
260 decoder
->SetSurfaceFlags(aSurfaceFlags
);
262 nsresult rv
= decoder
->Init();
264 return NS_ERROR_FAILURE
;
267 // Create an AnimationSurfaceProvider which will manage the decoding process
268 // and make this decoder's output available in the surface cache.
269 SurfaceKey surfaceKey
=
270 RasterSurfaceKey(aIntrinsicSize
, aSurfaceFlags
, PlaybackType::eAnimated
);
271 auto provider
= MakeNotNull
<RefPtr
<AnimationSurfaceProvider
>>(
272 aImage
, surfaceKey
, WrapNotNull(decoder
), aCurrentFrame
);
274 // Attempt to insert the surface provider into the surface cache right away so
275 // we won't trigger any more decoders with the same parameters.
276 switch (SurfaceCache::Insert(provider
)) {
277 case InsertOutcome::SUCCESS
:
279 case InsertOutcome::FAILURE_ALREADY_PRESENT
:
280 return NS_ERROR_ALREADY_INITIALIZED
;
282 return NS_ERROR_FAILURE
;
285 // Return the surface provider in its IDecodingTask guise.
286 RefPtr
<IDecodingTask
> task
= provider
.get();
287 task
.forget(aOutTask
);
292 already_AddRefed
<Decoder
> DecoderFactory::CloneAnimationDecoder(
294 MOZ_ASSERT(aDecoder
);
296 // In an ideal world, we would assert aDecoder->HasAnimation() but we cannot.
297 // The decoder may not have detected it is animated yet (e.g. it did not even
298 // get scheduled yet, or it has only decoded the first frame and has yet to
299 // rediscover it is animated).
300 DecoderType type
= aDecoder
->GetType();
301 MOZ_ASSERT(type
== DecoderType::GIF
|| type
== DecoderType::PNG
||
302 type
== DecoderType::WEBP
|| type
== DecoderType::AVIF
,
303 "Calling CloneAnimationDecoder for non-animating DecoderType");
305 RefPtr
<Decoder
> decoder
= GetDecoder(type
, nullptr, /* aIsRedecode = */ true);
306 MOZ_ASSERT(decoder
, "Should have a decoder now");
308 // Initialize the decoder.
309 decoder
->SetMetadataDecode(false);
310 decoder
->SetIterator(aDecoder
->GetSourceBuffer()->Iterator());
311 decoder
->SetDecoderFlags(aDecoder
->GetDecoderFlags());
312 decoder
->SetSurfaceFlags(aDecoder
->GetSurfaceFlags());
313 decoder
->SetFrameRecycler(aDecoder
->GetFrameRecycler());
315 if (NS_FAILED(decoder
->Init())) {
319 return decoder
.forget();
323 already_AddRefed
<Decoder
> DecoderFactory::CloneAnonymousMetadataDecoder(
324 Decoder
* aDecoder
, const Maybe
<DecoderFlags
>& aDecoderFlags
) {
325 MOZ_ASSERT(aDecoder
);
327 DecoderType type
= aDecoder
->GetType();
328 RefPtr
<Decoder
> decoder
=
329 GetDecoder(type
, nullptr, /* aIsRedecode = */ false);
330 MOZ_ASSERT(decoder
, "Should have a decoder now");
332 // Initialize the decoder.
333 decoder
->SetMetadataDecode(true);
334 decoder
->SetIterator(aDecoder
->GetSourceBuffer()->Iterator());
336 decoder
->SetDecoderFlags(*aDecoderFlags
);
338 decoder
->SetDecoderFlags(aDecoder
->GetDecoderFlags());
341 if (NS_FAILED(decoder
->Init())) {
345 return decoder
.forget();
349 already_AddRefed
<IDecodingTask
> DecoderFactory::CreateMetadataDecoder(
350 DecoderType aType
, NotNull
<RasterImage
*> aImage
, DecoderFlags aFlags
,
351 NotNull
<SourceBuffer
*> aSourceBuffer
) {
352 if (aType
== DecoderType::UNKNOWN
) {
356 RefPtr
<Decoder
> decoder
=
357 GetDecoder(aType
, aImage
, /* aIsRedecode = */ false);
358 MOZ_ASSERT(decoder
, "Should have a decoder now");
360 // Initialize the decoder.
361 decoder
->SetMetadataDecode(true);
362 decoder
->SetDecoderFlags(aFlags
);
363 decoder
->SetIterator(aSourceBuffer
->Iterator());
365 if (NS_FAILED(decoder
->Init())) {
369 RefPtr
<IDecodingTask
> task
= new MetadataDecodingTask(WrapNotNull(decoder
));
370 return task
.forget();
374 already_AddRefed
<Decoder
> DecoderFactory::CreateDecoderForICOResource(
375 DecoderType aType
, SourceBufferIterator
&& aIterator
,
376 NotNull
<nsICODecoder
*> aICODecoder
, bool aIsMetadataDecode
,
377 const Maybe
<OrientedIntSize
>& aExpectedSize
,
378 const Maybe
<uint32_t>& aDataOffset
380 // Create the decoder.
381 RefPtr
<Decoder
> decoder
;
383 case DecoderType::BMP
:
384 MOZ_ASSERT(aDataOffset
);
386 new nsBMPDecoder(aICODecoder
->GetImageMaybeNull(), *aDataOffset
);
389 case DecoderType::PNG
:
390 MOZ_ASSERT(!aDataOffset
);
391 decoder
= new nsPNGDecoder(aICODecoder
->GetImageMaybeNull());
395 MOZ_ASSERT_UNREACHABLE("Invalid ICO resource decoder type");
401 // Initialize the decoder, copying settings from @aICODecoder.
402 decoder
->SetMetadataDecode(aIsMetadataDecode
);
403 decoder
->SetIterator(std::forward
<SourceBufferIterator
>(aIterator
));
404 if (!aIsMetadataDecode
) {
405 decoder
->SetOutputSize(aICODecoder
->OutputSize());
408 decoder
->SetExpectedSize(*aExpectedSize
);
410 decoder
->SetDecoderFlags(aICODecoder
->GetDecoderFlags());
411 decoder
->SetSurfaceFlags(aICODecoder
->GetSurfaceFlags());
412 decoder
->SetFinalizeFrames(false);
414 if (NS_FAILED(decoder
->Init())) {
418 return decoder
.forget();
422 already_AddRefed
<Decoder
> DecoderFactory::CreateAnonymousDecoder(
423 DecoderType aType
, NotNull
<SourceBuffer
*> aSourceBuffer
,
424 const Maybe
<IntSize
>& aOutputSize
, DecoderFlags aDecoderFlags
,
425 SurfaceFlags aSurfaceFlags
) {
426 if (aType
== DecoderType::UNKNOWN
) {
430 // Only can use COUNT_FRAMES with metadata decoders.
431 if (NS_WARN_IF(bool(aDecoderFlags
& DecoderFlags::COUNT_FRAMES
))) {
435 RefPtr
<Decoder
> decoder
=
436 GetDecoder(aType
, /* aImage = */ nullptr, /* aIsRedecode = */ false);
437 MOZ_ASSERT(decoder
, "Should have a decoder now");
439 // Initialize the decoder.
440 decoder
->SetMetadataDecode(false);
441 decoder
->SetIterator(aSourceBuffer
->Iterator());
443 // Anonymous decoders are always transient; we don't want to optimize surfaces
444 // or do any other expensive work that might be wasted.
445 DecoderFlags decoderFlags
= DecoderFlags::IMAGE_IS_TRANSIENT
;
447 decoder
->SetDecoderFlags(aDecoderFlags
| decoderFlags
);
448 decoder
->SetSurfaceFlags(aSurfaceFlags
);
450 // Set an output size for downscale-during-decode if requested.
452 decoder
->SetOutputSize(OrientedIntSize::FromUnknownSize(*aOutputSize
));
455 if (NS_FAILED(decoder
->Init())) {
459 return decoder
.forget();
463 already_AddRefed
<Decoder
> DecoderFactory::CreateAnonymousMetadataDecoder(
464 DecoderType aType
, NotNull
<SourceBuffer
*> aSourceBuffer
,
465 DecoderFlags aDecoderFlags
) {
466 if (aType
== DecoderType::UNKNOWN
) {
470 RefPtr
<Decoder
> decoder
=
471 GetDecoder(aType
, /* aImage = */ nullptr, /* aIsRedecode = */ false);
472 MOZ_ASSERT(decoder
, "Should have a decoder now");
474 // Initialize the decoder.
475 decoder
->SetMetadataDecode(true);
476 decoder
->SetIterator(aSourceBuffer
->Iterator());
477 decoder
->SetDecoderFlags(aDecoderFlags
);
479 if (NS_FAILED(decoder
->Init())) {
483 return decoder
.forget();
487 } // namespace mozilla