Bug 1540028 [wpt PR 16099] - Catch more exceptions in Document-createElement-namespac...
[gecko.git] / image / DecoderFactory.cpp
blob7ad0f39b8654b90f4a5e2910963a8c535d5504e3
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 "gfxPrefs.h"
9 #include "nsMimeTypes.h"
10 #include "mozilla/RefPtr.h"
12 #include "AnimationSurfaceProvider.h"
13 #include "Decoder.h"
14 #include "DecodedSurfaceProvider.h"
15 #include "IDecodingTask.h"
16 #include "ImageOps.h"
17 #include "nsPNGDecoder.h"
18 #include "nsGIFDecoder2.h"
19 #include "nsJPEGDecoder.h"
20 #include "nsBMPDecoder.h"
21 #include "nsICODecoder.h"
22 #include "nsIconDecoder.h"
23 #include "nsWebPDecoder.h"
25 namespace mozilla {
27 using namespace gfx;
29 namespace image {
31 /* static */
32 DecoderType DecoderFactory::GetDecoderType(const char* aMimeType) {
33 // By default we don't know.
34 DecoderType type = DecoderType::UNKNOWN;
36 // PNG
37 if (!strcmp(aMimeType, IMAGE_PNG)) {
38 type = DecoderType::PNG;
39 } else if (!strcmp(aMimeType, IMAGE_X_PNG)) {
40 type = DecoderType::PNG;
41 } else if (!strcmp(aMimeType, IMAGE_APNG)) {
42 type = DecoderType::PNG;
44 // GIF
45 } else if (!strcmp(aMimeType, IMAGE_GIF)) {
46 type = DecoderType::GIF;
48 // JPEG
49 } else if (!strcmp(aMimeType, IMAGE_JPEG)) {
50 type = DecoderType::JPEG;
51 } else if (!strcmp(aMimeType, IMAGE_PJPEG)) {
52 type = DecoderType::JPEG;
53 } else if (!strcmp(aMimeType, IMAGE_JPG)) {
54 type = DecoderType::JPEG;
56 // BMP
57 } else if (!strcmp(aMimeType, IMAGE_BMP)) {
58 type = DecoderType::BMP;
59 } else if (!strcmp(aMimeType, IMAGE_BMP_MS)) {
60 type = DecoderType::BMP;
62 // BMP_CLIPBOARD
63 } else if (!strcmp(aMimeType, IMAGE_BMP_MS_CLIPBOARD)) {
64 type = DecoderType::BMP_CLIPBOARD;
66 // ICO
67 } else if (!strcmp(aMimeType, IMAGE_ICO)) {
68 type = DecoderType::ICO;
69 } else if (!strcmp(aMimeType, IMAGE_ICO_MS)) {
70 type = DecoderType::ICO;
72 // Icon
73 } else if (!strcmp(aMimeType, IMAGE_ICON_MS)) {
74 type = DecoderType::ICON;
76 // WebP
77 } else if (!strcmp(aMimeType, IMAGE_WEBP) && gfxPrefs::ImageWebPEnabled()) {
78 type = DecoderType::WEBP;
81 return type;
84 /* static */
85 already_AddRefed<Decoder> DecoderFactory::GetDecoder(DecoderType aType,
86 RasterImage* aImage,
87 bool aIsRedecode) {
88 RefPtr<Decoder> decoder;
90 switch (aType) {
91 case DecoderType::PNG:
92 decoder = new nsPNGDecoder(aImage);
93 break;
94 case DecoderType::GIF:
95 decoder = new nsGIFDecoder2(aImage);
96 break;
97 case DecoderType::JPEG:
98 // If we have all the data we don't want to waste cpu time doing
99 // a progressive decode.
100 decoder = new nsJPEGDecoder(
101 aImage, aIsRedecode ? Decoder::SEQUENTIAL : Decoder::PROGRESSIVE);
102 break;
103 case DecoderType::BMP:
104 decoder = new nsBMPDecoder(aImage);
105 break;
106 case DecoderType::BMP_CLIPBOARD:
107 decoder = new nsBMPDecoder(aImage, /* aForClipboard */ true);
108 break;
109 case DecoderType::ICO:
110 decoder = new nsICODecoder(aImage);
111 break;
112 case DecoderType::ICON:
113 decoder = new nsIconDecoder(aImage);
114 break;
115 case DecoderType::WEBP:
116 decoder = new nsWebPDecoder(aImage);
117 break;
118 default:
119 MOZ_ASSERT_UNREACHABLE("Unknown decoder type");
122 return decoder.forget();
125 /* static */
126 nsresult DecoderFactory::CreateDecoder(
127 DecoderType aType, NotNull<RasterImage*> aImage,
128 NotNull<SourceBuffer*> aSourceBuffer, const IntSize& aIntrinsicSize,
129 const IntSize& aOutputSize, DecoderFlags aDecoderFlags,
130 SurfaceFlags aSurfaceFlags, IDecodingTask** aOutTask) {
131 if (aType == DecoderType::UNKNOWN) {
132 return NS_ERROR_INVALID_ARG;
135 // Create an anonymous decoder. Interaction with the SurfaceCache and the
136 // owning RasterImage will be mediated by DecodedSurfaceProvider.
137 RefPtr<Decoder> decoder = GetDecoder(
138 aType, nullptr, bool(aDecoderFlags & DecoderFlags::IS_REDECODE));
139 MOZ_ASSERT(decoder, "Should have a decoder now");
141 // Initialize the decoder.
142 decoder->SetMetadataDecode(false);
143 decoder->SetIterator(aSourceBuffer->Iterator());
144 decoder->SetOutputSize(aOutputSize);
145 decoder->SetDecoderFlags(aDecoderFlags | DecoderFlags::FIRST_FRAME_ONLY);
146 decoder->SetSurfaceFlags(aSurfaceFlags);
148 nsresult rv = decoder->Init();
149 if (NS_FAILED(rv)) {
150 return NS_ERROR_FAILURE;
153 // Create a DecodedSurfaceProvider which will manage the decoding process and
154 // make this decoder's output available in the surface cache.
155 SurfaceKey surfaceKey =
156 RasterSurfaceKey(aOutputSize, aSurfaceFlags, PlaybackType::eStatic);
157 auto provider = MakeNotNull<RefPtr<DecodedSurfaceProvider>>(
158 aImage, surfaceKey, WrapNotNull(decoder));
159 if (aDecoderFlags & DecoderFlags::CANNOT_SUBSTITUTE) {
160 provider->Availability().SetCannotSubstitute();
163 // Attempt to insert the surface provider into the surface cache right away so
164 // we won't trigger any more decoders with the same parameters.
165 switch (SurfaceCache::Insert(provider)) {
166 case InsertOutcome::SUCCESS:
167 break;
168 case InsertOutcome::FAILURE_ALREADY_PRESENT:
169 return NS_ERROR_ALREADY_INITIALIZED;
170 default:
171 return NS_ERROR_FAILURE;
174 // Return the surface provider in its IDecodingTask guise.
175 RefPtr<IDecodingTask> task = provider.get();
176 task.forget(aOutTask);
177 return NS_OK;
180 /* static */
181 nsresult DecoderFactory::CreateAnimationDecoder(
182 DecoderType aType, NotNull<RasterImage*> aImage,
183 NotNull<SourceBuffer*> aSourceBuffer, const IntSize& aIntrinsicSize,
184 DecoderFlags aDecoderFlags, SurfaceFlags aSurfaceFlags,
185 size_t aCurrentFrame, IDecodingTask** aOutTask) {
186 if (aType == DecoderType::UNKNOWN) {
187 return NS_ERROR_INVALID_ARG;
190 MOZ_ASSERT(aType == DecoderType::GIF || aType == DecoderType::PNG ||
191 aType == DecoderType::WEBP,
192 "Calling CreateAnimationDecoder for non-animating DecoderType");
194 // Create an anonymous decoder. Interaction with the SurfaceCache and the
195 // owning RasterImage will be mediated by AnimationSurfaceProvider.
196 RefPtr<Decoder> decoder =
197 GetDecoder(aType, nullptr, /* aIsRedecode = */ true);
198 MOZ_ASSERT(decoder, "Should have a decoder now");
200 // Initialize the decoder.
201 decoder->SetMetadataDecode(false);
202 decoder->SetIterator(aSourceBuffer->Iterator());
203 decoder->SetDecoderFlags(aDecoderFlags | DecoderFlags::IS_REDECODE);
204 decoder->SetSurfaceFlags(aSurfaceFlags);
206 nsresult rv = decoder->Init();
207 if (NS_FAILED(rv)) {
208 return NS_ERROR_FAILURE;
211 // Create an AnimationSurfaceProvider which will manage the decoding process
212 // and make this decoder's output available in the surface cache.
213 SurfaceKey surfaceKey =
214 RasterSurfaceKey(aIntrinsicSize, aSurfaceFlags, PlaybackType::eAnimated);
215 auto provider = MakeNotNull<RefPtr<AnimationSurfaceProvider>>(
216 aImage, surfaceKey, WrapNotNull(decoder), aCurrentFrame);
218 // Attempt to insert the surface provider into the surface cache right away so
219 // we won't trigger any more decoders with the same parameters.
220 switch (SurfaceCache::Insert(provider)) {
221 case InsertOutcome::SUCCESS:
222 break;
223 case InsertOutcome::FAILURE_ALREADY_PRESENT:
224 return NS_ERROR_ALREADY_INITIALIZED;
225 default:
226 return NS_ERROR_FAILURE;
229 // Return the surface provider in its IDecodingTask guise.
230 RefPtr<IDecodingTask> task = provider.get();
231 task.forget(aOutTask);
232 return NS_OK;
235 /* static */
236 already_AddRefed<Decoder> DecoderFactory::CloneAnimationDecoder(
237 Decoder* aDecoder) {
238 MOZ_ASSERT(aDecoder);
240 // In an ideal world, we would assert aDecoder->HasAnimation() but we cannot.
241 // The decoder may not have detected it is animated yet (e.g. it did not even
242 // get scheduled yet, or it has only decoded the first frame and has yet to
243 // rediscover it is animated).
244 DecoderType type = aDecoder->GetType();
245 MOZ_ASSERT(type == DecoderType::GIF || type == DecoderType::PNG ||
246 type == DecoderType::WEBP,
247 "Calling CloneAnimationDecoder for non-animating DecoderType");
249 RefPtr<Decoder> decoder = GetDecoder(type, nullptr, /* aIsRedecode = */ true);
250 MOZ_ASSERT(decoder, "Should have a decoder now");
252 // Initialize the decoder.
253 decoder->SetMetadataDecode(false);
254 decoder->SetIterator(aDecoder->GetSourceBuffer()->Iterator());
255 decoder->SetDecoderFlags(aDecoder->GetDecoderFlags());
256 decoder->SetSurfaceFlags(aDecoder->GetSurfaceFlags());
257 decoder->SetFrameRecycler(aDecoder->GetFrameRecycler());
259 if (NS_FAILED(decoder->Init())) {
260 return nullptr;
263 return decoder.forget();
266 /* static */
267 already_AddRefed<IDecodingTask> DecoderFactory::CreateMetadataDecoder(
268 DecoderType aType, NotNull<RasterImage*> aImage,
269 NotNull<SourceBuffer*> aSourceBuffer) {
270 if (aType == DecoderType::UNKNOWN) {
271 return nullptr;
274 RefPtr<Decoder> decoder =
275 GetDecoder(aType, aImage, /* aIsRedecode = */ false);
276 MOZ_ASSERT(decoder, "Should have a decoder now");
278 // Initialize the decoder.
279 decoder->SetMetadataDecode(true);
280 decoder->SetIterator(aSourceBuffer->Iterator());
282 if (NS_FAILED(decoder->Init())) {
283 return nullptr;
286 RefPtr<IDecodingTask> task = new MetadataDecodingTask(WrapNotNull(decoder));
287 return task.forget();
290 /* static */
291 already_AddRefed<Decoder> DecoderFactory::CreateDecoderForICOResource(
292 DecoderType aType, SourceBufferIterator&& aIterator,
293 NotNull<nsICODecoder*> aICODecoder, bool aIsMetadataDecode,
294 const Maybe<IntSize>& aExpectedSize, const Maybe<uint32_t>& aDataOffset
295 /* = Nothing() */) {
296 // Create the decoder.
297 RefPtr<Decoder> decoder;
298 switch (aType) {
299 case DecoderType::BMP:
300 MOZ_ASSERT(aDataOffset);
301 decoder =
302 new nsBMPDecoder(aICODecoder->GetImageMaybeNull(), *aDataOffset);
303 break;
305 case DecoderType::PNG:
306 MOZ_ASSERT(!aDataOffset);
307 decoder = new nsPNGDecoder(aICODecoder->GetImageMaybeNull());
308 break;
310 default:
311 MOZ_ASSERT_UNREACHABLE("Invalid ICO resource decoder type");
312 return nullptr;
315 MOZ_ASSERT(decoder);
317 // Initialize the decoder, copying settings from @aICODecoder.
318 decoder->SetMetadataDecode(aIsMetadataDecode);
319 decoder->SetIterator(std::forward<SourceBufferIterator>(aIterator));
320 if (!aIsMetadataDecode) {
321 decoder->SetOutputSize(aICODecoder->OutputSize());
323 if (aExpectedSize) {
324 decoder->SetExpectedSize(*aExpectedSize);
326 decoder->SetDecoderFlags(aICODecoder->GetDecoderFlags());
327 decoder->SetSurfaceFlags(aICODecoder->GetSurfaceFlags());
328 decoder->SetFinalizeFrames(false);
330 if (NS_FAILED(decoder->Init())) {
331 return nullptr;
334 return decoder.forget();
337 /* static */
338 already_AddRefed<Decoder> DecoderFactory::CreateAnonymousDecoder(
339 DecoderType aType, NotNull<SourceBuffer*> aSourceBuffer,
340 const Maybe<IntSize>& aOutputSize, DecoderFlags aDecoderFlags,
341 SurfaceFlags aSurfaceFlags) {
342 if (aType == DecoderType::UNKNOWN) {
343 return nullptr;
346 RefPtr<Decoder> decoder =
347 GetDecoder(aType, /* aImage = */ nullptr, /* aIsRedecode = */ false);
348 MOZ_ASSERT(decoder, "Should have a decoder now");
350 // Initialize the decoder.
351 decoder->SetMetadataDecode(false);
352 decoder->SetIterator(aSourceBuffer->Iterator());
354 // Anonymous decoders are always transient; we don't want to optimize surfaces
355 // or do any other expensive work that might be wasted.
356 DecoderFlags decoderFlags = DecoderFlags::IMAGE_IS_TRANSIENT;
358 decoder->SetDecoderFlags(aDecoderFlags | decoderFlags);
359 decoder->SetSurfaceFlags(aSurfaceFlags);
361 // Set an output size for downscale-during-decode if requested.
362 if (aOutputSize) {
363 decoder->SetOutputSize(*aOutputSize);
366 if (NS_FAILED(decoder->Init())) {
367 return nullptr;
370 return decoder.forget();
373 /* static */
374 already_AddRefed<Decoder> DecoderFactory::CreateAnonymousMetadataDecoder(
375 DecoderType aType, NotNull<SourceBuffer*> aSourceBuffer) {
376 if (aType == DecoderType::UNKNOWN) {
377 return nullptr;
380 RefPtr<Decoder> decoder =
381 GetDecoder(aType, /* aImage = */ nullptr, /* aIsRedecode = */ false);
382 MOZ_ASSERT(decoder, "Should have a decoder now");
384 // Initialize the decoder.
385 decoder->SetMetadataDecode(true);
386 decoder->SetIterator(aSourceBuffer->Iterator());
387 decoder->SetDecoderFlags(DecoderFlags::FIRST_FRAME_ONLY);
389 if (NS_FAILED(decoder->Init())) {
390 return nullptr;
393 return decoder.forget();
396 } // namespace image
397 } // namespace mozilla