Backed out 3 changesets (bug 1901078, bug 1749048) for causing interface related...
[gecko.git] / image / DecoderFactory.cpp
blob55e0c5584762e19a3c627bf869dd4361a80188cb
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"
22 #include "nsWebPDecoder.h"
23 #ifdef MOZ_AV1
24 # include "nsAVIFDecoder.h"
25 #endif
26 #ifdef MOZ_JXL
27 # include "nsJXLDecoder.h"
28 #endif
30 namespace mozilla {
32 using namespace gfx;
34 namespace image {
36 /* static */
37 DecoderType DecoderFactory::GetDecoderType(const char* aMimeType) {
38 // By default we don't know.
39 DecoderType type = DecoderType::UNKNOWN;
41 // PNG
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;
49 // GIF
50 } else if (!strcmp(aMimeType, IMAGE_GIF)) {
51 type = DecoderType::GIF;
53 // JPEG
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;
61 // BMP
62 } else if (!strcmp(aMimeType, IMAGE_BMP)) {
63 type = DecoderType::BMP;
64 } else if (!strcmp(aMimeType, IMAGE_BMP_MS)) {
65 type = DecoderType::BMP;
67 // BMP_CLIPBOARD
68 } else if (!strcmp(aMimeType, IMAGE_BMP_MS_CLIPBOARD)) {
69 type = DecoderType::BMP_CLIPBOARD;
71 // ICO
72 } else if (!strcmp(aMimeType, IMAGE_ICO)) {
73 type = DecoderType::ICO;
74 } else if (!strcmp(aMimeType, IMAGE_ICO_MS)) {
75 type = DecoderType::ICO;
77 // Icon
78 } else if (!strcmp(aMimeType, IMAGE_ICON_MS)) {
79 type = DecoderType::ICON;
81 // WebP
82 } else if (!strcmp(aMimeType, IMAGE_WEBP)) {
83 type = DecoderType::WEBP;
85 // AVIF
87 #ifdef MOZ_AV1
88 else if (!strcmp(aMimeType, IMAGE_AVIF) &&
89 StaticPrefs::image_avif_enabled()) {
90 type = DecoderType::AVIF;
92 #endif
93 #ifdef MOZ_JXL
94 else if (!strcmp(aMimeType, IMAGE_JXL) && StaticPrefs::image_jxl_enabled()) {
95 type = DecoderType::JXL;
97 #endif
99 return type;
102 /* static */
103 DecoderFlags DecoderFactory::GetDefaultDecoderFlagsForType(DecoderType aType) {
104 auto flags = DefaultDecoderFlags();
106 #ifdef MOZ_AV1
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;
115 #endif
117 return flags;
120 /* static */
121 already_AddRefed<Decoder> DecoderFactory::GetDecoder(DecoderType aType,
122 RasterImage* aImage,
123 bool aIsRedecode) {
124 RefPtr<Decoder> decoder;
126 switch (aType) {
127 case DecoderType::PNG:
128 decoder = new nsPNGDecoder(aImage);
129 break;
130 case DecoderType::GIF:
131 decoder = new nsGIFDecoder2(aImage);
132 break;
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);
138 break;
139 case DecoderType::BMP:
140 decoder = new nsBMPDecoder(aImage);
141 break;
142 case DecoderType::BMP_CLIPBOARD:
143 decoder = new nsBMPDecoder(aImage, /* aForClipboard */ true);
144 break;
145 case DecoderType::ICO:
146 decoder = new nsICODecoder(aImage);
147 break;
148 case DecoderType::ICON:
149 decoder = new nsIconDecoder(aImage);
150 break;
151 case DecoderType::WEBP:
152 decoder = new nsWebPDecoder(aImage);
153 break;
154 #ifdef MOZ_AV1
155 case DecoderType::AVIF:
156 decoder = new nsAVIFDecoder(aImage);
157 break;
158 #endif
159 #ifdef MOZ_JXL
160 case DecoderType::JXL:
161 decoder = new nsJXLDecoder(aImage);
162 break;
163 #endif
164 default:
165 MOZ_ASSERT_UNREACHABLE("Unknown decoder type");
168 return decoder.forget();
171 /* static */
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();
200 if (NS_FAILED(rv)) {
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:
218 break;
219 case InsertOutcome::FAILURE_ALREADY_PRESENT:
220 return NS_ERROR_ALREADY_INITIALIZED;
221 default:
222 return NS_ERROR_FAILURE;
225 // Return the surface provider in its IDecodingTask guise.
226 RefPtr<IDecodingTask> task = provider.get();
227 task.forget(aOutTask);
228 return NS_OK;
231 /* static */
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();
263 if (NS_FAILED(rv)) {
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:
278 break;
279 case InsertOutcome::FAILURE_ALREADY_PRESENT:
280 return NS_ERROR_ALREADY_INITIALIZED;
281 default:
282 return NS_ERROR_FAILURE;
285 // Return the surface provider in its IDecodingTask guise.
286 RefPtr<IDecodingTask> task = provider.get();
287 task.forget(aOutTask);
288 return NS_OK;
291 /* static */
292 already_AddRefed<Decoder> DecoderFactory::CloneAnimationDecoder(
293 Decoder* aDecoder) {
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())) {
316 return nullptr;
319 return decoder.forget();
322 /* static */
323 already_AddRefed<IDecodingTask> DecoderFactory::CreateMetadataDecoder(
324 DecoderType aType, NotNull<RasterImage*> aImage, DecoderFlags aFlags,
325 NotNull<SourceBuffer*> aSourceBuffer) {
326 if (aType == DecoderType::UNKNOWN) {
327 return nullptr;
330 RefPtr<Decoder> decoder =
331 GetDecoder(aType, aImage, /* aIsRedecode = */ false);
332 MOZ_ASSERT(decoder, "Should have a decoder now");
334 // Initialize the decoder.
335 decoder->SetMetadataDecode(true);
336 decoder->SetDecoderFlags(aFlags);
337 decoder->SetIterator(aSourceBuffer->Iterator());
339 if (NS_FAILED(decoder->Init())) {
340 return nullptr;
343 RefPtr<IDecodingTask> task = new MetadataDecodingTask(WrapNotNull(decoder));
344 return task.forget();
347 /* static */
348 already_AddRefed<Decoder> DecoderFactory::CreateDecoderForICOResource(
349 DecoderType aType, SourceBufferIterator&& aIterator,
350 NotNull<nsICODecoder*> aICODecoder, bool aIsMetadataDecode,
351 const Maybe<OrientedIntSize>& aExpectedSize,
352 const Maybe<uint32_t>& aDataOffset
353 /* = Nothing() */) {
354 // Create the decoder.
355 RefPtr<Decoder> decoder;
356 switch (aType) {
357 case DecoderType::BMP:
358 MOZ_ASSERT(aDataOffset);
359 decoder =
360 new nsBMPDecoder(aICODecoder->GetImageMaybeNull(), *aDataOffset);
361 break;
363 case DecoderType::PNG:
364 MOZ_ASSERT(!aDataOffset);
365 decoder = new nsPNGDecoder(aICODecoder->GetImageMaybeNull());
366 break;
368 default:
369 MOZ_ASSERT_UNREACHABLE("Invalid ICO resource decoder type");
370 return nullptr;
373 MOZ_ASSERT(decoder);
375 // Initialize the decoder, copying settings from @aICODecoder.
376 decoder->SetMetadataDecode(aIsMetadataDecode);
377 decoder->SetIterator(std::forward<SourceBufferIterator>(aIterator));
378 if (!aIsMetadataDecode) {
379 decoder->SetOutputSize(aICODecoder->OutputSize());
381 if (aExpectedSize) {
382 decoder->SetExpectedSize(*aExpectedSize);
384 decoder->SetDecoderFlags(aICODecoder->GetDecoderFlags());
385 decoder->SetSurfaceFlags(aICODecoder->GetSurfaceFlags());
386 decoder->SetFinalizeFrames(false);
388 if (NS_FAILED(decoder->Init())) {
389 return nullptr;
392 return decoder.forget();
395 /* static */
396 already_AddRefed<Decoder> DecoderFactory::CreateAnonymousDecoder(
397 DecoderType aType, NotNull<SourceBuffer*> aSourceBuffer,
398 const Maybe<IntSize>& aOutputSize, DecoderFlags aDecoderFlags,
399 SurfaceFlags aSurfaceFlags) {
400 if (aType == DecoderType::UNKNOWN) {
401 return nullptr;
404 // Only can use COUNT_FRAMES with metadata decoders.
405 if (NS_WARN_IF(bool(aDecoderFlags & DecoderFlags::COUNT_FRAMES))) {
406 return nullptr;
409 RefPtr<Decoder> decoder =
410 GetDecoder(aType, /* aImage = */ nullptr, /* aIsRedecode = */ false);
411 MOZ_ASSERT(decoder, "Should have a decoder now");
413 // Initialize the decoder.
414 decoder->SetMetadataDecode(false);
415 decoder->SetIterator(aSourceBuffer->Iterator());
417 // Anonymous decoders are always transient; we don't want to optimize surfaces
418 // or do any other expensive work that might be wasted.
419 DecoderFlags decoderFlags = DecoderFlags::IMAGE_IS_TRANSIENT;
421 decoder->SetDecoderFlags(aDecoderFlags | decoderFlags);
422 decoder->SetSurfaceFlags(aSurfaceFlags);
424 // Set an output size for downscale-during-decode if requested.
425 if (aOutputSize) {
426 decoder->SetOutputSize(OrientedIntSize::FromUnknownSize(*aOutputSize));
429 if (NS_FAILED(decoder->Init())) {
430 return nullptr;
433 return decoder.forget();
436 /* static */
437 already_AddRefed<Decoder> DecoderFactory::CreateAnonymousMetadataDecoder(
438 DecoderType aType, NotNull<SourceBuffer*> aSourceBuffer,
439 DecoderFlags aDecoderFlags) {
440 if (aType == DecoderType::UNKNOWN) {
441 return nullptr;
444 RefPtr<Decoder> decoder =
445 GetDecoder(aType, /* aImage = */ nullptr, /* aIsRedecode = */ false);
446 MOZ_ASSERT(decoder, "Should have a decoder now");
448 // Initialize the decoder.
449 decoder->SetMetadataDecode(true);
450 decoder->SetIterator(aSourceBuffer->Iterator());
451 decoder->SetDecoderFlags(aDecoderFlags);
453 if (NS_FAILED(decoder->Init())) {
454 return nullptr;
457 return decoder.forget();
460 } // namespace image
461 } // namespace mozilla