Bug 1869043 assert that graph set access is main thread only r=padenot
[gecko.git] / image / DecoderFactory.cpp
blobf291a0934ab20d40324f976729dd0c9ed2761048
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 // Create an anonymous decoder. Interaction with the SurfaceCache and the
182 // owning RasterImage will be mediated by DecodedSurfaceProvider.
183 RefPtr<Decoder> decoder = GetDecoder(
184 aType, nullptr, bool(aDecoderFlags & DecoderFlags::IS_REDECODE));
185 MOZ_ASSERT(decoder, "Should have a decoder now");
187 // Initialize the decoder.
188 decoder->SetMetadataDecode(false);
189 decoder->SetIterator(aSourceBuffer->Iterator());
190 decoder->SetOutputSize(OrientedIntSize::FromUnknownSize(aOutputSize));
191 decoder->SetDecoderFlags(aDecoderFlags | DecoderFlags::FIRST_FRAME_ONLY);
192 decoder->SetSurfaceFlags(aSurfaceFlags);
194 nsresult rv = decoder->Init();
195 if (NS_FAILED(rv)) {
196 return NS_ERROR_FAILURE;
199 // Create a DecodedSurfaceProvider which will manage the decoding process and
200 // make this decoder's output available in the surface cache.
201 SurfaceKey surfaceKey =
202 RasterSurfaceKey(aOutputSize, aSurfaceFlags, PlaybackType::eStatic);
203 auto provider = MakeNotNull<RefPtr<DecodedSurfaceProvider>>(
204 aImage, surfaceKey, WrapNotNull(decoder));
205 if (aDecoderFlags & DecoderFlags::CANNOT_SUBSTITUTE) {
206 provider->Availability().SetCannotSubstitute();
209 // Attempt to insert the surface provider into the surface cache right away so
210 // we won't trigger any more decoders with the same parameters.
211 switch (SurfaceCache::Insert(provider)) {
212 case InsertOutcome::SUCCESS:
213 break;
214 case InsertOutcome::FAILURE_ALREADY_PRESENT:
215 return NS_ERROR_ALREADY_INITIALIZED;
216 default:
217 return NS_ERROR_FAILURE;
220 // Return the surface provider in its IDecodingTask guise.
221 RefPtr<IDecodingTask> task = provider.get();
222 task.forget(aOutTask);
223 return NS_OK;
226 /* static */
227 nsresult DecoderFactory::CreateAnimationDecoder(
228 DecoderType aType, NotNull<RasterImage*> aImage,
229 NotNull<SourceBuffer*> aSourceBuffer, const IntSize& aIntrinsicSize,
230 DecoderFlags aDecoderFlags, SurfaceFlags aSurfaceFlags,
231 size_t aCurrentFrame, IDecodingTask** aOutTask) {
232 if (aType == DecoderType::UNKNOWN) {
233 return NS_ERROR_INVALID_ARG;
236 MOZ_ASSERT(aType == DecoderType::GIF || aType == DecoderType::PNG ||
237 aType == DecoderType::WEBP || aType == DecoderType::AVIF,
238 "Calling CreateAnimationDecoder for non-animating DecoderType");
240 // Create an anonymous decoder. Interaction with the SurfaceCache and the
241 // owning RasterImage will be mediated by AnimationSurfaceProvider.
242 RefPtr<Decoder> decoder =
243 GetDecoder(aType, nullptr, /* aIsRedecode = */ true);
244 MOZ_ASSERT(decoder, "Should have a decoder now");
246 // Initialize the decoder.
247 decoder->SetMetadataDecode(false);
248 decoder->SetIterator(aSourceBuffer->Iterator());
249 decoder->SetDecoderFlags(aDecoderFlags | DecoderFlags::IS_REDECODE);
250 decoder->SetSurfaceFlags(aSurfaceFlags);
252 nsresult rv = decoder->Init();
253 if (NS_FAILED(rv)) {
254 return NS_ERROR_FAILURE;
257 // Create an AnimationSurfaceProvider which will manage the decoding process
258 // and make this decoder's output available in the surface cache.
259 SurfaceKey surfaceKey =
260 RasterSurfaceKey(aIntrinsicSize, aSurfaceFlags, PlaybackType::eAnimated);
261 auto provider = MakeNotNull<RefPtr<AnimationSurfaceProvider>>(
262 aImage, surfaceKey, WrapNotNull(decoder), aCurrentFrame);
264 // Attempt to insert the surface provider into the surface cache right away so
265 // we won't trigger any more decoders with the same parameters.
266 switch (SurfaceCache::Insert(provider)) {
267 case InsertOutcome::SUCCESS:
268 break;
269 case InsertOutcome::FAILURE_ALREADY_PRESENT:
270 return NS_ERROR_ALREADY_INITIALIZED;
271 default:
272 return NS_ERROR_FAILURE;
275 // Return the surface provider in its IDecodingTask guise.
276 RefPtr<IDecodingTask> task = provider.get();
277 task.forget(aOutTask);
278 return NS_OK;
281 /* static */
282 already_AddRefed<Decoder> DecoderFactory::CloneAnimationDecoder(
283 Decoder* aDecoder) {
284 MOZ_ASSERT(aDecoder);
286 // In an ideal world, we would assert aDecoder->HasAnimation() but we cannot.
287 // The decoder may not have detected it is animated yet (e.g. it did not even
288 // get scheduled yet, or it has only decoded the first frame and has yet to
289 // rediscover it is animated).
290 DecoderType type = aDecoder->GetType();
291 MOZ_ASSERT(type == DecoderType::GIF || type == DecoderType::PNG ||
292 type == DecoderType::WEBP || type == DecoderType::AVIF,
293 "Calling CloneAnimationDecoder for non-animating DecoderType");
295 RefPtr<Decoder> decoder = GetDecoder(type, nullptr, /* aIsRedecode = */ true);
296 MOZ_ASSERT(decoder, "Should have a decoder now");
298 // Initialize the decoder.
299 decoder->SetMetadataDecode(false);
300 decoder->SetIterator(aDecoder->GetSourceBuffer()->Iterator());
301 decoder->SetDecoderFlags(aDecoder->GetDecoderFlags());
302 decoder->SetSurfaceFlags(aDecoder->GetSurfaceFlags());
303 decoder->SetFrameRecycler(aDecoder->GetFrameRecycler());
305 if (NS_FAILED(decoder->Init())) {
306 return nullptr;
309 return decoder.forget();
312 /* static */
313 already_AddRefed<IDecodingTask> DecoderFactory::CreateMetadataDecoder(
314 DecoderType aType, NotNull<RasterImage*> aImage, DecoderFlags aFlags,
315 NotNull<SourceBuffer*> aSourceBuffer) {
316 if (aType == DecoderType::UNKNOWN) {
317 return nullptr;
320 RefPtr<Decoder> decoder =
321 GetDecoder(aType, aImage, /* aIsRedecode = */ false);
322 MOZ_ASSERT(decoder, "Should have a decoder now");
324 // Initialize the decoder.
325 decoder->SetMetadataDecode(true);
326 decoder->SetDecoderFlags(aFlags);
327 decoder->SetIterator(aSourceBuffer->Iterator());
329 if (NS_FAILED(decoder->Init())) {
330 return nullptr;
333 RefPtr<IDecodingTask> task = new MetadataDecodingTask(WrapNotNull(decoder));
334 return task.forget();
337 /* static */
338 already_AddRefed<Decoder> DecoderFactory::CreateDecoderForICOResource(
339 DecoderType aType, SourceBufferIterator&& aIterator,
340 NotNull<nsICODecoder*> aICODecoder, bool aIsMetadataDecode,
341 const Maybe<OrientedIntSize>& aExpectedSize,
342 const Maybe<uint32_t>& aDataOffset
343 /* = Nothing() */) {
344 // Create the decoder.
345 RefPtr<Decoder> decoder;
346 switch (aType) {
347 case DecoderType::BMP:
348 MOZ_ASSERT(aDataOffset);
349 decoder =
350 new nsBMPDecoder(aICODecoder->GetImageMaybeNull(), *aDataOffset);
351 break;
353 case DecoderType::PNG:
354 MOZ_ASSERT(!aDataOffset);
355 decoder = new nsPNGDecoder(aICODecoder->GetImageMaybeNull());
356 break;
358 default:
359 MOZ_ASSERT_UNREACHABLE("Invalid ICO resource decoder type");
360 return nullptr;
363 MOZ_ASSERT(decoder);
365 // Initialize the decoder, copying settings from @aICODecoder.
366 decoder->SetMetadataDecode(aIsMetadataDecode);
367 decoder->SetIterator(std::forward<SourceBufferIterator>(aIterator));
368 if (!aIsMetadataDecode) {
369 decoder->SetOutputSize(aICODecoder->OutputSize());
371 if (aExpectedSize) {
372 decoder->SetExpectedSize(*aExpectedSize);
374 decoder->SetDecoderFlags(aICODecoder->GetDecoderFlags());
375 decoder->SetSurfaceFlags(aICODecoder->GetSurfaceFlags());
376 decoder->SetFinalizeFrames(false);
378 if (NS_FAILED(decoder->Init())) {
379 return nullptr;
382 return decoder.forget();
385 /* static */
386 already_AddRefed<Decoder> DecoderFactory::CreateAnonymousDecoder(
387 DecoderType aType, NotNull<SourceBuffer*> aSourceBuffer,
388 const Maybe<IntSize>& aOutputSize, DecoderFlags aDecoderFlags,
389 SurfaceFlags aSurfaceFlags) {
390 if (aType == DecoderType::UNKNOWN) {
391 return nullptr;
394 RefPtr<Decoder> decoder =
395 GetDecoder(aType, /* aImage = */ nullptr, /* aIsRedecode = */ false);
396 MOZ_ASSERT(decoder, "Should have a decoder now");
398 // Initialize the decoder.
399 decoder->SetMetadataDecode(false);
400 decoder->SetIterator(aSourceBuffer->Iterator());
402 // Anonymous decoders are always transient; we don't want to optimize surfaces
403 // or do any other expensive work that might be wasted.
404 DecoderFlags decoderFlags = DecoderFlags::IMAGE_IS_TRANSIENT;
406 decoder->SetDecoderFlags(aDecoderFlags | decoderFlags);
407 decoder->SetSurfaceFlags(aSurfaceFlags);
409 // Set an output size for downscale-during-decode if requested.
410 if (aOutputSize) {
411 decoder->SetOutputSize(OrientedIntSize::FromUnknownSize(*aOutputSize));
414 if (NS_FAILED(decoder->Init())) {
415 return nullptr;
418 return decoder.forget();
421 /* static */
422 already_AddRefed<Decoder> DecoderFactory::CreateAnonymousMetadataDecoder(
423 DecoderType aType, NotNull<SourceBuffer*> aSourceBuffer) {
424 if (aType == DecoderType::UNKNOWN) {
425 return nullptr;
428 RefPtr<Decoder> decoder =
429 GetDecoder(aType, /* aImage = */ nullptr, /* aIsRedecode = */ false);
430 MOZ_ASSERT(decoder, "Should have a decoder now");
432 // Initialize the decoder.
433 decoder->SetMetadataDecode(true);
434 decoder->SetIterator(aSourceBuffer->Iterator());
435 decoder->SetDecoderFlags(DecoderFlags::FIRST_FRAME_ONLY);
437 if (NS_FAILED(decoder->Init())) {
438 return nullptr;
441 return decoder.forget();
444 } // namespace image
445 } // namespace mozilla