Bug 1690340 - Part 2: Use the new naming for the developer tools menu items. r=jdescottes
[gecko.git] / image / DecoderFactory.cpp
bloba65166c510e861f11f989396014f1033ebd11640
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
27 namespace mozilla {
29 using namespace gfx;
31 namespace image {
33 /* static */
34 DecoderType DecoderFactory::GetDecoderType(const char* aMimeType) {
35 // By default we don't know.
36 DecoderType type = DecoderType::UNKNOWN;
38 // PNG
39 if (!strcmp(aMimeType, IMAGE_PNG)) {
40 type = DecoderType::PNG;
41 } else if (!strcmp(aMimeType, IMAGE_X_PNG)) {
42 type = DecoderType::PNG;
43 } else if (!strcmp(aMimeType, IMAGE_APNG)) {
44 type = DecoderType::PNG;
46 // GIF
47 } else if (!strcmp(aMimeType, IMAGE_GIF)) {
48 type = DecoderType::GIF;
50 // JPEG
51 } else if (!strcmp(aMimeType, IMAGE_JPEG)) {
52 type = DecoderType::JPEG;
53 } else if (!strcmp(aMimeType, IMAGE_PJPEG)) {
54 type = DecoderType::JPEG;
55 } else if (!strcmp(aMimeType, IMAGE_JPG)) {
56 type = DecoderType::JPEG;
58 // BMP
59 } else if (!strcmp(aMimeType, IMAGE_BMP)) {
60 type = DecoderType::BMP;
61 } else if (!strcmp(aMimeType, IMAGE_BMP_MS)) {
62 type = DecoderType::BMP;
64 // BMP_CLIPBOARD
65 } else if (!strcmp(aMimeType, IMAGE_BMP_MS_CLIPBOARD)) {
66 type = DecoderType::BMP_CLIPBOARD;
68 // ICO
69 } else if (!strcmp(aMimeType, IMAGE_ICO)) {
70 type = DecoderType::ICO;
71 } else if (!strcmp(aMimeType, IMAGE_ICO_MS)) {
72 type = DecoderType::ICO;
74 // Icon
75 } else if (!strcmp(aMimeType, IMAGE_ICON_MS)) {
76 type = DecoderType::ICON;
78 // WebP
79 } else if (!strcmp(aMimeType, IMAGE_WEBP) &&
80 StaticPrefs::image_webp_enabled()) {
81 type = DecoderType::WEBP;
83 // AVIF
85 #ifdef MOZ_AV1
86 else if (!strcmp(aMimeType, IMAGE_AVIF) &&
87 StaticPrefs::image_avif_enabled()) {
88 type = DecoderType::AVIF;
90 #endif
92 return type;
95 /* static */
96 already_AddRefed<Decoder> DecoderFactory::GetDecoder(DecoderType aType,
97 RasterImage* aImage,
98 bool aIsRedecode) {
99 RefPtr<Decoder> decoder;
101 switch (aType) {
102 case DecoderType::PNG:
103 decoder = new nsPNGDecoder(aImage);
104 break;
105 case DecoderType::GIF:
106 decoder = new nsGIFDecoder2(aImage);
107 break;
108 case DecoderType::JPEG:
109 // If we have all the data we don't want to waste cpu time doing
110 // a progressive decode.
111 decoder = new nsJPEGDecoder(
112 aImage, aIsRedecode ? Decoder::SEQUENTIAL : Decoder::PROGRESSIVE);
113 break;
114 case DecoderType::BMP:
115 decoder = new nsBMPDecoder(aImage);
116 break;
117 case DecoderType::BMP_CLIPBOARD:
118 decoder = new nsBMPDecoder(aImage, /* aForClipboard */ true);
119 break;
120 case DecoderType::ICO:
121 decoder = new nsICODecoder(aImage);
122 break;
123 case DecoderType::ICON:
124 decoder = new nsIconDecoder(aImage);
125 break;
126 case DecoderType::WEBP:
127 decoder = new nsWebPDecoder(aImage);
128 break;
129 #ifdef MOZ_AV1
130 case DecoderType::AVIF:
131 decoder = new nsAVIFDecoder(aImage);
132 break;
133 #endif
134 default:
135 MOZ_ASSERT_UNREACHABLE("Unknown decoder type");
138 return decoder.forget();
141 /* static */
142 nsresult DecoderFactory::CreateDecoder(
143 DecoderType aType, NotNull<RasterImage*> aImage,
144 NotNull<SourceBuffer*> aSourceBuffer, const IntSize& aIntrinsicSize,
145 const IntSize& aOutputSize, DecoderFlags aDecoderFlags,
146 SurfaceFlags aSurfaceFlags, IDecodingTask** aOutTask) {
147 if (aType == DecoderType::UNKNOWN) {
148 return NS_ERROR_INVALID_ARG;
151 // Create an anonymous decoder. Interaction with the SurfaceCache and the
152 // owning RasterImage will be mediated by DecodedSurfaceProvider.
153 RefPtr<Decoder> decoder = GetDecoder(
154 aType, nullptr, bool(aDecoderFlags & DecoderFlags::IS_REDECODE));
155 MOZ_ASSERT(decoder, "Should have a decoder now");
157 // Initialize the decoder.
158 decoder->SetMetadataDecode(false);
159 decoder->SetIterator(aSourceBuffer->Iterator());
160 decoder->SetOutputSize(aOutputSize);
161 decoder->SetDecoderFlags(aDecoderFlags | DecoderFlags::FIRST_FRAME_ONLY);
162 decoder->SetSurfaceFlags(aSurfaceFlags);
164 nsresult rv = decoder->Init();
165 if (NS_FAILED(rv)) {
166 return NS_ERROR_FAILURE;
169 // Create a DecodedSurfaceProvider which will manage the decoding process and
170 // make this decoder's output available in the surface cache.
171 SurfaceKey surfaceKey =
172 RasterSurfaceKey(aOutputSize, aSurfaceFlags, PlaybackType::eStatic);
173 auto provider = MakeNotNull<RefPtr<DecodedSurfaceProvider>>(
174 aImage, surfaceKey, WrapNotNull(decoder));
175 if (aDecoderFlags & DecoderFlags::CANNOT_SUBSTITUTE) {
176 provider->Availability().SetCannotSubstitute();
179 // Attempt to insert the surface provider into the surface cache right away so
180 // we won't trigger any more decoders with the same parameters.
181 switch (SurfaceCache::Insert(provider)) {
182 case InsertOutcome::SUCCESS:
183 break;
184 case InsertOutcome::FAILURE_ALREADY_PRESENT:
185 return NS_ERROR_ALREADY_INITIALIZED;
186 default:
187 return NS_ERROR_FAILURE;
190 // Return the surface provider in its IDecodingTask guise.
191 RefPtr<IDecodingTask> task = provider.get();
192 task.forget(aOutTask);
193 return NS_OK;
196 /* static */
197 nsresult DecoderFactory::CreateAnimationDecoder(
198 DecoderType aType, NotNull<RasterImage*> aImage,
199 NotNull<SourceBuffer*> aSourceBuffer, const IntSize& aIntrinsicSize,
200 DecoderFlags aDecoderFlags, SurfaceFlags aSurfaceFlags,
201 size_t aCurrentFrame, IDecodingTask** aOutTask) {
202 if (aType == DecoderType::UNKNOWN) {
203 return NS_ERROR_INVALID_ARG;
206 MOZ_ASSERT(aType == DecoderType::GIF || aType == DecoderType::PNG ||
207 aType == DecoderType::WEBP,
208 "Calling CreateAnimationDecoder for non-animating DecoderType");
210 // Create an anonymous decoder. Interaction with the SurfaceCache and the
211 // owning RasterImage will be mediated by AnimationSurfaceProvider.
212 RefPtr<Decoder> decoder =
213 GetDecoder(aType, nullptr, /* aIsRedecode = */ true);
214 MOZ_ASSERT(decoder, "Should have a decoder now");
216 // Initialize the decoder.
217 decoder->SetMetadataDecode(false);
218 decoder->SetIterator(aSourceBuffer->Iterator());
219 decoder->SetDecoderFlags(aDecoderFlags | DecoderFlags::IS_REDECODE);
220 decoder->SetSurfaceFlags(aSurfaceFlags);
222 nsresult rv = decoder->Init();
223 if (NS_FAILED(rv)) {
224 return NS_ERROR_FAILURE;
227 // Create an AnimationSurfaceProvider which will manage the decoding process
228 // and make this decoder's output available in the surface cache.
229 SurfaceKey surfaceKey =
230 RasterSurfaceKey(aIntrinsicSize, aSurfaceFlags, PlaybackType::eAnimated);
231 auto provider = MakeNotNull<RefPtr<AnimationSurfaceProvider>>(
232 aImage, surfaceKey, WrapNotNull(decoder), aCurrentFrame);
234 // Attempt to insert the surface provider into the surface cache right away so
235 // we won't trigger any more decoders with the same parameters.
236 switch (SurfaceCache::Insert(provider)) {
237 case InsertOutcome::SUCCESS:
238 break;
239 case InsertOutcome::FAILURE_ALREADY_PRESENT:
240 return NS_ERROR_ALREADY_INITIALIZED;
241 default:
242 return NS_ERROR_FAILURE;
245 // Return the surface provider in its IDecodingTask guise.
246 RefPtr<IDecodingTask> task = provider.get();
247 task.forget(aOutTask);
248 return NS_OK;
251 /* static */
252 already_AddRefed<Decoder> DecoderFactory::CloneAnimationDecoder(
253 Decoder* aDecoder) {
254 MOZ_ASSERT(aDecoder);
256 // In an ideal world, we would assert aDecoder->HasAnimation() but we cannot.
257 // The decoder may not have detected it is animated yet (e.g. it did not even
258 // get scheduled yet, or it has only decoded the first frame and has yet to
259 // rediscover it is animated).
260 DecoderType type = aDecoder->GetType();
261 MOZ_ASSERT(type == DecoderType::GIF || type == DecoderType::PNG ||
262 type == DecoderType::WEBP,
263 "Calling CloneAnimationDecoder for non-animating DecoderType");
265 RefPtr<Decoder> decoder = GetDecoder(type, nullptr, /* aIsRedecode = */ true);
266 MOZ_ASSERT(decoder, "Should have a decoder now");
268 // Initialize the decoder.
269 decoder->SetMetadataDecode(false);
270 decoder->SetIterator(aDecoder->GetSourceBuffer()->Iterator());
271 decoder->SetDecoderFlags(aDecoder->GetDecoderFlags());
272 decoder->SetSurfaceFlags(aDecoder->GetSurfaceFlags());
273 decoder->SetFrameRecycler(aDecoder->GetFrameRecycler());
275 if (NS_FAILED(decoder->Init())) {
276 return nullptr;
279 return decoder.forget();
282 /* static */
283 already_AddRefed<IDecodingTask> DecoderFactory::CreateMetadataDecoder(
284 DecoderType aType, NotNull<RasterImage*> aImage,
285 NotNull<SourceBuffer*> aSourceBuffer) {
286 if (aType == DecoderType::UNKNOWN) {
287 return nullptr;
290 RefPtr<Decoder> decoder =
291 GetDecoder(aType, aImage, /* aIsRedecode = */ false);
292 MOZ_ASSERT(decoder, "Should have a decoder now");
294 // Initialize the decoder.
295 decoder->SetMetadataDecode(true);
296 decoder->SetIterator(aSourceBuffer->Iterator());
298 if (NS_FAILED(decoder->Init())) {
299 return nullptr;
302 RefPtr<IDecodingTask> task = new MetadataDecodingTask(WrapNotNull(decoder));
303 return task.forget();
306 /* static */
307 already_AddRefed<Decoder> DecoderFactory::CreateDecoderForICOResource(
308 DecoderType aType, SourceBufferIterator&& aIterator,
309 NotNull<nsICODecoder*> aICODecoder, bool aIsMetadataDecode,
310 const Maybe<IntSize>& aExpectedSize, const Maybe<uint32_t>& aDataOffset
311 /* = Nothing() */) {
312 // Create the decoder.
313 RefPtr<Decoder> decoder;
314 switch (aType) {
315 case DecoderType::BMP:
316 MOZ_ASSERT(aDataOffset);
317 decoder =
318 new nsBMPDecoder(aICODecoder->GetImageMaybeNull(), *aDataOffset);
319 break;
321 case DecoderType::PNG:
322 MOZ_ASSERT(!aDataOffset);
323 decoder = new nsPNGDecoder(aICODecoder->GetImageMaybeNull());
324 break;
326 default:
327 MOZ_ASSERT_UNREACHABLE("Invalid ICO resource decoder type");
328 return nullptr;
331 MOZ_ASSERT(decoder);
333 // Initialize the decoder, copying settings from @aICODecoder.
334 decoder->SetMetadataDecode(aIsMetadataDecode);
335 decoder->SetIterator(std::forward<SourceBufferIterator>(aIterator));
336 if (!aIsMetadataDecode) {
337 decoder->SetOutputSize(aICODecoder->OutputSize());
339 if (aExpectedSize) {
340 decoder->SetExpectedSize(*aExpectedSize);
342 decoder->SetDecoderFlags(aICODecoder->GetDecoderFlags());
343 decoder->SetSurfaceFlags(aICODecoder->GetSurfaceFlags());
344 decoder->SetFinalizeFrames(false);
346 if (NS_FAILED(decoder->Init())) {
347 return nullptr;
350 return decoder.forget();
353 /* static */
354 already_AddRefed<Decoder> DecoderFactory::CreateAnonymousDecoder(
355 DecoderType aType, NotNull<SourceBuffer*> aSourceBuffer,
356 const Maybe<IntSize>& aOutputSize, DecoderFlags aDecoderFlags,
357 SurfaceFlags aSurfaceFlags) {
358 if (aType == DecoderType::UNKNOWN) {
359 return nullptr;
362 RefPtr<Decoder> decoder =
363 GetDecoder(aType, /* aImage = */ nullptr, /* aIsRedecode = */ false);
364 MOZ_ASSERT(decoder, "Should have a decoder now");
366 // Initialize the decoder.
367 decoder->SetMetadataDecode(false);
368 decoder->SetIterator(aSourceBuffer->Iterator());
370 // Anonymous decoders are always transient; we don't want to optimize surfaces
371 // or do any other expensive work that might be wasted.
372 DecoderFlags decoderFlags = DecoderFlags::IMAGE_IS_TRANSIENT;
374 decoder->SetDecoderFlags(aDecoderFlags | decoderFlags);
375 decoder->SetSurfaceFlags(aSurfaceFlags);
377 // Set an output size for downscale-during-decode if requested.
378 if (aOutputSize) {
379 decoder->SetOutputSize(*aOutputSize);
382 if (NS_FAILED(decoder->Init())) {
383 return nullptr;
386 return decoder.forget();
389 /* static */
390 already_AddRefed<Decoder> DecoderFactory::CreateAnonymousMetadataDecoder(
391 DecoderType aType, NotNull<SourceBuffer*> aSourceBuffer) {
392 if (aType == DecoderType::UNKNOWN) {
393 return nullptr;
396 RefPtr<Decoder> decoder =
397 GetDecoder(aType, /* aImage = */ nullptr, /* aIsRedecode = */ false);
398 MOZ_ASSERT(decoder, "Should have a decoder now");
400 // Initialize the decoder.
401 decoder->SetMetadataDecode(true);
402 decoder->SetIterator(aSourceBuffer->Iterator());
403 decoder->SetDecoderFlags(DecoderFlags::FIRST_FRAME_ONLY);
405 if (NS_FAILED(decoder->Init())) {
406 return nullptr;
409 return decoder.forget();
412 } // namespace image
413 } // namespace mozilla