Bug 1472338: part 1) Add Chrome tests for the async Clipboard API. r=NeilDeakin
[gecko.git] / image / DecoderFactory.cpp
blob5004b93eae09c522c4d63ac418920698e8ff25aa
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 StaticPrefs::image_webp_enabled()) {
84 type = DecoderType::WEBP;
86 // AVIF
88 #ifdef MOZ_AV1
89 else if (!strcmp(aMimeType, IMAGE_AVIF) &&
90 StaticPrefs::image_avif_enabled()) {
91 type = DecoderType::AVIF;
93 #endif
94 #ifdef MOZ_JXL
95 else if (!strcmp(aMimeType, IMAGE_JXL) && StaticPrefs::image_jxl_enabled()) {
96 type = DecoderType::JXL;
98 #endif
100 return type;
103 /* static */
104 already_AddRefed<Decoder> DecoderFactory::GetDecoder(DecoderType aType,
105 RasterImage* aImage,
106 bool aIsRedecode) {
107 RefPtr<Decoder> decoder;
109 switch (aType) {
110 case DecoderType::PNG:
111 decoder = new nsPNGDecoder(aImage);
112 break;
113 case DecoderType::GIF:
114 decoder = new nsGIFDecoder2(aImage);
115 break;
116 case DecoderType::JPEG:
117 // If we have all the data we don't want to waste cpu time doing
118 // a progressive decode.
119 decoder = new nsJPEGDecoder(
120 aImage, aIsRedecode ? Decoder::SEQUENTIAL : Decoder::PROGRESSIVE);
121 break;
122 case DecoderType::BMP:
123 decoder = new nsBMPDecoder(aImage);
124 break;
125 case DecoderType::BMP_CLIPBOARD:
126 decoder = new nsBMPDecoder(aImage, /* aForClipboard */ true);
127 break;
128 case DecoderType::ICO:
129 decoder = new nsICODecoder(aImage);
130 break;
131 case DecoderType::ICON:
132 decoder = new nsIconDecoder(aImage);
133 break;
134 case DecoderType::WEBP:
135 decoder = new nsWebPDecoder(aImage);
136 break;
137 #ifdef MOZ_AV1
138 case DecoderType::AVIF:
139 decoder = new nsAVIFDecoder(aImage);
140 break;
141 #endif
142 #ifdef MOZ_JXL
143 case DecoderType::JXL:
144 decoder = new nsJXLDecoder(aImage);
145 break;
146 #endif
147 default:
148 MOZ_ASSERT_UNREACHABLE("Unknown decoder type");
151 return decoder.forget();
154 /* static */
155 nsresult DecoderFactory::CreateDecoder(
156 DecoderType aType, NotNull<RasterImage*> aImage,
157 NotNull<SourceBuffer*> aSourceBuffer, const IntSize& aIntrinsicSize,
158 const IntSize& aOutputSize, DecoderFlags aDecoderFlags,
159 SurfaceFlags aSurfaceFlags, IDecodingTask** aOutTask) {
160 if (aType == DecoderType::UNKNOWN) {
161 return NS_ERROR_INVALID_ARG;
164 // Create an anonymous decoder. Interaction with the SurfaceCache and the
165 // owning RasterImage will be mediated by DecodedSurfaceProvider.
166 RefPtr<Decoder> decoder = GetDecoder(
167 aType, nullptr, bool(aDecoderFlags & DecoderFlags::IS_REDECODE));
168 MOZ_ASSERT(decoder, "Should have a decoder now");
170 // Initialize the decoder.
171 decoder->SetMetadataDecode(false);
172 decoder->SetIterator(aSourceBuffer->Iterator());
173 decoder->SetOutputSize(OrientedIntSize::FromUnknownSize(aOutputSize));
174 decoder->SetDecoderFlags(aDecoderFlags | DecoderFlags::FIRST_FRAME_ONLY);
175 decoder->SetSurfaceFlags(aSurfaceFlags);
177 nsresult rv = decoder->Init();
178 if (NS_FAILED(rv)) {
179 return NS_ERROR_FAILURE;
182 // Create a DecodedSurfaceProvider which will manage the decoding process and
183 // make this decoder's output available in the surface cache.
184 SurfaceKey surfaceKey =
185 RasterSurfaceKey(aOutputSize, aSurfaceFlags, PlaybackType::eStatic);
186 auto provider = MakeNotNull<RefPtr<DecodedSurfaceProvider>>(
187 aImage, surfaceKey, WrapNotNull(decoder));
188 if (aDecoderFlags & DecoderFlags::CANNOT_SUBSTITUTE) {
189 provider->Availability().SetCannotSubstitute();
192 // Attempt to insert the surface provider into the surface cache right away so
193 // we won't trigger any more decoders with the same parameters.
194 switch (SurfaceCache::Insert(provider)) {
195 case InsertOutcome::SUCCESS:
196 break;
197 case InsertOutcome::FAILURE_ALREADY_PRESENT:
198 return NS_ERROR_ALREADY_INITIALIZED;
199 default:
200 return NS_ERROR_FAILURE;
203 // Return the surface provider in its IDecodingTask guise.
204 RefPtr<IDecodingTask> task = provider.get();
205 task.forget(aOutTask);
206 return NS_OK;
209 /* static */
210 nsresult DecoderFactory::CreateAnimationDecoder(
211 DecoderType aType, NotNull<RasterImage*> aImage,
212 NotNull<SourceBuffer*> aSourceBuffer, const IntSize& aIntrinsicSize,
213 DecoderFlags aDecoderFlags, SurfaceFlags aSurfaceFlags,
214 size_t aCurrentFrame, IDecodingTask** aOutTask) {
215 if (aType == DecoderType::UNKNOWN) {
216 return NS_ERROR_INVALID_ARG;
219 MOZ_ASSERT(aType == DecoderType::GIF || aType == DecoderType::PNG ||
220 aType == DecoderType::WEBP,
221 "Calling CreateAnimationDecoder for non-animating DecoderType");
223 // Create an anonymous decoder. Interaction with the SurfaceCache and the
224 // owning RasterImage will be mediated by AnimationSurfaceProvider.
225 RefPtr<Decoder> decoder =
226 GetDecoder(aType, nullptr, /* aIsRedecode = */ true);
227 MOZ_ASSERT(decoder, "Should have a decoder now");
229 // Initialize the decoder.
230 decoder->SetMetadataDecode(false);
231 decoder->SetIterator(aSourceBuffer->Iterator());
232 decoder->SetDecoderFlags(aDecoderFlags | DecoderFlags::IS_REDECODE);
233 decoder->SetSurfaceFlags(aSurfaceFlags);
235 nsresult rv = decoder->Init();
236 if (NS_FAILED(rv)) {
237 return NS_ERROR_FAILURE;
240 // Create an AnimationSurfaceProvider which will manage the decoding process
241 // and make this decoder's output available in the surface cache.
242 SurfaceKey surfaceKey =
243 RasterSurfaceKey(aIntrinsicSize, aSurfaceFlags, PlaybackType::eAnimated);
244 auto provider = MakeNotNull<RefPtr<AnimationSurfaceProvider>>(
245 aImage, surfaceKey, WrapNotNull(decoder), aCurrentFrame);
247 // Attempt to insert the surface provider into the surface cache right away so
248 // we won't trigger any more decoders with the same parameters.
249 switch (SurfaceCache::Insert(provider)) {
250 case InsertOutcome::SUCCESS:
251 break;
252 case InsertOutcome::FAILURE_ALREADY_PRESENT:
253 return NS_ERROR_ALREADY_INITIALIZED;
254 default:
255 return NS_ERROR_FAILURE;
258 // Return the surface provider in its IDecodingTask guise.
259 RefPtr<IDecodingTask> task = provider.get();
260 task.forget(aOutTask);
261 return NS_OK;
264 /* static */
265 already_AddRefed<Decoder> DecoderFactory::CloneAnimationDecoder(
266 Decoder* aDecoder) {
267 MOZ_ASSERT(aDecoder);
269 // In an ideal world, we would assert aDecoder->HasAnimation() but we cannot.
270 // The decoder may not have detected it is animated yet (e.g. it did not even
271 // get scheduled yet, or it has only decoded the first frame and has yet to
272 // rediscover it is animated).
273 DecoderType type = aDecoder->GetType();
274 MOZ_ASSERT(type == DecoderType::GIF || type == DecoderType::PNG ||
275 type == DecoderType::WEBP,
276 "Calling CloneAnimationDecoder for non-animating DecoderType");
278 RefPtr<Decoder> decoder = GetDecoder(type, nullptr, /* aIsRedecode = */ true);
279 MOZ_ASSERT(decoder, "Should have a decoder now");
281 // Initialize the decoder.
282 decoder->SetMetadataDecode(false);
283 decoder->SetIterator(aDecoder->GetSourceBuffer()->Iterator());
284 decoder->SetDecoderFlags(aDecoder->GetDecoderFlags());
285 decoder->SetSurfaceFlags(aDecoder->GetSurfaceFlags());
286 decoder->SetFrameRecycler(aDecoder->GetFrameRecycler());
288 if (NS_FAILED(decoder->Init())) {
289 return nullptr;
292 return decoder.forget();
295 /* static */
296 already_AddRefed<IDecodingTask> DecoderFactory::CreateMetadataDecoder(
297 DecoderType aType, NotNull<RasterImage*> aImage,
298 NotNull<SourceBuffer*> aSourceBuffer) {
299 if (aType == DecoderType::UNKNOWN) {
300 return nullptr;
303 RefPtr<Decoder> decoder =
304 GetDecoder(aType, aImage, /* aIsRedecode = */ false);
305 MOZ_ASSERT(decoder, "Should have a decoder now");
307 // Initialize the decoder.
308 decoder->SetMetadataDecode(true);
309 decoder->SetIterator(aSourceBuffer->Iterator());
311 if (NS_FAILED(decoder->Init())) {
312 return nullptr;
315 RefPtr<IDecodingTask> task = new MetadataDecodingTask(WrapNotNull(decoder));
316 return task.forget();
319 /* static */
320 already_AddRefed<Decoder> DecoderFactory::CreateDecoderForICOResource(
321 DecoderType aType, SourceBufferIterator&& aIterator,
322 NotNull<nsICODecoder*> aICODecoder, bool aIsMetadataDecode,
323 const Maybe<OrientedIntSize>& aExpectedSize,
324 const Maybe<uint32_t>& aDataOffset
325 /* = Nothing() */) {
326 // Create the decoder.
327 RefPtr<Decoder> decoder;
328 switch (aType) {
329 case DecoderType::BMP:
330 MOZ_ASSERT(aDataOffset);
331 decoder =
332 new nsBMPDecoder(aICODecoder->GetImageMaybeNull(), *aDataOffset);
333 break;
335 case DecoderType::PNG:
336 MOZ_ASSERT(!aDataOffset);
337 decoder = new nsPNGDecoder(aICODecoder->GetImageMaybeNull());
338 break;
340 default:
341 MOZ_ASSERT_UNREACHABLE("Invalid ICO resource decoder type");
342 return nullptr;
345 MOZ_ASSERT(decoder);
347 // Initialize the decoder, copying settings from @aICODecoder.
348 decoder->SetMetadataDecode(aIsMetadataDecode);
349 decoder->SetIterator(std::forward<SourceBufferIterator>(aIterator));
350 if (!aIsMetadataDecode) {
351 decoder->SetOutputSize(aICODecoder->OutputSize());
353 if (aExpectedSize) {
354 decoder->SetExpectedSize(*aExpectedSize);
356 decoder->SetDecoderFlags(aICODecoder->GetDecoderFlags());
357 decoder->SetSurfaceFlags(aICODecoder->GetSurfaceFlags());
358 decoder->SetFinalizeFrames(false);
360 if (NS_FAILED(decoder->Init())) {
361 return nullptr;
364 return decoder.forget();
367 /* static */
368 already_AddRefed<Decoder> DecoderFactory::CreateAnonymousDecoder(
369 DecoderType aType, NotNull<SourceBuffer*> aSourceBuffer,
370 const Maybe<IntSize>& aOutputSize, DecoderFlags aDecoderFlags,
371 SurfaceFlags aSurfaceFlags) {
372 if (aType == DecoderType::UNKNOWN) {
373 return nullptr;
376 RefPtr<Decoder> decoder =
377 GetDecoder(aType, /* aImage = */ nullptr, /* aIsRedecode = */ false);
378 MOZ_ASSERT(decoder, "Should have a decoder now");
380 // Initialize the decoder.
381 decoder->SetMetadataDecode(false);
382 decoder->SetIterator(aSourceBuffer->Iterator());
384 // Anonymous decoders are always transient; we don't want to optimize surfaces
385 // or do any other expensive work that might be wasted.
386 DecoderFlags decoderFlags = DecoderFlags::IMAGE_IS_TRANSIENT;
388 decoder->SetDecoderFlags(aDecoderFlags | decoderFlags);
389 decoder->SetSurfaceFlags(aSurfaceFlags);
391 // Set an output size for downscale-during-decode if requested.
392 if (aOutputSize) {
393 decoder->SetOutputSize(OrientedIntSize::FromUnknownSize(*aOutputSize));
396 if (NS_FAILED(decoder->Init())) {
397 return nullptr;
400 return decoder.forget();
403 /* static */
404 already_AddRefed<Decoder> DecoderFactory::CreateAnonymousMetadataDecoder(
405 DecoderType aType, NotNull<SourceBuffer*> aSourceBuffer) {
406 if (aType == DecoderType::UNKNOWN) {
407 return nullptr;
410 RefPtr<Decoder> decoder =
411 GetDecoder(aType, /* aImage = */ nullptr, /* aIsRedecode = */ false);
412 MOZ_ASSERT(decoder, "Should have a decoder now");
414 // Initialize the decoder.
415 decoder->SetMetadataDecode(true);
416 decoder->SetIterator(aSourceBuffer->Iterator());
417 decoder->SetDecoderFlags(DecoderFlags::FIRST_FRAME_ONLY);
419 if (NS_FAILED(decoder->Init())) {
420 return nullptr;
423 return decoder.forget();
426 } // namespace image
427 } // namespace mozilla