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"
29 /* static */ DecoderType
30 DecoderFactory::GetDecoderType(const char* aMimeType
)
32 // By default we don't know.
33 DecoderType type
= DecoderType::UNKNOWN
;
36 if (!strcmp(aMimeType
, IMAGE_PNG
)) {
37 type
= DecoderType::PNG
;
38 } else if (!strcmp(aMimeType
, IMAGE_X_PNG
)) {
39 type
= DecoderType::PNG
;
40 } else if (!strcmp(aMimeType
, IMAGE_APNG
)) {
41 type
= DecoderType::PNG
;
44 } else if (!strcmp(aMimeType
, IMAGE_GIF
)) {
45 type
= DecoderType::GIF
;
48 } else if (!strcmp(aMimeType
, IMAGE_JPEG
)) {
49 type
= DecoderType::JPEG
;
50 } else if (!strcmp(aMimeType
, IMAGE_PJPEG
)) {
51 type
= DecoderType::JPEG
;
52 } else if (!strcmp(aMimeType
, IMAGE_JPG
)) {
53 type
= DecoderType::JPEG
;
56 } else if (!strcmp(aMimeType
, IMAGE_BMP
)) {
57 type
= DecoderType::BMP
;
58 } else if (!strcmp(aMimeType
, IMAGE_BMP_MS
)) {
59 type
= DecoderType::BMP
;
62 } else if (!strcmp(aMimeType
, IMAGE_ICO
)) {
63 type
= DecoderType::ICO
;
64 } else if (!strcmp(aMimeType
, IMAGE_ICO_MS
)) {
65 type
= DecoderType::ICO
;
68 } else if (!strcmp(aMimeType
, IMAGE_ICON_MS
)) {
69 type
= DecoderType::ICON
;
75 /* static */ already_AddRefed
<Decoder
>
76 DecoderFactory::GetDecoder(DecoderType aType
,
80 RefPtr
<Decoder
> decoder
;
83 case DecoderType::PNG
:
84 decoder
= new nsPNGDecoder(aImage
);
86 case DecoderType::GIF
:
87 decoder
= new nsGIFDecoder2(aImage
);
89 case DecoderType::JPEG
:
90 // If we have all the data we don't want to waste cpu time doing
91 // a progressive decode.
92 decoder
= new nsJPEGDecoder(aImage
,
93 aIsRedecode
? Decoder::SEQUENTIAL
94 : Decoder::PROGRESSIVE
);
96 case DecoderType::BMP
:
97 decoder
= new nsBMPDecoder(aImage
);
99 case DecoderType::ICO
:
100 decoder
= new nsICODecoder(aImage
);
102 case DecoderType::ICON
:
103 decoder
= new nsIconDecoder(aImage
);
106 MOZ_ASSERT_UNREACHABLE("Unknown decoder type");
109 return decoder
.forget();
112 /* static */ nsresult
113 DecoderFactory::CreateDecoder(DecoderType aType
,
114 NotNull
<RasterImage
*> aImage
,
115 NotNull
<SourceBuffer
*> aSourceBuffer
,
116 const IntSize
& aIntrinsicSize
,
117 const IntSize
& aOutputSize
,
118 DecoderFlags aDecoderFlags
,
119 SurfaceFlags aSurfaceFlags
,
120 IDecodingTask
** aOutTask
)
122 if (aType
== DecoderType::UNKNOWN
) {
123 return NS_ERROR_INVALID_ARG
;
126 // Create an anonymous decoder. Interaction with the SurfaceCache and the
127 // owning RasterImage will be mediated by DecodedSurfaceProvider.
128 RefPtr
<Decoder
> decoder
=
129 GetDecoder(aType
, nullptr, bool(aDecoderFlags
& DecoderFlags::IS_REDECODE
));
130 MOZ_ASSERT(decoder
, "Should have a decoder now");
132 // Initialize the decoder.
133 decoder
->SetMetadataDecode(false);
134 decoder
->SetIterator(aSourceBuffer
->Iterator());
135 decoder
->SetOutputSize(aOutputSize
);
136 decoder
->SetDecoderFlags(aDecoderFlags
| DecoderFlags::FIRST_FRAME_ONLY
);
137 decoder
->SetSurfaceFlags(aSurfaceFlags
);
139 nsresult rv
= decoder
->Init();
141 return NS_ERROR_FAILURE
;
144 // Create a DecodedSurfaceProvider which will manage the decoding process and
145 // make this decoder's output available in the surface cache.
146 SurfaceKey surfaceKey
=
147 RasterSurfaceKey(aOutputSize
, aSurfaceFlags
, PlaybackType::eStatic
);
148 auto provider
= MakeNotNull
<RefPtr
<DecodedSurfaceProvider
>>(
149 aImage
, surfaceKey
, WrapNotNull(decoder
));
150 if (aDecoderFlags
& DecoderFlags::CANNOT_SUBSTITUTE
) {
151 provider
->Availability().SetCannotSubstitute();
154 // Attempt to insert the surface provider into the surface cache right away so
155 // we won't trigger any more decoders with the same parameters.
156 switch (SurfaceCache::Insert(provider
)) {
157 case InsertOutcome::SUCCESS
:
159 case InsertOutcome::FAILURE_ALREADY_PRESENT
:
160 return NS_ERROR_ALREADY_INITIALIZED
;
162 return NS_ERROR_FAILURE
;
165 // Return the surface provider in its IDecodingTask guise.
166 RefPtr
<IDecodingTask
> task
= provider
.get();
167 task
.forget(aOutTask
);
171 /* static */ nsresult
172 DecoderFactory::CreateAnimationDecoder(DecoderType aType
,
173 NotNull
<RasterImage
*> aImage
,
174 NotNull
<SourceBuffer
*> aSourceBuffer
,
175 const IntSize
& aIntrinsicSize
,
176 DecoderFlags aDecoderFlags
,
177 SurfaceFlags aSurfaceFlags
,
178 size_t aCurrentFrame
,
179 IDecodingTask
** aOutTask
)
181 if (aType
== DecoderType::UNKNOWN
) {
182 return NS_ERROR_INVALID_ARG
;
185 MOZ_ASSERT(aType
== DecoderType::GIF
|| aType
== DecoderType::PNG
,
186 "Calling CreateAnimationDecoder for non-animating DecoderType");
188 // Create an anonymous decoder. Interaction with the SurfaceCache and the
189 // owning RasterImage will be mediated by AnimationSurfaceProvider.
190 RefPtr
<Decoder
> decoder
= GetDecoder(aType
, nullptr, /* aIsRedecode = */ true);
191 MOZ_ASSERT(decoder
, "Should have a decoder now");
193 // Initialize the decoder.
194 decoder
->SetMetadataDecode(false);
195 decoder
->SetIterator(aSourceBuffer
->Iterator());
196 decoder
->SetDecoderFlags(aDecoderFlags
| DecoderFlags::IS_REDECODE
);
197 decoder
->SetSurfaceFlags(aSurfaceFlags
);
199 nsresult rv
= decoder
->Init();
201 return NS_ERROR_FAILURE
;
204 // Create an AnimationSurfaceProvider which will manage the decoding process
205 // and make this decoder's output available in the surface cache.
206 SurfaceKey surfaceKey
=
207 RasterSurfaceKey(aIntrinsicSize
, aSurfaceFlags
, PlaybackType::eAnimated
);
208 auto provider
= MakeNotNull
<RefPtr
<AnimationSurfaceProvider
>>(
209 aImage
, surfaceKey
, WrapNotNull(decoder
), aCurrentFrame
);
211 // Attempt to insert the surface provider into the surface cache right away so
212 // we won't trigger any more decoders with the same parameters.
213 switch (SurfaceCache::Insert(provider
)) {
214 case InsertOutcome::SUCCESS
:
216 case InsertOutcome::FAILURE_ALREADY_PRESENT
:
217 return NS_ERROR_ALREADY_INITIALIZED
;
219 return NS_ERROR_FAILURE
;
222 // Return the surface provider in its IDecodingTask guise.
223 RefPtr
<IDecodingTask
> task
= provider
.get();
224 task
.forget(aOutTask
);
228 /* static */ already_AddRefed
<Decoder
>
229 DecoderFactory::CloneAnimationDecoder(Decoder
* aDecoder
)
231 MOZ_ASSERT(aDecoder
);
233 // In an ideal world, we would assert aDecoder->HasAnimation() but we cannot.
234 // The decoder may not have detected it is animated yet (e.g. it did not even
235 // get scheduled yet, or it has only decoded the first frame and has yet to
236 // rediscover it is animated).
237 DecoderType type
= aDecoder
->GetType();
238 MOZ_ASSERT(type
== DecoderType::GIF
|| type
== DecoderType::PNG
,
239 "Calling CloneAnimationDecoder for non-animating DecoderType");
241 RefPtr
<Decoder
> decoder
= GetDecoder(type
, nullptr, /* aIsRedecode = */ true);
242 MOZ_ASSERT(decoder
, "Should have a decoder now");
244 // Initialize the decoder.
245 decoder
->SetMetadataDecode(false);
246 decoder
->SetIterator(aDecoder
->GetSourceBuffer()->Iterator());
247 decoder
->SetDecoderFlags(aDecoder
->GetDecoderFlags());
248 decoder
->SetSurfaceFlags(aDecoder
->GetSurfaceFlags());
250 if (NS_FAILED(decoder
->Init())) {
254 return decoder
.forget();
257 /* static */ already_AddRefed
<IDecodingTask
>
258 DecoderFactory::CreateMetadataDecoder(DecoderType aType
,
259 NotNull
<RasterImage
*> aImage
,
260 NotNull
<SourceBuffer
*> aSourceBuffer
)
262 if (aType
== DecoderType::UNKNOWN
) {
266 RefPtr
<Decoder
> decoder
=
267 GetDecoder(aType
, aImage
, /* aIsRedecode = */ false);
268 MOZ_ASSERT(decoder
, "Should have a decoder now");
270 // Initialize the decoder.
271 decoder
->SetMetadataDecode(true);
272 decoder
->SetIterator(aSourceBuffer
->Iterator());
274 if (NS_FAILED(decoder
->Init())) {
278 RefPtr
<IDecodingTask
> task
= new MetadataDecodingTask(WrapNotNull(decoder
));
279 return task
.forget();
282 /* static */ already_AddRefed
<Decoder
>
283 DecoderFactory::CreateDecoderForICOResource(DecoderType aType
,
284 SourceBufferIterator
&& aIterator
,
285 NotNull
<nsICODecoder
*> aICODecoder
,
286 bool aIsMetadataDecode
,
287 const Maybe
<IntSize
>& aExpectedSize
,
288 const Maybe
<uint32_t>& aDataOffset
291 // Create the decoder.
292 RefPtr
<Decoder
> decoder
;
294 case DecoderType::BMP
:
295 MOZ_ASSERT(aDataOffset
);
296 decoder
= new nsBMPDecoder(aICODecoder
->GetImageMaybeNull(), *aDataOffset
);
299 case DecoderType::PNG
:
300 MOZ_ASSERT(!aDataOffset
);
301 decoder
= new nsPNGDecoder(aICODecoder
->GetImageMaybeNull());
305 MOZ_ASSERT_UNREACHABLE("Invalid ICO resource decoder type");
311 // Initialize the decoder, copying settings from @aICODecoder.
312 decoder
->SetMetadataDecode(aIsMetadataDecode
);
313 decoder
->SetIterator(Forward
<SourceBufferIterator
>(aIterator
));
314 if (!aIsMetadataDecode
) {
315 decoder
->SetOutputSize(aICODecoder
->OutputSize());
318 decoder
->SetExpectedSize(*aExpectedSize
);
320 decoder
->SetDecoderFlags(aICODecoder
->GetDecoderFlags());
321 decoder
->SetSurfaceFlags(aICODecoder
->GetSurfaceFlags());
322 decoder
->SetFinalizeFrames(false);
324 if (NS_FAILED(decoder
->Init())) {
328 return decoder
.forget();
331 /* static */ already_AddRefed
<Decoder
>
332 DecoderFactory::CreateAnonymousDecoder(DecoderType aType
,
333 NotNull
<SourceBuffer
*> aSourceBuffer
,
334 const Maybe
<IntSize
>& aOutputSize
,
335 SurfaceFlags aSurfaceFlags
)
337 if (aType
== DecoderType::UNKNOWN
) {
341 RefPtr
<Decoder
> decoder
=
342 GetDecoder(aType
, /* aImage = */ nullptr, /* aIsRedecode = */ false);
343 MOZ_ASSERT(decoder
, "Should have a decoder now");
345 // Initialize the decoder.
346 decoder
->SetMetadataDecode(false);
347 decoder
->SetIterator(aSourceBuffer
->Iterator());
349 // Anonymous decoders are always transient; we don't want to optimize surfaces
350 // or do any other expensive work that might be wasted.
351 DecoderFlags decoderFlags
= DecoderFlags::IMAGE_IS_TRANSIENT
;
353 // Without an image, the decoder can't store anything in the SurfaceCache, so
354 // callers will only be able to retrieve the most recent frame via
355 // Decoder::GetCurrentFrame(). That means that anonymous decoders should
356 // always be first-frame-only decoders, because nobody ever wants the *last*
358 decoderFlags
|= DecoderFlags::FIRST_FRAME_ONLY
;
360 decoder
->SetDecoderFlags(decoderFlags
);
361 decoder
->SetSurfaceFlags(aSurfaceFlags
);
363 // Set an output size for downscale-during-decode if requested.
365 decoder
->SetOutputSize(*aOutputSize
);
368 if (NS_FAILED(decoder
->Init())) {
372 return decoder
.forget();
375 /* static */ already_AddRefed
<Decoder
>
376 DecoderFactory::CreateAnonymousMetadataDecoder(DecoderType aType
,
377 NotNull
<SourceBuffer
*> aSourceBuffer
)
379 if (aType
== DecoderType::UNKNOWN
) {
383 RefPtr
<Decoder
> decoder
=
384 GetDecoder(aType
, /* aImage = */ nullptr, /* aIsRedecode = */ false);
385 MOZ_ASSERT(decoder
, "Should have a decoder now");
387 // Initialize the decoder.
388 decoder
->SetMetadataDecode(true);
389 decoder
->SetIterator(aSourceBuffer
->Iterator());
390 decoder
->SetDecoderFlags(DecoderFlags::FIRST_FRAME_ONLY
);
392 if (NS_FAILED(decoder
->Init())) {
396 return decoder
.forget();
400 } // namespace mozilla