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/. */
5 
6 #include "DecoderFactory.h"
7 
8 #include "nsMimeTypes.h"
9 #include "mozilla/RefPtr.h"
10 
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
29 
30 namespace mozilla {
31 
32 using namespace gfx;
33 
34 namespace image {
35 
36 /* static */
GetDecoderType(const char * aMimeType)37 DecoderType DecoderFactory::GetDecoderType(const char* aMimeType) {
38   // By default we don't know.
39   DecoderType type = DecoderType::UNKNOWN;
40 
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;
48 
49     // GIF
50   } else if (!strcmp(aMimeType, IMAGE_GIF)) {
51     type = DecoderType::GIF;
52 
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;
60 
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;
66 
67     // BMP_CLIPBOARD
68   } else if (!strcmp(aMimeType, IMAGE_BMP_MS_CLIPBOARD)) {
69     type = DecoderType::BMP_CLIPBOARD;
70 
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;
76 
77     // Icon
78   } else if (!strcmp(aMimeType, IMAGE_ICON_MS)) {
79     type = DecoderType::ICON;
80 
81     // WebP
82   } else if (!strcmp(aMimeType, IMAGE_WEBP) &&
83              StaticPrefs::image_webp_enabled()) {
84     type = DecoderType::WEBP;
85 
86     // AVIF
87   }
88 #ifdef MOZ_AV1
89   else if (!strcmp(aMimeType, IMAGE_AVIF) &&
90            StaticPrefs::image_avif_enabled()) {
91     type = DecoderType::AVIF;
92   }
93 #endif
94 #ifdef MOZ_JXL
95   else if (!strcmp(aMimeType, IMAGE_JXL) && StaticPrefs::image_jxl_enabled()) {
96     type = DecoderType::JXL;
97   }
98 #endif
99 
100   return type;
101 }
102 
103 /* static */
GetDecoder(DecoderType aType,RasterImage * aImage,bool aIsRedecode)104 already_AddRefed<Decoder> DecoderFactory::GetDecoder(DecoderType aType,
105                                                      RasterImage* aImage,
106                                                      bool aIsRedecode) {
107   RefPtr<Decoder> decoder;
108 
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");
149   }
150 
151   return decoder.forget();
152 }
153 
154 /* static */
CreateDecoder(DecoderType aType,NotNull<RasterImage * > aImage,NotNull<SourceBuffer * > aSourceBuffer,const IntSize & aIntrinsicSize,const IntSize & aOutputSize,DecoderFlags aDecoderFlags,SurfaceFlags aSurfaceFlags,IDecodingTask ** aOutTask)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;
162   }
163 
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");
169 
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);
176 
177   nsresult rv = decoder->Init();
178   if (NS_FAILED(rv)) {
179     return NS_ERROR_FAILURE;
180   }
181 
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();
190   }
191 
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;
201   }
202 
203   // Return the surface provider in its IDecodingTask guise.
204   RefPtr<IDecodingTask> task = provider.get();
205   task.forget(aOutTask);
206   return NS_OK;
207 }
208 
209 /* static */
CreateAnimationDecoder(DecoderType aType,NotNull<RasterImage * > aImage,NotNull<SourceBuffer * > aSourceBuffer,const IntSize & aIntrinsicSize,DecoderFlags aDecoderFlags,SurfaceFlags aSurfaceFlags,size_t aCurrentFrame,IDecodingTask ** aOutTask)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;
217   }
218 
219   MOZ_ASSERT(aType == DecoderType::GIF || aType == DecoderType::PNG ||
220                  aType == DecoderType::WEBP,
221              "Calling CreateAnimationDecoder for non-animating DecoderType");
222 
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");
228 
229   // Initialize the decoder.
230   decoder->SetMetadataDecode(false);
231   decoder->SetIterator(aSourceBuffer->Iterator());
232   decoder->SetDecoderFlags(aDecoderFlags | DecoderFlags::IS_REDECODE);
233   decoder->SetSurfaceFlags(aSurfaceFlags);
234 
235   nsresult rv = decoder->Init();
236   if (NS_FAILED(rv)) {
237     return NS_ERROR_FAILURE;
238   }
239 
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);
246 
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;
256   }
257 
258   // Return the surface provider in its IDecodingTask guise.
259   RefPtr<IDecodingTask> task = provider.get();
260   task.forget(aOutTask);
261   return NS_OK;
262 }
263 
264 /* static */
CloneAnimationDecoder(Decoder * aDecoder)265 already_AddRefed<Decoder> DecoderFactory::CloneAnimationDecoder(
266     Decoder* aDecoder) {
267   MOZ_ASSERT(aDecoder);
268 
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");
277 
278   RefPtr<Decoder> decoder = GetDecoder(type, nullptr, /* aIsRedecode = */ true);
279   MOZ_ASSERT(decoder, "Should have a decoder now");
280 
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());
287 
288   if (NS_FAILED(decoder->Init())) {
289     return nullptr;
290   }
291 
292   return decoder.forget();
293 }
294 
295 /* static */
CreateMetadataDecoder(DecoderType aType,NotNull<RasterImage * > aImage,NotNull<SourceBuffer * > aSourceBuffer)296 already_AddRefed<IDecodingTask> DecoderFactory::CreateMetadataDecoder(
297     DecoderType aType, NotNull<RasterImage*> aImage,
298     NotNull<SourceBuffer*> aSourceBuffer) {
299   if (aType == DecoderType::UNKNOWN) {
300     return nullptr;
301   }
302 
303   RefPtr<Decoder> decoder =
304       GetDecoder(aType, aImage, /* aIsRedecode = */ false);
305   MOZ_ASSERT(decoder, "Should have a decoder now");
306 
307   // Initialize the decoder.
308   decoder->SetMetadataDecode(true);
309   decoder->SetIterator(aSourceBuffer->Iterator());
310 
311   if (NS_FAILED(decoder->Init())) {
312     return nullptr;
313   }
314 
315   RefPtr<IDecodingTask> task = new MetadataDecodingTask(WrapNotNull(decoder));
316   return task.forget();
317 }
318 
319 /* static */
CreateDecoderForICOResource(DecoderType aType,SourceBufferIterator && aIterator,NotNull<nsICODecoder * > aICODecoder,bool aIsMetadataDecode,const Maybe<OrientedIntSize> & aExpectedSize,const Maybe<uint32_t> & aDataOffset)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;
334 
335     case DecoderType::PNG:
336       MOZ_ASSERT(!aDataOffset);
337       decoder = new nsPNGDecoder(aICODecoder->GetImageMaybeNull());
338       break;
339 
340     default:
341       MOZ_ASSERT_UNREACHABLE("Invalid ICO resource decoder type");
342       return nullptr;
343   }
344 
345   MOZ_ASSERT(decoder);
346 
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());
352   }
353   if (aExpectedSize) {
354     decoder->SetExpectedSize(*aExpectedSize);
355   }
356   decoder->SetDecoderFlags(aICODecoder->GetDecoderFlags());
357   decoder->SetSurfaceFlags(aICODecoder->GetSurfaceFlags());
358   decoder->SetFinalizeFrames(false);
359 
360   if (NS_FAILED(decoder->Init())) {
361     return nullptr;
362   }
363 
364   return decoder.forget();
365 }
366 
367 /* static */
CreateAnonymousDecoder(DecoderType aType,NotNull<SourceBuffer * > aSourceBuffer,const Maybe<IntSize> & aOutputSize,DecoderFlags aDecoderFlags,SurfaceFlags aSurfaceFlags)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;
374   }
375 
376   RefPtr<Decoder> decoder =
377       GetDecoder(aType, /* aImage = */ nullptr, /* aIsRedecode = */ false);
378   MOZ_ASSERT(decoder, "Should have a decoder now");
379 
380   // Initialize the decoder.
381   decoder->SetMetadataDecode(false);
382   decoder->SetIterator(aSourceBuffer->Iterator());
383 
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;
387 
388   decoder->SetDecoderFlags(aDecoderFlags | decoderFlags);
389   decoder->SetSurfaceFlags(aSurfaceFlags);
390 
391   // Set an output size for downscale-during-decode if requested.
392   if (aOutputSize) {
393     decoder->SetOutputSize(OrientedIntSize::FromUnknownSize(*aOutputSize));
394   }
395 
396   if (NS_FAILED(decoder->Init())) {
397     return nullptr;
398   }
399 
400   return decoder.forget();
401 }
402 
403 /* static */
CreateAnonymousMetadataDecoder(DecoderType aType,NotNull<SourceBuffer * > aSourceBuffer)404 already_AddRefed<Decoder> DecoderFactory::CreateAnonymousMetadataDecoder(
405     DecoderType aType, NotNull<SourceBuffer*> aSourceBuffer) {
406   if (aType == DecoderType::UNKNOWN) {
407     return nullptr;
408   }
409 
410   RefPtr<Decoder> decoder =
411       GetDecoder(aType, /* aImage = */ nullptr, /* aIsRedecode = */ false);
412   MOZ_ASSERT(decoder, "Should have a decoder now");
413 
414   // Initialize the decoder.
415   decoder->SetMetadataDecode(true);
416   decoder->SetIterator(aSourceBuffer->Iterator());
417   decoder->SetDecoderFlags(DecoderFlags::FIRST_FRAME_ONLY);
418 
419   if (NS_FAILED(decoder->Init())) {
420     return nullptr;
421   }
422 
423   return decoder.forget();
424 }
425 
426 }  // namespace image
427 }  // namespace mozilla
428