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 StaticPrefs::image_webp_enabled()) {
84 type
= DecoderType::WEBP
;
89 else if (!strcmp(aMimeType
, IMAGE_AVIF
) &&
90 StaticPrefs::image_avif_enabled()) {
91 type
= DecoderType::AVIF
;
95 else if (!strcmp(aMimeType
, IMAGE_JXL
) && StaticPrefs::image_jxl_enabled()) {
96 type
= DecoderType::JXL
;
104 already_AddRefed
<Decoder
> DecoderFactory::GetDecoder(DecoderType aType
,
107 RefPtr
<Decoder
> decoder
;
110 case DecoderType::PNG
:
111 decoder
= new nsPNGDecoder(aImage
);
113 case DecoderType::GIF
:
114 decoder
= new nsGIFDecoder2(aImage
);
116 case DecoderType::JPEG
:
117 // If we have all the data we don't want to waste cpu time doing
118 // a progressive decode.
119 decoder
= new nsJPEGDecoder(
120 aImage
, aIsRedecode
? Decoder::SEQUENTIAL
: Decoder::PROGRESSIVE
);
122 case DecoderType::BMP
:
123 decoder
= new nsBMPDecoder(aImage
);
125 case DecoderType::BMP_CLIPBOARD
:
126 decoder
= new nsBMPDecoder(aImage
, /* aForClipboard */ true);
128 case DecoderType::ICO
:
129 decoder
= new nsICODecoder(aImage
);
131 case DecoderType::ICON
:
132 decoder
= new nsIconDecoder(aImage
);
134 case DecoderType::WEBP
:
135 decoder
= new nsWebPDecoder(aImage
);
138 case DecoderType::AVIF
:
139 decoder
= new nsAVIFDecoder(aImage
);
143 case DecoderType::JXL
:
144 decoder
= new nsJXLDecoder(aImage
);
148 MOZ_ASSERT_UNREACHABLE("Unknown decoder type");
151 return decoder
.forget();
155 nsresult
DecoderFactory::CreateDecoder(
156 DecoderType aType
, NotNull
<RasterImage
*> aImage
,
157 NotNull
<SourceBuffer
*> aSourceBuffer
, const IntSize
& aIntrinsicSize
,
158 const IntSize
& aOutputSize
, DecoderFlags aDecoderFlags
,
159 SurfaceFlags aSurfaceFlags
, IDecodingTask
** aOutTask
) {
160 if (aType
== DecoderType::UNKNOWN
) {
161 return NS_ERROR_INVALID_ARG
;
164 // Create an anonymous decoder. Interaction with the SurfaceCache and the
165 // owning RasterImage will be mediated by DecodedSurfaceProvider.
166 RefPtr
<Decoder
> decoder
= GetDecoder(
167 aType
, nullptr, bool(aDecoderFlags
& DecoderFlags::IS_REDECODE
));
168 MOZ_ASSERT(decoder
, "Should have a decoder now");
170 // Initialize the decoder.
171 decoder
->SetMetadataDecode(false);
172 decoder
->SetIterator(aSourceBuffer
->Iterator());
173 decoder
->SetOutputSize(OrientedIntSize::FromUnknownSize(aOutputSize
));
174 decoder
->SetDecoderFlags(aDecoderFlags
| DecoderFlags::FIRST_FRAME_ONLY
);
175 decoder
->SetSurfaceFlags(aSurfaceFlags
);
177 nsresult rv
= decoder
->Init();
179 return NS_ERROR_FAILURE
;
182 // Create a DecodedSurfaceProvider which will manage the decoding process and
183 // make this decoder's output available in the surface cache.
184 SurfaceKey surfaceKey
=
185 RasterSurfaceKey(aOutputSize
, aSurfaceFlags
, PlaybackType::eStatic
);
186 auto provider
= MakeNotNull
<RefPtr
<DecodedSurfaceProvider
>>(
187 aImage
, surfaceKey
, WrapNotNull(decoder
));
188 if (aDecoderFlags
& DecoderFlags::CANNOT_SUBSTITUTE
) {
189 provider
->Availability().SetCannotSubstitute();
192 // Attempt to insert the surface provider into the surface cache right away so
193 // we won't trigger any more decoders with the same parameters.
194 switch (SurfaceCache::Insert(provider
)) {
195 case InsertOutcome::SUCCESS
:
197 case InsertOutcome::FAILURE_ALREADY_PRESENT
:
198 return NS_ERROR_ALREADY_INITIALIZED
;
200 return NS_ERROR_FAILURE
;
203 // Return the surface provider in its IDecodingTask guise.
204 RefPtr
<IDecodingTask
> task
= provider
.get();
205 task
.forget(aOutTask
);
210 nsresult
DecoderFactory::CreateAnimationDecoder(
211 DecoderType aType
, NotNull
<RasterImage
*> aImage
,
212 NotNull
<SourceBuffer
*> aSourceBuffer
, const IntSize
& aIntrinsicSize
,
213 DecoderFlags aDecoderFlags
, SurfaceFlags aSurfaceFlags
,
214 size_t aCurrentFrame
, IDecodingTask
** aOutTask
) {
215 if (aType
== DecoderType::UNKNOWN
) {
216 return NS_ERROR_INVALID_ARG
;
219 MOZ_ASSERT(aType
== DecoderType::GIF
|| aType
== DecoderType::PNG
||
220 aType
== DecoderType::WEBP
|| aType
== DecoderType::AVIF
,
221 "Calling CreateAnimationDecoder for non-animating DecoderType");
223 // Create an anonymous decoder. Interaction with the SurfaceCache and the
224 // owning RasterImage will be mediated by AnimationSurfaceProvider.
225 RefPtr
<Decoder
> decoder
=
226 GetDecoder(aType
, nullptr, /* aIsRedecode = */ true);
227 MOZ_ASSERT(decoder
, "Should have a decoder now");
229 // Initialize the decoder.
230 decoder
->SetMetadataDecode(false);
231 decoder
->SetIterator(aSourceBuffer
->Iterator());
232 decoder
->SetDecoderFlags(aDecoderFlags
| DecoderFlags::IS_REDECODE
);
233 decoder
->SetSurfaceFlags(aSurfaceFlags
);
235 nsresult rv
= decoder
->Init();
237 return NS_ERROR_FAILURE
;
240 // Create an AnimationSurfaceProvider which will manage the decoding process
241 // and make this decoder's output available in the surface cache.
242 SurfaceKey surfaceKey
=
243 RasterSurfaceKey(aIntrinsicSize
, aSurfaceFlags
, PlaybackType::eAnimated
);
244 auto provider
= MakeNotNull
<RefPtr
<AnimationSurfaceProvider
>>(
245 aImage
, surfaceKey
, WrapNotNull(decoder
), aCurrentFrame
);
247 // Attempt to insert the surface provider into the surface cache right away so
248 // we won't trigger any more decoders with the same parameters.
249 switch (SurfaceCache::Insert(provider
)) {
250 case InsertOutcome::SUCCESS
:
252 case InsertOutcome::FAILURE_ALREADY_PRESENT
:
253 return NS_ERROR_ALREADY_INITIALIZED
;
255 return NS_ERROR_FAILURE
;
258 // Return the surface provider in its IDecodingTask guise.
259 RefPtr
<IDecodingTask
> task
= provider
.get();
260 task
.forget(aOutTask
);
265 already_AddRefed
<Decoder
> DecoderFactory::CloneAnimationDecoder(
267 MOZ_ASSERT(aDecoder
);
269 // In an ideal world, we would assert aDecoder->HasAnimation() but we cannot.
270 // The decoder may not have detected it is animated yet (e.g. it did not even
271 // get scheduled yet, or it has only decoded the first frame and has yet to
272 // rediscover it is animated).
273 DecoderType type
= aDecoder
->GetType();
274 MOZ_ASSERT(type
== DecoderType::GIF
|| type
== DecoderType::PNG
||
275 type
== DecoderType::WEBP
|| type
== DecoderType::AVIF
,
276 "Calling CloneAnimationDecoder for non-animating DecoderType");
278 RefPtr
<Decoder
> decoder
= GetDecoder(type
, nullptr, /* aIsRedecode = */ true);
279 MOZ_ASSERT(decoder
, "Should have a decoder now");
281 // Initialize the decoder.
282 decoder
->SetMetadataDecode(false);
283 decoder
->SetIterator(aDecoder
->GetSourceBuffer()->Iterator());
284 decoder
->SetDecoderFlags(aDecoder
->GetDecoderFlags());
285 decoder
->SetSurfaceFlags(aDecoder
->GetSurfaceFlags());
286 decoder
->SetFrameRecycler(aDecoder
->GetFrameRecycler());
288 if (NS_FAILED(decoder
->Init())) {
292 return decoder
.forget();
296 already_AddRefed
<IDecodingTask
> DecoderFactory::CreateMetadataDecoder(
297 DecoderType aType
, NotNull
<RasterImage
*> aImage
,
298 NotNull
<SourceBuffer
*> aSourceBuffer
) {
299 if (aType
== DecoderType::UNKNOWN
) {
303 RefPtr
<Decoder
> decoder
=
304 GetDecoder(aType
, aImage
, /* aIsRedecode = */ false);
305 MOZ_ASSERT(decoder
, "Should have a decoder now");
307 // Initialize the decoder.
308 decoder
->SetMetadataDecode(true);
309 decoder
->SetIterator(aSourceBuffer
->Iterator());
311 if (NS_FAILED(decoder
->Init())) {
315 RefPtr
<IDecodingTask
> task
= new MetadataDecodingTask(WrapNotNull(decoder
));
316 return task
.forget();
320 already_AddRefed
<Decoder
> DecoderFactory::CreateDecoderForICOResource(
321 DecoderType aType
, SourceBufferIterator
&& aIterator
,
322 NotNull
<nsICODecoder
*> aICODecoder
, bool aIsMetadataDecode
,
323 const Maybe
<OrientedIntSize
>& aExpectedSize
,
324 const Maybe
<uint32_t>& aDataOffset
326 // Create the decoder.
327 RefPtr
<Decoder
> decoder
;
329 case DecoderType::BMP
:
330 MOZ_ASSERT(aDataOffset
);
332 new nsBMPDecoder(aICODecoder
->GetImageMaybeNull(), *aDataOffset
);
335 case DecoderType::PNG
:
336 MOZ_ASSERT(!aDataOffset
);
337 decoder
= new nsPNGDecoder(aICODecoder
->GetImageMaybeNull());
341 MOZ_ASSERT_UNREACHABLE("Invalid ICO resource decoder type");
347 // Initialize the decoder, copying settings from @aICODecoder.
348 decoder
->SetMetadataDecode(aIsMetadataDecode
);
349 decoder
->SetIterator(std::forward
<SourceBufferIterator
>(aIterator
));
350 if (!aIsMetadataDecode
) {
351 decoder
->SetOutputSize(aICODecoder
->OutputSize());
354 decoder
->SetExpectedSize(*aExpectedSize
);
356 decoder
->SetDecoderFlags(aICODecoder
->GetDecoderFlags());
357 decoder
->SetSurfaceFlags(aICODecoder
->GetSurfaceFlags());
358 decoder
->SetFinalizeFrames(false);
360 if (NS_FAILED(decoder
->Init())) {
364 return decoder
.forget();
368 already_AddRefed
<Decoder
> DecoderFactory::CreateAnonymousDecoder(
369 DecoderType aType
, NotNull
<SourceBuffer
*> aSourceBuffer
,
370 const Maybe
<IntSize
>& aOutputSize
, DecoderFlags aDecoderFlags
,
371 SurfaceFlags aSurfaceFlags
) {
372 if (aType
== DecoderType::UNKNOWN
) {
376 RefPtr
<Decoder
> decoder
=
377 GetDecoder(aType
, /* aImage = */ nullptr, /* aIsRedecode = */ false);
378 MOZ_ASSERT(decoder
, "Should have a decoder now");
380 // Initialize the decoder.
381 decoder
->SetMetadataDecode(false);
382 decoder
->SetIterator(aSourceBuffer
->Iterator());
384 // Anonymous decoders are always transient; we don't want to optimize surfaces
385 // or do any other expensive work that might be wasted.
386 DecoderFlags decoderFlags
= DecoderFlags::IMAGE_IS_TRANSIENT
;
388 decoder
->SetDecoderFlags(aDecoderFlags
| decoderFlags
);
389 decoder
->SetSurfaceFlags(aSurfaceFlags
);
391 // Set an output size for downscale-during-decode if requested.
393 decoder
->SetOutputSize(OrientedIntSize::FromUnknownSize(*aOutputSize
));
396 if (NS_FAILED(decoder
->Init())) {
400 return decoder
.forget();
404 already_AddRefed
<Decoder
> DecoderFactory::CreateAnonymousMetadataDecoder(
405 DecoderType aType
, NotNull
<SourceBuffer
*> aSourceBuffer
) {
406 if (aType
== DecoderType::UNKNOWN
) {
410 RefPtr
<Decoder
> decoder
=
411 GetDecoder(aType
, /* aImage = */ nullptr, /* aIsRedecode = */ false);
412 MOZ_ASSERT(decoder
, "Should have a decoder now");
414 // Initialize the decoder.
415 decoder
->SetMetadataDecode(true);
416 decoder
->SetIterator(aSourceBuffer
->Iterator());
417 decoder
->SetDecoderFlags(DecoderFlags::FIRST_FRAME_ONLY
);
419 if (NS_FAILED(decoder
->Init())) {
423 return decoder
.forget();
427 } // namespace mozilla