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"
9 #include "nsMimeTypes.h"
10 #include "mozilla/RefPtr.h"
12 #include "AnimationSurfaceProvider.h"
14 #include "DecodedSurfaceProvider.h"
15 #include "IDecodingTask.h"
17 #include "nsPNGDecoder.h"
18 #include "nsGIFDecoder2.h"
19 #include "nsJPEGDecoder.h"
20 #include "nsBMPDecoder.h"
21 #include "nsICODecoder.h"
22 #include "nsIconDecoder.h"
23 #include "nsWebPDecoder.h"
32 DecoderType
DecoderFactory::GetDecoderType(const char* aMimeType
) {
33 // By default we don't know.
34 DecoderType type
= DecoderType::UNKNOWN
;
37 if (!strcmp(aMimeType
, IMAGE_PNG
)) {
38 type
= DecoderType::PNG
;
39 } else if (!strcmp(aMimeType
, IMAGE_X_PNG
)) {
40 type
= DecoderType::PNG
;
41 } else if (!strcmp(aMimeType
, IMAGE_APNG
)) {
42 type
= DecoderType::PNG
;
45 } else if (!strcmp(aMimeType
, IMAGE_GIF
)) {
46 type
= DecoderType::GIF
;
49 } else if (!strcmp(aMimeType
, IMAGE_JPEG
)) {
50 type
= DecoderType::JPEG
;
51 } else if (!strcmp(aMimeType
, IMAGE_PJPEG
)) {
52 type
= DecoderType::JPEG
;
53 } else if (!strcmp(aMimeType
, IMAGE_JPG
)) {
54 type
= DecoderType::JPEG
;
57 } else if (!strcmp(aMimeType
, IMAGE_BMP
)) {
58 type
= DecoderType::BMP
;
59 } else if (!strcmp(aMimeType
, IMAGE_BMP_MS
)) {
60 type
= DecoderType::BMP
;
63 } else if (!strcmp(aMimeType
, IMAGE_BMP_MS_CLIPBOARD
)) {
64 type
= DecoderType::BMP_CLIPBOARD
;
67 } else if (!strcmp(aMimeType
, IMAGE_ICO
)) {
68 type
= DecoderType::ICO
;
69 } else if (!strcmp(aMimeType
, IMAGE_ICO_MS
)) {
70 type
= DecoderType::ICO
;
73 } else if (!strcmp(aMimeType
, IMAGE_ICON_MS
)) {
74 type
= DecoderType::ICON
;
77 } else if (!strcmp(aMimeType
, IMAGE_WEBP
) && gfxPrefs::ImageWebPEnabled()) {
78 type
= DecoderType::WEBP
;
85 already_AddRefed
<Decoder
> DecoderFactory::GetDecoder(DecoderType aType
,
88 RefPtr
<Decoder
> decoder
;
91 case DecoderType::PNG
:
92 decoder
= new nsPNGDecoder(aImage
);
94 case DecoderType::GIF
:
95 decoder
= new nsGIFDecoder2(aImage
);
97 case DecoderType::JPEG
:
98 // If we have all the data we don't want to waste cpu time doing
99 // a progressive decode.
100 decoder
= new nsJPEGDecoder(
101 aImage
, aIsRedecode
? Decoder::SEQUENTIAL
: Decoder::PROGRESSIVE
);
103 case DecoderType::BMP
:
104 decoder
= new nsBMPDecoder(aImage
);
106 case DecoderType::BMP_CLIPBOARD
:
107 decoder
= new nsBMPDecoder(aImage
, /* aForClipboard */ true);
109 case DecoderType::ICO
:
110 decoder
= new nsICODecoder(aImage
);
112 case DecoderType::ICON
:
113 decoder
= new nsIconDecoder(aImage
);
115 case DecoderType::WEBP
:
116 decoder
= new nsWebPDecoder(aImage
);
119 MOZ_ASSERT_UNREACHABLE("Unknown decoder type");
122 return decoder
.forget();
126 nsresult
DecoderFactory::CreateDecoder(
127 DecoderType aType
, NotNull
<RasterImage
*> aImage
,
128 NotNull
<SourceBuffer
*> aSourceBuffer
, const IntSize
& aIntrinsicSize
,
129 const IntSize
& aOutputSize
, DecoderFlags aDecoderFlags
,
130 SurfaceFlags aSurfaceFlags
, IDecodingTask
** aOutTask
) {
131 if (aType
== DecoderType::UNKNOWN
) {
132 return NS_ERROR_INVALID_ARG
;
135 // Create an anonymous decoder. Interaction with the SurfaceCache and the
136 // owning RasterImage will be mediated by DecodedSurfaceProvider.
137 RefPtr
<Decoder
> decoder
= GetDecoder(
138 aType
, nullptr, bool(aDecoderFlags
& DecoderFlags::IS_REDECODE
));
139 MOZ_ASSERT(decoder
, "Should have a decoder now");
141 // Initialize the decoder.
142 decoder
->SetMetadataDecode(false);
143 decoder
->SetIterator(aSourceBuffer
->Iterator());
144 decoder
->SetOutputSize(aOutputSize
);
145 decoder
->SetDecoderFlags(aDecoderFlags
| DecoderFlags::FIRST_FRAME_ONLY
);
146 decoder
->SetSurfaceFlags(aSurfaceFlags
);
148 nsresult rv
= decoder
->Init();
150 return NS_ERROR_FAILURE
;
153 // Create a DecodedSurfaceProvider which will manage the decoding process and
154 // make this decoder's output available in the surface cache.
155 SurfaceKey surfaceKey
=
156 RasterSurfaceKey(aOutputSize
, aSurfaceFlags
, PlaybackType::eStatic
);
157 auto provider
= MakeNotNull
<RefPtr
<DecodedSurfaceProvider
>>(
158 aImage
, surfaceKey
, WrapNotNull(decoder
));
159 if (aDecoderFlags
& DecoderFlags::CANNOT_SUBSTITUTE
) {
160 provider
->Availability().SetCannotSubstitute();
163 // Attempt to insert the surface provider into the surface cache right away so
164 // we won't trigger any more decoders with the same parameters.
165 switch (SurfaceCache::Insert(provider
)) {
166 case InsertOutcome::SUCCESS
:
168 case InsertOutcome::FAILURE_ALREADY_PRESENT
:
169 return NS_ERROR_ALREADY_INITIALIZED
;
171 return NS_ERROR_FAILURE
;
174 // Return the surface provider in its IDecodingTask guise.
175 RefPtr
<IDecodingTask
> task
= provider
.get();
176 task
.forget(aOutTask
);
181 nsresult
DecoderFactory::CreateAnimationDecoder(
182 DecoderType aType
, NotNull
<RasterImage
*> aImage
,
183 NotNull
<SourceBuffer
*> aSourceBuffer
, const IntSize
& aIntrinsicSize
,
184 DecoderFlags aDecoderFlags
, SurfaceFlags aSurfaceFlags
,
185 size_t aCurrentFrame
, IDecodingTask
** aOutTask
) {
186 if (aType
== DecoderType::UNKNOWN
) {
187 return NS_ERROR_INVALID_ARG
;
190 MOZ_ASSERT(aType
== DecoderType::GIF
|| aType
== DecoderType::PNG
||
191 aType
== DecoderType::WEBP
,
192 "Calling CreateAnimationDecoder for non-animating DecoderType");
194 // Create an anonymous decoder. Interaction with the SurfaceCache and the
195 // owning RasterImage will be mediated by AnimationSurfaceProvider.
196 RefPtr
<Decoder
> decoder
=
197 GetDecoder(aType
, nullptr, /* aIsRedecode = */ true);
198 MOZ_ASSERT(decoder
, "Should have a decoder now");
200 // Initialize the decoder.
201 decoder
->SetMetadataDecode(false);
202 decoder
->SetIterator(aSourceBuffer
->Iterator());
203 decoder
->SetDecoderFlags(aDecoderFlags
| DecoderFlags::IS_REDECODE
);
204 decoder
->SetSurfaceFlags(aSurfaceFlags
);
206 nsresult rv
= decoder
->Init();
208 return NS_ERROR_FAILURE
;
211 // Create an AnimationSurfaceProvider which will manage the decoding process
212 // and make this decoder's output available in the surface cache.
213 SurfaceKey surfaceKey
=
214 RasterSurfaceKey(aIntrinsicSize
, aSurfaceFlags
, PlaybackType::eAnimated
);
215 auto provider
= MakeNotNull
<RefPtr
<AnimationSurfaceProvider
>>(
216 aImage
, surfaceKey
, WrapNotNull(decoder
), aCurrentFrame
);
218 // Attempt to insert the surface provider into the surface cache right away so
219 // we won't trigger any more decoders with the same parameters.
220 switch (SurfaceCache::Insert(provider
)) {
221 case InsertOutcome::SUCCESS
:
223 case InsertOutcome::FAILURE_ALREADY_PRESENT
:
224 return NS_ERROR_ALREADY_INITIALIZED
;
226 return NS_ERROR_FAILURE
;
229 // Return the surface provider in its IDecodingTask guise.
230 RefPtr
<IDecodingTask
> task
= provider
.get();
231 task
.forget(aOutTask
);
236 already_AddRefed
<Decoder
> DecoderFactory::CloneAnimationDecoder(
238 MOZ_ASSERT(aDecoder
);
240 // In an ideal world, we would assert aDecoder->HasAnimation() but we cannot.
241 // The decoder may not have detected it is animated yet (e.g. it did not even
242 // get scheduled yet, or it has only decoded the first frame and has yet to
243 // rediscover it is animated).
244 DecoderType type
= aDecoder
->GetType();
245 MOZ_ASSERT(type
== DecoderType::GIF
|| type
== DecoderType::PNG
||
246 type
== DecoderType::WEBP
,
247 "Calling CloneAnimationDecoder for non-animating DecoderType");
249 RefPtr
<Decoder
> decoder
= GetDecoder(type
, nullptr, /* aIsRedecode = */ true);
250 MOZ_ASSERT(decoder
, "Should have a decoder now");
252 // Initialize the decoder.
253 decoder
->SetMetadataDecode(false);
254 decoder
->SetIterator(aDecoder
->GetSourceBuffer()->Iterator());
255 decoder
->SetDecoderFlags(aDecoder
->GetDecoderFlags());
256 decoder
->SetSurfaceFlags(aDecoder
->GetSurfaceFlags());
257 decoder
->SetFrameRecycler(aDecoder
->GetFrameRecycler());
259 if (NS_FAILED(decoder
->Init())) {
263 return decoder
.forget();
267 already_AddRefed
<IDecodingTask
> DecoderFactory::CreateMetadataDecoder(
268 DecoderType aType
, NotNull
<RasterImage
*> aImage
,
269 NotNull
<SourceBuffer
*> aSourceBuffer
) {
270 if (aType
== DecoderType::UNKNOWN
) {
274 RefPtr
<Decoder
> decoder
=
275 GetDecoder(aType
, aImage
, /* aIsRedecode = */ false);
276 MOZ_ASSERT(decoder
, "Should have a decoder now");
278 // Initialize the decoder.
279 decoder
->SetMetadataDecode(true);
280 decoder
->SetIterator(aSourceBuffer
->Iterator());
282 if (NS_FAILED(decoder
->Init())) {
286 RefPtr
<IDecodingTask
> task
= new MetadataDecodingTask(WrapNotNull(decoder
));
287 return task
.forget();
291 already_AddRefed
<Decoder
> DecoderFactory::CreateDecoderForICOResource(
292 DecoderType aType
, SourceBufferIterator
&& aIterator
,
293 NotNull
<nsICODecoder
*> aICODecoder
, bool aIsMetadataDecode
,
294 const Maybe
<IntSize
>& aExpectedSize
, const Maybe
<uint32_t>& aDataOffset
296 // Create the decoder.
297 RefPtr
<Decoder
> decoder
;
299 case DecoderType::BMP
:
300 MOZ_ASSERT(aDataOffset
);
302 new nsBMPDecoder(aICODecoder
->GetImageMaybeNull(), *aDataOffset
);
305 case DecoderType::PNG
:
306 MOZ_ASSERT(!aDataOffset
);
307 decoder
= new nsPNGDecoder(aICODecoder
->GetImageMaybeNull());
311 MOZ_ASSERT_UNREACHABLE("Invalid ICO resource decoder type");
317 // Initialize the decoder, copying settings from @aICODecoder.
318 decoder
->SetMetadataDecode(aIsMetadataDecode
);
319 decoder
->SetIterator(std::forward
<SourceBufferIterator
>(aIterator
));
320 if (!aIsMetadataDecode
) {
321 decoder
->SetOutputSize(aICODecoder
->OutputSize());
324 decoder
->SetExpectedSize(*aExpectedSize
);
326 decoder
->SetDecoderFlags(aICODecoder
->GetDecoderFlags());
327 decoder
->SetSurfaceFlags(aICODecoder
->GetSurfaceFlags());
328 decoder
->SetFinalizeFrames(false);
330 if (NS_FAILED(decoder
->Init())) {
334 return decoder
.forget();
338 already_AddRefed
<Decoder
> DecoderFactory::CreateAnonymousDecoder(
339 DecoderType aType
, NotNull
<SourceBuffer
*> aSourceBuffer
,
340 const Maybe
<IntSize
>& aOutputSize
, DecoderFlags aDecoderFlags
,
341 SurfaceFlags aSurfaceFlags
) {
342 if (aType
== DecoderType::UNKNOWN
) {
346 RefPtr
<Decoder
> decoder
=
347 GetDecoder(aType
, /* aImage = */ nullptr, /* aIsRedecode = */ false);
348 MOZ_ASSERT(decoder
, "Should have a decoder now");
350 // Initialize the decoder.
351 decoder
->SetMetadataDecode(false);
352 decoder
->SetIterator(aSourceBuffer
->Iterator());
354 // Anonymous decoders are always transient; we don't want to optimize surfaces
355 // or do any other expensive work that might be wasted.
356 DecoderFlags decoderFlags
= DecoderFlags::IMAGE_IS_TRANSIENT
;
358 decoder
->SetDecoderFlags(aDecoderFlags
| decoderFlags
);
359 decoder
->SetSurfaceFlags(aSurfaceFlags
);
361 // Set an output size for downscale-during-decode if requested.
363 decoder
->SetOutputSize(*aOutputSize
);
366 if (NS_FAILED(decoder
->Init())) {
370 return decoder
.forget();
374 already_AddRefed
<Decoder
> DecoderFactory::CreateAnonymousMetadataDecoder(
375 DecoderType aType
, NotNull
<SourceBuffer
*> aSourceBuffer
) {
376 if (aType
== DecoderType::UNKNOWN
) {
380 RefPtr
<Decoder
> decoder
=
381 GetDecoder(aType
, /* aImage = */ nullptr, /* aIsRedecode = */ false);
382 MOZ_ASSERT(decoder
, "Should have a decoder now");
384 // Initialize the decoder.
385 decoder
->SetMetadataDecode(true);
386 decoder
->SetIterator(aSourceBuffer
->Iterator());
387 decoder
->SetDecoderFlags(DecoderFlags::FIRST_FRAME_ONLY
);
389 if (NS_FAILED(decoder
->Init())) {
393 return decoder
.forget();
397 } // namespace mozilla