DecoderFactory.cpp (15192B)
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 "ImageUtils.h" 9 #include "nsMimeTypes.h" 10 #include "mozilla/RefPtr.h" 11 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" 24 #ifdef MOZ_AV1 25 # include "nsAVIFDecoder.h" 26 #endif 27 #ifdef MOZ_JXL 28 # include "nsJXLDecoder.h" 29 #endif 30 31 namespace mozilla { 32 33 using namespace gfx; 34 35 namespace image { 36 37 /* static */ 38 DecoderType DecoderFactory::GetDecoderType(const char* aMimeType) { 39 // By default we don't know. 40 DecoderType type = DecoderType::UNKNOWN; 41 42 // PNG 43 if (!strcmp(aMimeType, IMAGE_PNG)) { 44 type = DecoderType::PNG; 45 } else if (!strcmp(aMimeType, IMAGE_X_PNG)) { 46 type = DecoderType::PNG; 47 } else if (!strcmp(aMimeType, IMAGE_APNG)) { 48 type = DecoderType::PNG; 49 50 // GIF 51 } else if (!strcmp(aMimeType, IMAGE_GIF)) { 52 type = DecoderType::GIF; 53 54 // JPEG 55 } else if (!strcmp(aMimeType, IMAGE_JPEG)) { 56 type = DecoderType::JPEG; 57 } else if (!strcmp(aMimeType, IMAGE_PJPEG)) { 58 type = DecoderType::JPEG; 59 } else if (!strcmp(aMimeType, IMAGE_JPG)) { 60 type = DecoderType::JPEG; 61 } else if (!strcmp(aMimeType, IMAGE_JPEG_PDF)) { 62 type = DecoderType::JPEG_PDF; 63 64 // BMP 65 } else if (!strcmp(aMimeType, IMAGE_BMP)) { 66 type = DecoderType::BMP; 67 } else if (!strcmp(aMimeType, IMAGE_BMP_MS)) { 68 type = DecoderType::BMP; 69 70 // BMP_CLIPBOARD 71 } else if (!strcmp(aMimeType, IMAGE_BMP_MS_CLIPBOARD)) { 72 type = DecoderType::BMP_CLIPBOARD; 73 74 // ICO 75 } else if (!strcmp(aMimeType, IMAGE_ICO)) { 76 type = DecoderType::ICO; 77 } else if (!strcmp(aMimeType, IMAGE_ICO_MS)) { 78 type = DecoderType::ICO; 79 80 // Icon 81 } else if (!strcmp(aMimeType, IMAGE_ICON_MS)) { 82 type = DecoderType::ICON; 83 84 // WebP 85 } else if (!strcmp(aMimeType, IMAGE_WEBP)) { 86 type = DecoderType::WEBP; 87 88 // AVIF 89 } 90 #ifdef MOZ_AV1 91 else if (!strcmp(aMimeType, IMAGE_AVIF)) { 92 type = DecoderType::AVIF; 93 } 94 #endif 95 #ifdef MOZ_JXL 96 else if (!strcmp(aMimeType, IMAGE_JXL) && StaticPrefs::image_jxl_enabled()) { 97 type = DecoderType::JXL; 98 } 99 #endif 100 101 return type; 102 } 103 104 /* static */ 105 DecoderFlags DecoderFactory::GetDefaultDecoderFlagsForType(DecoderType aType) { 106 auto flags = DefaultDecoderFlags(); 107 108 #ifdef MOZ_AV1 109 if (aType == DecoderType::AVIF) { 110 if (StaticPrefs::image_avif_sequence_enabled()) { 111 flags |= DecoderFlags::AVIF_SEQUENCES_ENABLED; 112 } 113 if (StaticPrefs::image_avif_sequence_animate_avif_major_branded_images()) { 114 flags |= DecoderFlags::AVIF_ANIMATE_AVIF_MAJOR; 115 } 116 } 117 #endif 118 119 return flags; 120 } 121 122 /* static */ 123 already_AddRefed<Decoder> DecoderFactory::GetDecoder(DecoderType aType, 124 RasterImage* aImage, 125 bool aIsRedecode) { 126 RefPtr<Decoder> decoder; 127 128 switch (aType) { 129 case DecoderType::PNG: 130 decoder = new nsPNGDecoder(aImage); 131 break; 132 case DecoderType::GIF: 133 decoder = new nsGIFDecoder2(aImage); 134 break; 135 case DecoderType::JPEG: 136 case DecoderType::JPEG_PDF: 137 // If we have all the data we don't want to waste cpu time doing 138 // a progressive decode. 139 decoder = new nsJPEGDecoder( 140 aImage, aIsRedecode ? Decoder::SEQUENTIAL : Decoder::PROGRESSIVE, 141 aType == DecoderType::JPEG_PDF); 142 break; 143 case DecoderType::BMP: 144 decoder = new nsBMPDecoder(aImage); 145 break; 146 case DecoderType::BMP_CLIPBOARD: 147 decoder = new nsBMPDecoder(aImage, /* aForClipboard */ true); 148 break; 149 case DecoderType::ICO: 150 decoder = new nsICODecoder(aImage); 151 break; 152 case DecoderType::ICON: 153 decoder = new nsIconDecoder(aImage); 154 break; 155 case DecoderType::WEBP: 156 decoder = new nsWebPDecoder(aImage); 157 break; 158 #ifdef MOZ_AV1 159 case DecoderType::AVIF: 160 decoder = new nsAVIFDecoder(aImage); 161 break; 162 #endif 163 #ifdef MOZ_JXL 164 case DecoderType::JXL: 165 decoder = new nsJXLDecoder(aImage); 166 break; 167 #endif 168 default: 169 MOZ_ASSERT_UNREACHABLE("Unknown decoder type"); 170 } 171 172 return decoder.forget(); 173 } 174 175 /* static */ 176 nsresult DecoderFactory::CreateDecoder( 177 DecoderType aType, NotNull<RasterImage*> aImage, 178 NotNull<SourceBuffer*> aSourceBuffer, const IntSize& aIntrinsicSize, 179 const IntSize& aOutputSize, DecoderFlags aDecoderFlags, 180 SurfaceFlags aSurfaceFlags, IDecodingTask** aOutTask) { 181 if (aType == DecoderType::UNKNOWN) { 182 return NS_ERROR_INVALID_ARG; 183 } 184 185 // Only can use COUNT_FRAMES with metadata decoders. 186 if (NS_WARN_IF(bool(aDecoderFlags & DecoderFlags::COUNT_FRAMES))) { 187 return NS_ERROR_INVALID_ARG; 188 } 189 190 // Create an anonymous decoder. Interaction with the SurfaceCache and the 191 // owning RasterImage will be mediated by DecodedSurfaceProvider. 192 RefPtr<Decoder> decoder = GetDecoder( 193 aType, nullptr, bool(aDecoderFlags & DecoderFlags::IS_REDECODE)); 194 MOZ_ASSERT(decoder, "Should have a decoder now"); 195 196 // Initialize the decoder. 197 decoder->SetMetadataDecode(false); 198 decoder->SetIterator(aSourceBuffer->Iterator()); 199 decoder->SetOutputSize(OrientedIntSize::FromUnknownSize(aOutputSize)); 200 decoder->SetDecoderFlags(aDecoderFlags | DecoderFlags::FIRST_FRAME_ONLY); 201 decoder->SetSurfaceFlags(aSurfaceFlags); 202 203 nsresult rv = decoder->Init(); 204 if (NS_FAILED(rv)) { 205 return NS_ERROR_FAILURE; 206 } 207 208 // Create a DecodedSurfaceProvider which will manage the decoding process and 209 // make this decoder's output available in the surface cache. 210 SurfaceKey surfaceKey = 211 RasterSurfaceKey(aOutputSize, aSurfaceFlags, PlaybackType::eStatic); 212 auto provider = MakeNotNull<RefPtr<DecodedSurfaceProvider>>( 213 aImage, surfaceKey, WrapNotNull(decoder)); 214 if (aDecoderFlags & DecoderFlags::CANNOT_SUBSTITUTE) { 215 provider->Availability().SetCannotSubstitute(); 216 } 217 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; 227 } 228 229 // Return the surface provider in its IDecodingTask guise. 230 RefPtr<IDecodingTask> task = provider.get(); 231 task.forget(aOutTask); 232 return NS_OK; 233 } 234 235 /* static */ 236 nsresult DecoderFactory::CreateAnimationDecoder( 237 DecoderType aType, NotNull<RasterImage*> aImage, 238 NotNull<SourceBuffer*> aSourceBuffer, const IntSize& aIntrinsicSize, 239 DecoderFlags aDecoderFlags, SurfaceFlags aSurfaceFlags, 240 size_t aCurrentFrame, IDecodingTask** aOutTask) { 241 if (aType == DecoderType::UNKNOWN) { 242 return NS_ERROR_INVALID_ARG; 243 } 244 245 // Only can use COUNT_FRAMES with metadata decoders. 246 if (NS_WARN_IF(bool(aDecoderFlags & DecoderFlags::COUNT_FRAMES))) { 247 return NS_ERROR_INVALID_ARG; 248 } 249 250 MOZ_ASSERT(aType == DecoderType::GIF || aType == DecoderType::PNG || 251 aType == DecoderType::WEBP || aType == DecoderType::AVIF, 252 "Calling CreateAnimationDecoder for non-animating DecoderType"); 253 254 // Create an anonymous decoder. Interaction with the SurfaceCache and the 255 // owning RasterImage will be mediated by AnimationSurfaceProvider. 256 RefPtr<Decoder> decoder = 257 GetDecoder(aType, nullptr, /* aIsRedecode = */ true); 258 MOZ_ASSERT(decoder, "Should have a decoder now"); 259 260 // Initialize the decoder. 261 decoder->SetMetadataDecode(false); 262 decoder->SetIterator(aSourceBuffer->Iterator()); 263 decoder->SetDecoderFlags(aDecoderFlags | DecoderFlags::IS_REDECODE); 264 decoder->SetSurfaceFlags(aSurfaceFlags); 265 266 nsresult rv = decoder->Init(); 267 if (NS_FAILED(rv)) { 268 return NS_ERROR_FAILURE; 269 } 270 271 // Create an AnimationSurfaceProvider which will manage the decoding process 272 // and make this decoder's output available in the surface cache. 273 SurfaceKey surfaceKey = 274 RasterSurfaceKey(aIntrinsicSize, aSurfaceFlags, PlaybackType::eAnimated); 275 auto provider = MakeNotNull<RefPtr<AnimationSurfaceProvider>>( 276 aImage, surfaceKey, WrapNotNull(decoder), aCurrentFrame); 277 278 // Attempt to insert the surface provider into the surface cache right away so 279 // we won't trigger any more decoders with the same parameters. 280 switch (SurfaceCache::Insert(provider)) { 281 case InsertOutcome::SUCCESS: 282 break; 283 case InsertOutcome::FAILURE_ALREADY_PRESENT: 284 return NS_ERROR_ALREADY_INITIALIZED; 285 default: 286 return NS_ERROR_FAILURE; 287 } 288 289 // Return the surface provider in its IDecodingTask guise. 290 RefPtr<IDecodingTask> task = provider.get(); 291 task.forget(aOutTask); 292 return NS_OK; 293 } 294 295 /* static */ 296 already_AddRefed<Decoder> DecoderFactory::CloneAnimationDecoder( 297 Decoder* aDecoder) { 298 MOZ_ASSERT(aDecoder); 299 300 // In an ideal world, we would assert aDecoder->HasAnimation() but we cannot. 301 // The decoder may not have detected it is animated yet (e.g. it did not even 302 // get scheduled yet, or it has only decoded the first frame and has yet to 303 // rediscover it is animated). 304 DecoderType type = aDecoder->GetType(); 305 MOZ_ASSERT(type == DecoderType::GIF || type == DecoderType::PNG || 306 type == DecoderType::WEBP || type == DecoderType::AVIF, 307 "Calling CloneAnimationDecoder for non-animating DecoderType"); 308 309 RefPtr<Decoder> decoder = GetDecoder(type, nullptr, /* aIsRedecode = */ true); 310 MOZ_ASSERT(decoder, "Should have a decoder now"); 311 312 // Initialize the decoder. 313 decoder->SetMetadataDecode(false); 314 decoder->SetIterator(aDecoder->GetSourceBuffer()->Iterator()); 315 decoder->SetDecoderFlags(aDecoder->GetDecoderFlags()); 316 decoder->SetSurfaceFlags(aDecoder->GetSurfaceFlags()); 317 decoder->SetFrameRecycler(aDecoder->GetFrameRecycler()); 318 319 if (NS_FAILED(decoder->Init())) { 320 return nullptr; 321 } 322 323 return decoder.forget(); 324 } 325 326 /* static */ 327 already_AddRefed<Decoder> DecoderFactory::CloneAnonymousMetadataDecoder( 328 Decoder* aDecoder, const Maybe<DecoderFlags>& aDecoderFlags) { 329 MOZ_ASSERT(aDecoder); 330 331 DecoderType type = aDecoder->GetType(); 332 RefPtr<Decoder> decoder = 333 GetDecoder(type, nullptr, /* aIsRedecode = */ false); 334 MOZ_ASSERT(decoder, "Should have a decoder now"); 335 336 // Initialize the decoder. 337 decoder->SetMetadataDecode(true); 338 decoder->SetIterator(aDecoder->GetSourceBuffer()->Iterator()); 339 if (aDecoderFlags) { 340 decoder->SetDecoderFlags(*aDecoderFlags); 341 } else { 342 decoder->SetDecoderFlags(aDecoder->GetDecoderFlags()); 343 } 344 345 if (NS_FAILED(decoder->Init())) { 346 return nullptr; 347 } 348 349 return decoder.forget(); 350 } 351 352 /* static */ 353 already_AddRefed<IDecodingTask> DecoderFactory::CreateMetadataDecoder( 354 DecoderType aType, NotNull<RasterImage*> aImage, DecoderFlags aFlags, 355 NotNull<SourceBuffer*> aSourceBuffer) { 356 if (aType == DecoderType::UNKNOWN) { 357 return nullptr; 358 } 359 360 RefPtr<Decoder> decoder = 361 GetDecoder(aType, aImage, /* aIsRedecode = */ false); 362 MOZ_ASSERT(decoder, "Should have a decoder now"); 363 364 // Initialize the decoder. 365 decoder->SetMetadataDecode(true); 366 decoder->SetDecoderFlags(aFlags); 367 decoder->SetIterator(aSourceBuffer->Iterator()); 368 369 if (NS_FAILED(decoder->Init())) { 370 return nullptr; 371 } 372 373 RefPtr<IDecodingTask> task = new MetadataDecodingTask(WrapNotNull(decoder)); 374 return task.forget(); 375 } 376 377 /* static */ 378 already_AddRefed<Decoder> DecoderFactory::CreateDecoderForICOResource( 379 DecoderType aType, SourceBufferIterator&& aIterator, 380 NotNull<nsICODecoder*> aICODecoder, bool aIsMetadataDecode, 381 const Maybe<OrientedIntSize>& aExpectedSize, 382 const Maybe<uint32_t>& aDataOffset 383 /* = Nothing() */) { 384 // Create the decoder. 385 RefPtr<Decoder> decoder; 386 switch (aType) { 387 case DecoderType::BMP: 388 MOZ_ASSERT(aDataOffset); 389 decoder = 390 new nsBMPDecoder(aICODecoder->GetImageMaybeNull(), *aDataOffset); 391 break; 392 393 case DecoderType::PNG: 394 MOZ_ASSERT(!aDataOffset); 395 decoder = new nsPNGDecoder(aICODecoder->GetImageMaybeNull()); 396 break; 397 398 default: 399 MOZ_ASSERT_UNREACHABLE("Invalid ICO resource decoder type"); 400 return nullptr; 401 } 402 403 MOZ_ASSERT(decoder); 404 405 // Initialize the decoder, copying settings from @aICODecoder. 406 decoder->SetMetadataDecode(aIsMetadataDecode); 407 decoder->SetIterator(std::forward<SourceBufferIterator>(aIterator)); 408 if (!aIsMetadataDecode) { 409 decoder->SetOutputSize(aICODecoder->OutputSize()); 410 } 411 if (aExpectedSize) { 412 decoder->SetExpectedSize(*aExpectedSize); 413 } 414 decoder->SetDecoderFlags(aICODecoder->GetDecoderFlags()); 415 decoder->SetSurfaceFlags(aICODecoder->GetSurfaceFlags()); 416 decoder->SetFinalizeFrames(false); 417 418 if (NS_FAILED(decoder->Init())) { 419 return nullptr; 420 } 421 422 return decoder.forget(); 423 } 424 425 /* static */ 426 already_AddRefed<Decoder> DecoderFactory::CreateAnonymousDecoder( 427 DecoderType aType, NotNull<SourceBuffer*> aSourceBuffer, 428 const Maybe<IntSize>& aOutputSize, DecoderFlags aDecoderFlags, 429 SurfaceFlags aSurfaceFlags) { 430 if (aType == DecoderType::UNKNOWN) { 431 return nullptr; 432 } 433 434 // Only can use COUNT_FRAMES with metadata decoders. 435 if (NS_WARN_IF(bool(aDecoderFlags & DecoderFlags::COUNT_FRAMES))) { 436 return nullptr; 437 } 438 439 RefPtr<Decoder> decoder = 440 GetDecoder(aType, /* aImage = */ nullptr, /* aIsRedecode = */ false); 441 MOZ_ASSERT(decoder, "Should have a decoder now"); 442 443 // Initialize the decoder. 444 decoder->SetMetadataDecode(false); 445 decoder->SetIterator(aSourceBuffer->Iterator()); 446 447 // Anonymous decoders are always transient; we don't want to optimize surfaces 448 // or do any other expensive work that might be wasted. 449 DecoderFlags decoderFlags = DecoderFlags::IMAGE_IS_TRANSIENT; 450 451 decoder->SetDecoderFlags(aDecoderFlags | decoderFlags); 452 decoder->SetSurfaceFlags(aSurfaceFlags); 453 454 // Set an output size for downscale-during-decode if requested. 455 if (aOutputSize) { 456 decoder->SetOutputSize(OrientedIntSize::FromUnknownSize(*aOutputSize)); 457 } 458 459 if (NS_FAILED(decoder->Init())) { 460 return nullptr; 461 } 462 463 return decoder.forget(); 464 } 465 466 /* static */ 467 already_AddRefed<Decoder> DecoderFactory::CreateAnonymousMetadataDecoder( 468 DecoderType aType, NotNull<SourceBuffer*> aSourceBuffer, 469 DecoderFlags aDecoderFlags) { 470 if (aType == DecoderType::UNKNOWN) { 471 return nullptr; 472 } 473 474 RefPtr<Decoder> decoder = 475 GetDecoder(aType, /* aImage = */ nullptr, /* aIsRedecode = */ false); 476 MOZ_ASSERT(decoder, "Should have a decoder now"); 477 478 // Initialize the decoder. 479 decoder->SetMetadataDecode(true); 480 decoder->SetIterator(aSourceBuffer->Iterator()); 481 decoder->SetDecoderFlags(aDecoderFlags); 482 483 if (NS_FAILED(decoder->Init())) { 484 return nullptr; 485 } 486 487 return decoder.forget(); 488 } 489 490 } // namespace image 491 } // namespace mozilla