Bug 1454184 [wpt PR 10474] - [Resource Timing] Align TAO parsing to spec, a=testonly
[gecko.git] / image / DecoderFactory.cpp
blobfeaa19189f95e0c6f45305684026fc7e54559850
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"
23 namespace mozilla {
25 using namespace gfx;
27 namespace image {
29 /* static */ DecoderType
30 DecoderFactory::GetDecoderType(const char* aMimeType)
32 // By default we don't know.
33 DecoderType type = DecoderType::UNKNOWN;
35 // PNG
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;
43 // GIF
44 } else if (!strcmp(aMimeType, IMAGE_GIF)) {
45 type = DecoderType::GIF;
47 // JPEG
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;
55 // BMP
56 } else if (!strcmp(aMimeType, IMAGE_BMP)) {
57 type = DecoderType::BMP;
58 } else if (!strcmp(aMimeType, IMAGE_BMP_MS)) {
59 type = DecoderType::BMP;
61 // ICO
62 } else if (!strcmp(aMimeType, IMAGE_ICO)) {
63 type = DecoderType::ICO;
64 } else if (!strcmp(aMimeType, IMAGE_ICO_MS)) {
65 type = DecoderType::ICO;
67 // Icon
68 } else if (!strcmp(aMimeType, IMAGE_ICON_MS)) {
69 type = DecoderType::ICON;
72 return type;
75 /* static */ already_AddRefed<Decoder>
76 DecoderFactory::GetDecoder(DecoderType aType,
77 RasterImage* aImage,
78 bool aIsRedecode)
80 RefPtr<Decoder> decoder;
82 switch (aType) {
83 case DecoderType::PNG:
84 decoder = new nsPNGDecoder(aImage);
85 break;
86 case DecoderType::GIF:
87 decoder = new nsGIFDecoder2(aImage);
88 break;
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);
95 break;
96 case DecoderType::BMP:
97 decoder = new nsBMPDecoder(aImage);
98 break;
99 case DecoderType::ICO:
100 decoder = new nsICODecoder(aImage);
101 break;
102 case DecoderType::ICON:
103 decoder = new nsIconDecoder(aImage);
104 break;
105 default:
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();
140 if (NS_FAILED(rv)) {
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:
158 break;
159 case InsertOutcome::FAILURE_ALREADY_PRESENT:
160 return NS_ERROR_ALREADY_INITIALIZED;
161 default:
162 return NS_ERROR_FAILURE;
165 // Return the surface provider in its IDecodingTask guise.
166 RefPtr<IDecodingTask> task = provider.get();
167 task.forget(aOutTask);
168 return NS_OK;
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();
200 if (NS_FAILED(rv)) {
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:
215 break;
216 case InsertOutcome::FAILURE_ALREADY_PRESENT:
217 return NS_ERROR_ALREADY_INITIALIZED;
218 default:
219 return NS_ERROR_FAILURE;
222 // Return the surface provider in its IDecodingTask guise.
223 RefPtr<IDecodingTask> task = provider.get();
224 task.forget(aOutTask);
225 return NS_OK;
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())) {
251 return nullptr;
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) {
263 return nullptr;
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())) {
275 return nullptr;
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
289 /* = Nothing() */)
291 // Create the decoder.
292 RefPtr<Decoder> decoder;
293 switch (aType) {
294 case DecoderType::BMP:
295 MOZ_ASSERT(aDataOffset);
296 decoder = new nsBMPDecoder(aICODecoder->GetImageMaybeNull(), *aDataOffset);
297 break;
299 case DecoderType::PNG:
300 MOZ_ASSERT(!aDataOffset);
301 decoder = new nsPNGDecoder(aICODecoder->GetImageMaybeNull());
302 break;
304 default:
305 MOZ_ASSERT_UNREACHABLE("Invalid ICO resource decoder type");
306 return nullptr;
309 MOZ_ASSERT(decoder);
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());
317 if (aExpectedSize) {
318 decoder->SetExpectedSize(*aExpectedSize);
320 decoder->SetDecoderFlags(aICODecoder->GetDecoderFlags());
321 decoder->SetSurfaceFlags(aICODecoder->GetSurfaceFlags());
322 decoder->SetFinalizeFrames(false);
324 if (NS_FAILED(decoder->Init())) {
325 return nullptr;
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) {
338 return nullptr;
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*
357 // frame.
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.
364 if (aOutputSize) {
365 decoder->SetOutputSize(*aOutputSize);
368 if (NS_FAILED(decoder->Init())) {
369 return nullptr;
372 return decoder.forget();
375 /* static */ already_AddRefed<Decoder>
376 DecoderFactory::CreateAnonymousMetadataDecoder(DecoderType aType,
377 NotNull<SourceBuffer*> aSourceBuffer)
379 if (aType == DecoderType::UNKNOWN) {
380 return nullptr;
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())) {
393 return nullptr;
396 return decoder.forget();
399 } // namespace image
400 } // namespace mozilla