Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/image/test/gtest/TestDecoders.cpp
Line
Count
Source (jump to first uncovered line)
1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
 * License, v. 2.0. If a copy of the MPL was not distributed with this
3
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5
#include "gtest/gtest.h"
6
7
#include "Common.h"
8
#include "AnimationSurfaceProvider.h"
9
#include "Decoder.h"
10
#include "DecoderFactory.h"
11
#include "decoders/nsBMPDecoder.h"
12
#include "IDecodingTask.h"
13
#include "ImageOps.h"
14
#include "imgIContainer.h"
15
#include "imgITools.h"
16
#include "ImageFactory.h"
17
#include "mozilla/gfx/2D.h"
18
#include "nsComponentManagerUtils.h"
19
#include "nsCOMPtr.h"
20
#include "nsIInputStream.h"
21
#include "nsIRunnable.h"
22
#include "nsIThread.h"
23
#include "mozilla/RefPtr.h"
24
#include "nsStreamUtils.h"
25
#include "nsString.h"
26
#include "nsThreadUtils.h"
27
#include "ProgressTracker.h"
28
#include "SourceBuffer.h"
29
30
using namespace mozilla;
31
using namespace mozilla::gfx;
32
using namespace mozilla::image;
33
34
static already_AddRefed<SourceSurface>
35
CheckDecoderState(const ImageTestCase& aTestCase, Decoder* aDecoder)
36
0
{
37
0
  EXPECT_TRUE(aDecoder->GetDecodeDone());
38
0
  EXPECT_EQ(bool(aTestCase.mFlags & TEST_CASE_HAS_ERROR),
39
0
            aDecoder->HasError());
40
0
41
0
  // Verify that the decoder made the expected progress.
42
0
  Progress progress = aDecoder->TakeProgress();
43
0
  EXPECT_EQ(bool(aTestCase.mFlags & TEST_CASE_HAS_ERROR),
44
0
            bool(progress & FLAG_HAS_ERROR));
45
0
46
0
  if (aTestCase.mFlags & TEST_CASE_HAS_ERROR) {
47
0
    return nullptr;  // That's all we can check for bad images.
48
0
  }
49
0
50
0
  EXPECT_TRUE(bool(progress & FLAG_SIZE_AVAILABLE));
51
0
  EXPECT_TRUE(bool(progress & FLAG_DECODE_COMPLETE));
52
0
  EXPECT_TRUE(bool(progress & FLAG_FRAME_COMPLETE));
53
0
  EXPECT_EQ(bool(aTestCase.mFlags & TEST_CASE_IS_TRANSPARENT),
54
0
            bool(progress & FLAG_HAS_TRANSPARENCY));
55
0
  EXPECT_EQ(bool(aTestCase.mFlags & TEST_CASE_IS_ANIMATED),
56
0
            bool(progress & FLAG_IS_ANIMATED));
57
0
58
0
  // The decoder should get the correct size.
59
0
  IntSize size = aDecoder->Size();
60
0
  EXPECT_EQ(aTestCase.mSize.width, size.width);
61
0
  EXPECT_EQ(aTestCase.mSize.height, size.height);
62
0
63
0
  // Get the current frame, which is always the first frame of the image
64
0
  // because CreateAnonymousDecoder() forces a first-frame-only decode.
65
0
  RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
66
0
  RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
67
0
68
0
  // Verify that the resulting surfaces matches our expectations.
69
0
  EXPECT_TRUE(surface->IsDataSourceSurface());
70
0
  EXPECT_TRUE(surface->GetFormat() == SurfaceFormat::B8G8R8X8 ||
71
0
              surface->GetFormat() == SurfaceFormat::B8G8R8A8);
72
0
  EXPECT_EQ(aTestCase.mOutputSize, surface->GetSize());
73
0
74
0
  return surface.forget();
75
0
}
76
77
static void
78
CheckDecoderResults(const ImageTestCase& aTestCase, Decoder* aDecoder)
79
0
{
80
0
  RefPtr<SourceSurface> surface = CheckDecoderState(aTestCase, aDecoder);
81
0
  if (!surface) {
82
0
    return;
83
0
  }
84
0
85
0
  if (aTestCase.mFlags & TEST_CASE_IGNORE_OUTPUT) {
86
0
    return;
87
0
  }
88
0
89
0
  // Check the output.
90
0
  EXPECT_TRUE(IsSolidColor(surface, BGRAColor::Green(),
91
0
                           aTestCase.mFlags & TEST_CASE_IS_FUZZY ? 1 : 0));
92
0
}
93
94
template <typename Func>
95
void WithSingleChunkDecode(const ImageTestCase& aTestCase,
96
                           const Maybe<IntSize>& aOutputSize,
97
                           Func aResultChecker)
98
0
{
99
0
  nsCOMPtr<nsIInputStream> inputStream = LoadFile(aTestCase.mPath);
100
0
  ASSERT_TRUE(inputStream != nullptr);
101
0
102
0
  // Figure out how much data we have.
103
0
  uint64_t length;
104
0
  nsresult rv = inputStream->Available(&length);
105
0
  ASSERT_TRUE(NS_SUCCEEDED(rv));
106
0
107
0
  // Write the data into a SourceBuffer.
108
0
  auto sourceBuffer = MakeNotNull<RefPtr<SourceBuffer>>();
109
0
  sourceBuffer->ExpectLength(length);
110
0
  rv = sourceBuffer->AppendFromInputStream(inputStream, length);
111
0
  ASSERT_TRUE(NS_SUCCEEDED(rv));
112
0
  sourceBuffer->Complete(NS_OK);
113
0
114
0
  // Create a decoder.
115
0
  DecoderType decoderType =
116
0
    DecoderFactory::GetDecoderType(aTestCase.mMimeType);
117
0
  RefPtr<Decoder> decoder =
118
0
    DecoderFactory::CreateAnonymousDecoder(decoderType, sourceBuffer, aOutputSize,
119
0
                                           DecoderFlags::FIRST_FRAME_ONLY,
120
0
                                           DefaultSurfaceFlags());
121
0
  ASSERT_TRUE(decoder != nullptr);
122
0
  RefPtr<IDecodingTask> task = new AnonymousDecodingTask(WrapNotNull(decoder));
123
0
124
0
  // Run the full decoder synchronously.
125
0
  task->Run();
126
0
127
0
  // Call the lambda to verify the expected results.
128
0
  aResultChecker(decoder);
129
0
}
Unexecuted instantiation: Unified_cpp_image_test_gtest0.cpp:void WithSingleChunkDecode<CheckDecoderSingleChunk(mozilla::image::ImageTestCase const&)::$_88>(mozilla::image::ImageTestCase const&, mozilla::Maybe<mozilla::gfx::IntSizeTyped<mozilla::gfx::UnknownUnits> > const&, CheckDecoderSingleChunk(mozilla::image::ImageTestCase const&)::$_88)
Unexecuted instantiation: Unified_cpp_image_test_gtest0.cpp:void WithSingleChunkDecode<CheckDownscaleDuringDecode(mozilla::image::ImageTestCase const&)::$_89>(mozilla::image::ImageTestCase const&, mozilla::Maybe<mozilla::gfx::IntSizeTyped<mozilla::gfx::UnknownUnits> > const&, CheckDownscaleDuringDecode(mozilla::image::ImageTestCase const&)::$_89)
130
131
static void
132
CheckDecoderSingleChunk(const ImageTestCase& aTestCase)
133
0
{
134
0
  WithSingleChunkDecode(aTestCase, Nothing(), [&](Decoder* aDecoder) {
135
0
    CheckDecoderResults(aTestCase, aDecoder);
136
0
  });
137
0
}
138
139
static void
140
CheckDecoderMultiChunk(const ImageTestCase& aTestCase)
141
0
{
142
0
  nsCOMPtr<nsIInputStream> inputStream = LoadFile(aTestCase.mPath);
143
0
  ASSERT_TRUE(inputStream != nullptr);
144
0
145
0
  // Figure out how much data we have.
146
0
  uint64_t length;
147
0
  nsresult rv = inputStream->Available(&length);
148
0
  ASSERT_TRUE(NS_SUCCEEDED(rv));
149
0
150
0
  // Create a SourceBuffer and a decoder.
151
0
  auto sourceBuffer = MakeNotNull<RefPtr<SourceBuffer>>();
152
0
  sourceBuffer->ExpectLength(length);
153
0
  DecoderType decoderType =
154
0
    DecoderFactory::GetDecoderType(aTestCase.mMimeType);
155
0
  RefPtr<Decoder> decoder =
156
0
    DecoderFactory::CreateAnonymousDecoder(decoderType, sourceBuffer, Nothing(),
157
0
                                           DecoderFlags::FIRST_FRAME_ONLY,
158
0
                                           DefaultSurfaceFlags());
159
0
  ASSERT_TRUE(decoder != nullptr);
160
0
  RefPtr<IDecodingTask> task = new AnonymousDecodingTask(WrapNotNull(decoder));
161
0
162
0
  for (uint64_t read = 0; read < length ; ++read) {
163
0
    uint64_t available = 0;
164
0
    rv = inputStream->Available(&available);
165
0
    ASSERT_TRUE(available > 0);
166
0
    ASSERT_TRUE(NS_SUCCEEDED(rv));
167
0
168
0
    rv = sourceBuffer->AppendFromInputStream(inputStream, 1);
169
0
    ASSERT_TRUE(NS_SUCCEEDED(rv));
170
0
171
0
    task->Run();
172
0
  }
173
0
174
0
  sourceBuffer->Complete(NS_OK);
175
0
  task->Run();
176
0
177
0
  CheckDecoderResults(aTestCase, decoder);
178
0
}
179
180
static void
181
CheckDownscaleDuringDecode(const ImageTestCase& aTestCase)
182
0
{
183
0
  // This function expects that |aTestCase| consists of 25 lines of green,
184
0
  // followed by 25 lines of red, followed by 25 lines of green, followed by 25
185
0
  // more lines of red. We'll downscale it from 100x100 to 20x20.
186
0
  IntSize outputSize(20, 20);
187
0
188
0
  WithSingleChunkDecode(aTestCase, Some(outputSize), [&](Decoder* aDecoder) {
189
0
    RefPtr<SourceSurface> surface = CheckDecoderState(aTestCase, aDecoder);
190
0
191
0
    // There are no downscale-during-decode tests that have TEST_CASE_HAS_ERROR
192
0
    // set, so we expect to always get a surface here.
193
0
    EXPECT_TRUE(surface != nullptr);
194
0
195
0
    if (aTestCase.mFlags & TEST_CASE_IGNORE_OUTPUT) {
196
0
      return;
197
0
    }
198
0
199
0
    // Check that the downscaled image is correct. Note that we skip rows near
200
0
    // the transitions between colors, since the downscaler does not produce a
201
0
    // sharp boundary at these points. Even some of the rows we test need a
202
0
    // small amount of fuzz; this is just the nature of Lanczos downscaling.
203
0
    EXPECT_TRUE(RowsAreSolidColor(surface, 0, 4, BGRAColor::Green(), /* aFuzz = */ 47));
204
0
    EXPECT_TRUE(RowsAreSolidColor(surface, 6, 3, BGRAColor::Red(), /* aFuzz = */ 27));
205
0
    EXPECT_TRUE(RowsAreSolidColor(surface, 11, 3, BGRAColor::Green(), /* aFuzz = */ 47));
206
0
    EXPECT_TRUE(RowsAreSolidColor(surface, 16, 4, BGRAColor::Red(), /* aFuzz = */ 27));
207
0
  });
208
0
}
209
210
static void
211
CheckAnimationDecoderResults(const ImageTestCase& aTestCase,
212
                             AnimationSurfaceProvider* aProvider,
213
                             Decoder* aDecoder)
214
0
{
215
0
  EXPECT_TRUE(aDecoder->GetDecodeDone());
216
0
  EXPECT_EQ(bool(aTestCase.mFlags & TEST_CASE_HAS_ERROR),
217
0
            aDecoder->HasError());
218
0
219
0
  if (aTestCase.mFlags & TEST_CASE_HAS_ERROR) {
220
0
    return;  // That's all we can check for bad images.
221
0
  }
222
0
223
0
  // The decoder should get the correct size.
224
0
  IntSize size = aDecoder->Size();
225
0
  EXPECT_EQ(aTestCase.mSize.width, size.width);
226
0
  EXPECT_EQ(aTestCase.mSize.height, size.height);
227
0
228
0
  if (aTestCase.mFlags & TEST_CASE_IGNORE_OUTPUT) {
229
0
    return;
230
0
  }
231
0
232
0
  // Check the output.
233
0
  AutoTArray<BGRAColor, 2> framePixels;
234
0
  framePixels.AppendElement(BGRAColor::Green());
235
0
  framePixels.AppendElement(BGRAColor(0x7F, 0x7F, 0x7F, 0xFF));
236
0
237
0
  DrawableSurface drawableSurface(WrapNotNull(aProvider));
238
0
  for (size_t i = 0; i < framePixels.Length(); ++i) {
239
0
    nsresult rv = drawableSurface.Seek(i);
240
0
    EXPECT_TRUE(NS_SUCCEEDED(rv));
241
0
242
0
    // Check the first frame, all green.
243
0
    RawAccessFrameRef rawFrame = drawableSurface->RawAccessRef();
244
0
    RefPtr<SourceSurface> surface = rawFrame->GetSourceSurface();
245
0
246
0
    // Verify that the resulting surfaces matches our expectations.
247
0
    EXPECT_TRUE(surface->IsDataSourceSurface());
248
0
    EXPECT_TRUE(surface->GetFormat() == SurfaceFormat::B8G8R8X8 ||
249
0
                surface->GetFormat() == SurfaceFormat::B8G8R8A8);
250
0
    EXPECT_EQ(aTestCase.mOutputSize, surface->GetSize());
251
0
    EXPECT_TRUE(IsSolidColor(surface, framePixels[i],
252
0
                             aTestCase.mFlags & TEST_CASE_IS_FUZZY ? 1 : 0));
253
0
  }
254
0
255
0
  // Should be no more frames.
256
0
  nsresult rv = drawableSurface.Seek(framePixels.Length());
257
0
  EXPECT_TRUE(NS_FAILED(rv));
258
0
}
259
260
template <typename Func>
261
static void
262
WithSingleChunkAnimationDecode(const ImageTestCase& aTestCase,
263
                               Func aResultChecker)
264
0
{
265
0
  // Create an image.
266
0
  RefPtr<Image> image =
267
0
    ImageFactory::CreateAnonymousImage(nsDependentCString(aTestCase.mMimeType));
268
0
  ASSERT_TRUE(!image->HasError());
269
0
270
0
  NotNull<RefPtr<RasterImage>> rasterImage =
271
0
    WrapNotNull(static_cast<RasterImage*>(image.get()));
272
0
273
0
  nsCOMPtr<nsIInputStream> inputStream = LoadFile(aTestCase.mPath);
274
0
  ASSERT_TRUE(inputStream != nullptr);
275
0
276
0
  // Figure out how much data we have.
277
0
  uint64_t length;
278
0
  nsresult rv = inputStream->Available(&length);
279
0
  ASSERT_TRUE(NS_SUCCEEDED(rv));
280
0
281
0
  // Write the data into a SourceBuffer.
282
0
  NotNull<RefPtr<SourceBuffer>> sourceBuffer = WrapNotNull(new SourceBuffer());
283
0
  sourceBuffer->ExpectLength(length);
284
0
  rv = sourceBuffer->AppendFromInputStream(inputStream, length);
285
0
  ASSERT_TRUE(NS_SUCCEEDED(rv));
286
0
  sourceBuffer->Complete(NS_OK);
287
0
288
0
  // Create a metadata decoder first, because otherwise RasterImage will get
289
0
  // unhappy about finding out the image is animated during a full decode.
290
0
  DecoderType decoderType =
291
0
    DecoderFactory::GetDecoderType(aTestCase.mMimeType);
292
0
  RefPtr<IDecodingTask> task =
293
0
    DecoderFactory::CreateMetadataDecoder(decoderType, rasterImage, sourceBuffer);
294
0
  ASSERT_TRUE(task != nullptr);
295
0
296
0
  // Run the metadata decoder synchronously.
297
0
  task->Run();
298
0
299
0
  // Create a decoder.
300
0
  DecoderFlags decoderFlags = DecoderFlags::BLEND_ANIMATION;
301
0
  SurfaceFlags surfaceFlags = DefaultSurfaceFlags();
302
0
  RefPtr<Decoder> decoder =
303
0
    DecoderFactory::CreateAnonymousDecoder(decoderType, sourceBuffer, Nothing(),
304
0
                                           decoderFlags, surfaceFlags);
305
0
  ASSERT_TRUE(decoder != nullptr);
306
0
307
0
  // Create an AnimationSurfaceProvider which will manage the decoding process
308
0
  // and make this decoder's output available in the surface cache.
309
0
  SurfaceKey surfaceKey =
310
0
    RasterSurfaceKey(aTestCase.mOutputSize, surfaceFlags, PlaybackType::eAnimated);
311
0
  RefPtr<AnimationSurfaceProvider> provider =
312
0
    new AnimationSurfaceProvider(rasterImage,
313
0
                                 surfaceKey,
314
0
                                 WrapNotNull(decoder),
315
0
                                 /* aCurrentFrame */ 0);
316
0
317
0
  // Run the full decoder synchronously.
318
0
  provider->Run();
319
0
320
0
  // Call the lambda to verify the expected results.
321
0
  aResultChecker(provider, decoder);
322
0
}
323
324
static void
325
CheckAnimationDecoderSingleChunk(const ImageTestCase& aTestCase)
326
0
{
327
0
  WithSingleChunkAnimationDecode(aTestCase, [&](AnimationSurfaceProvider* aProvider, Decoder* aDecoder) {
328
0
    CheckAnimationDecoderResults(aTestCase, aProvider, aDecoder);
329
0
  });
330
0
}
331
332
class ImageDecoders : public ::testing::Test
333
{
334
protected:
335
  AutoInitializeImageLib mInit;
336
};
337
338
TEST_F(ImageDecoders, PNGSingleChunk)
339
0
{
340
0
  CheckDecoderSingleChunk(GreenPNGTestCase());
341
0
}
342
343
TEST_F(ImageDecoders, PNGMultiChunk)
344
0
{
345
0
  CheckDecoderMultiChunk(GreenPNGTestCase());
346
0
}
347
348
TEST_F(ImageDecoders, PNGDownscaleDuringDecode)
349
0
{
350
0
  CheckDownscaleDuringDecode(DownscaledPNGTestCase());
351
0
}
352
353
TEST_F(ImageDecoders, GIFSingleChunk)
354
0
{
355
0
  CheckDecoderSingleChunk(GreenGIFTestCase());
356
0
}
357
358
TEST_F(ImageDecoders, GIFMultiChunk)
359
0
{
360
0
  CheckDecoderMultiChunk(GreenGIFTestCase());
361
0
}
362
363
TEST_F(ImageDecoders, GIFDownscaleDuringDecode)
364
0
{
365
0
  CheckDownscaleDuringDecode(DownscaledGIFTestCase());
366
0
}
367
368
TEST_F(ImageDecoders, JPGSingleChunk)
369
0
{
370
0
  CheckDecoderSingleChunk(GreenJPGTestCase());
371
0
}
372
373
TEST_F(ImageDecoders, JPGMultiChunk)
374
0
{
375
0
  CheckDecoderMultiChunk(GreenJPGTestCase());
376
0
}
377
378
TEST_F(ImageDecoders, JPGDownscaleDuringDecode)
379
0
{
380
0
  CheckDownscaleDuringDecode(DownscaledJPGTestCase());
381
0
}
382
383
TEST_F(ImageDecoders, BMPSingleChunk)
384
0
{
385
0
  CheckDecoderSingleChunk(GreenBMPTestCase());
386
0
}
387
388
TEST_F(ImageDecoders, BMPMultiChunk)
389
0
{
390
0
  CheckDecoderMultiChunk(GreenBMPTestCase());
391
0
}
392
393
TEST_F(ImageDecoders, BMPDownscaleDuringDecode)
394
0
{
395
0
  CheckDownscaleDuringDecode(DownscaledBMPTestCase());
396
0
}
397
398
TEST_F(ImageDecoders, ICOSingleChunk)
399
0
{
400
0
  CheckDecoderSingleChunk(GreenICOTestCase());
401
0
}
402
403
TEST_F(ImageDecoders, ICOMultiChunk)
404
0
{
405
0
  CheckDecoderMultiChunk(GreenICOTestCase());
406
0
}
407
408
TEST_F(ImageDecoders, ICODownscaleDuringDecode)
409
0
{
410
0
  CheckDownscaleDuringDecode(DownscaledICOTestCase());
411
0
}
412
413
TEST_F(ImageDecoders, ICOWithANDMaskDownscaleDuringDecode)
414
0
{
415
0
  CheckDownscaleDuringDecode(DownscaledTransparentICOWithANDMaskTestCase());
416
0
}
417
418
TEST_F(ImageDecoders, IconSingleChunk)
419
0
{
420
0
  CheckDecoderSingleChunk(GreenIconTestCase());
421
0
}
422
423
TEST_F(ImageDecoders, IconMultiChunk)
424
0
{
425
0
  CheckDecoderMultiChunk(GreenIconTestCase());
426
0
}
427
428
TEST_F(ImageDecoders, IconDownscaleDuringDecode)
429
0
{
430
0
  CheckDownscaleDuringDecode(DownscaledIconTestCase());
431
0
}
432
433
TEST_F(ImageDecoders, AnimatedGIFSingleChunk)
434
0
{
435
0
  CheckDecoderSingleChunk(GreenFirstFrameAnimatedGIFTestCase());
436
0
}
437
438
TEST_F(ImageDecoders, AnimatedGIFMultiChunk)
439
0
{
440
0
  CheckDecoderMultiChunk(GreenFirstFrameAnimatedGIFTestCase());
441
0
}
442
443
TEST_F(ImageDecoders, AnimatedGIFWithBlendedFrames)
444
0
{
445
0
  CheckAnimationDecoderSingleChunk(GreenFirstFrameAnimatedGIFTestCase());
446
0
}
447
448
TEST_F(ImageDecoders, AnimatedPNGSingleChunk)
449
0
{
450
0
  CheckDecoderSingleChunk(GreenFirstFrameAnimatedPNGTestCase());
451
0
}
452
453
TEST_F(ImageDecoders, AnimatedPNGMultiChunk)
454
0
{
455
0
  CheckDecoderMultiChunk(GreenFirstFrameAnimatedPNGTestCase());
456
0
}
457
458
TEST_F(ImageDecoders, AnimatedPNGWithBlendedFrames)
459
0
{
460
0
  CheckAnimationDecoderSingleChunk(GreenFirstFrameAnimatedPNGTestCase());
461
0
}
462
463
TEST_F(ImageDecoders, CorruptSingleChunk)
464
0
{
465
0
  CheckDecoderSingleChunk(CorruptTestCase());
466
0
}
467
468
TEST_F(ImageDecoders, CorruptMultiChunk)
469
0
{
470
0
  CheckDecoderMultiChunk(CorruptTestCase());
471
0
}
472
473
TEST_F(ImageDecoders, CorruptBMPWithTruncatedHeaderSingleChunk)
474
0
{
475
0
  CheckDecoderSingleChunk(CorruptBMPWithTruncatedHeader());
476
0
}
477
478
TEST_F(ImageDecoders, CorruptBMPWithTruncatedHeaderMultiChunk)
479
0
{
480
0
  CheckDecoderMultiChunk(CorruptBMPWithTruncatedHeader());
481
0
}
482
483
TEST_F(ImageDecoders, CorruptICOWithBadBMPWidthSingleChunk)
484
0
{
485
0
  CheckDecoderSingleChunk(CorruptICOWithBadBMPWidthTestCase());
486
0
}
487
488
TEST_F(ImageDecoders, CorruptICOWithBadBMPWidthMultiChunk)
489
0
{
490
0
  CheckDecoderMultiChunk(CorruptICOWithBadBMPWidthTestCase());
491
0
}
492
493
TEST_F(ImageDecoders, CorruptICOWithBadBMPHeightSingleChunk)
494
0
{
495
0
  CheckDecoderSingleChunk(CorruptICOWithBadBMPHeightTestCase());
496
0
}
497
498
TEST_F(ImageDecoders, CorruptICOWithBadBMPHeightMultiChunk)
499
0
{
500
0
  CheckDecoderMultiChunk(CorruptICOWithBadBMPHeightTestCase());
501
0
}
502
503
TEST_F(ImageDecoders, CorruptICOWithBadBppSingleChunk)
504
0
{
505
0
  CheckDecoderSingleChunk(CorruptICOWithBadBppTestCase());
506
0
}
507
508
TEST_F(ImageDecoders, AnimatedGIFWithFRAME_FIRST)
509
0
{
510
0
  ImageTestCase testCase = GreenFirstFrameAnimatedGIFTestCase();
511
0
512
0
  // Verify that we can decode this test case and retrieve the first frame using
513
0
  // imgIContainer::FRAME_FIRST. This ensures that we correctly trigger a
514
0
  // single-frame decode rather than an animated decode when
515
0
  // imgIContainer::FRAME_FIRST is requested.
516
0
517
0
  // Create an image.
518
0
  RefPtr<Image> image =
519
0
    ImageFactory::CreateAnonymousImage(nsDependentCString(testCase.mMimeType));
520
0
  ASSERT_TRUE(!image->HasError());
521
0
522
0
  nsCOMPtr<nsIInputStream> inputStream = LoadFile(testCase.mPath);
523
0
  ASSERT_TRUE(inputStream);
524
0
525
0
  // Figure out how much data we have.
526
0
  uint64_t length;
527
0
  nsresult rv = inputStream->Available(&length);
528
0
  ASSERT_TRUE(NS_SUCCEEDED(rv));
529
0
530
0
  // Write the data into the image.
531
0
  rv = image->OnImageDataAvailable(nullptr, nullptr, inputStream, 0,
532
0
                                   static_cast<uint32_t>(length));
533
0
  ASSERT_TRUE(NS_SUCCEEDED(rv));
534
0
535
0
  // Let the image know we've sent all the data.
536
0
  rv = image->OnImageDataComplete(nullptr, nullptr, NS_OK, true);
537
0
  ASSERT_TRUE(NS_SUCCEEDED(rv));
538
0
539
0
  RefPtr<ProgressTracker> tracker = image->GetProgressTracker();
540
0
  tracker->SyncNotifyProgress(FLAG_LOAD_COMPLETE);
541
0
542
0
  // Lock the image so its surfaces don't disappear during the test.
543
0
  image->LockImage();
544
0
545
0
  auto unlock = mozilla::MakeScopeExit([&] {
546
0
    image->UnlockImage();
547
0
  });
548
0
549
0
  // Use GetFrame() to force a sync decode of the image, specifying FRAME_FIRST
550
0
  // to ensure that we don't get an animated decode.
551
0
  RefPtr<SourceSurface> surface =
552
0
    image->GetFrame(imgIContainer::FRAME_FIRST,
553
0
                    imgIContainer::FLAG_SYNC_DECODE);
554
0
555
0
  // Ensure that the image's metadata meets our expectations.
556
0
  IntSize imageSize(0, 0);
557
0
  rv = image->GetWidth(&imageSize.width);
558
0
  EXPECT_TRUE(NS_SUCCEEDED(rv));
559
0
  rv = image->GetHeight(&imageSize.height);
560
0
  EXPECT_TRUE(NS_SUCCEEDED(rv));
561
0
562
0
  EXPECT_EQ(testCase.mSize.width, imageSize.width);
563
0
  EXPECT_EQ(testCase.mSize.height, imageSize.height);
564
0
565
0
  Progress imageProgress = tracker->GetProgress();
566
0
567
0
  EXPECT_TRUE(bool(imageProgress & FLAG_HAS_TRANSPARENCY) == false);
568
0
  EXPECT_TRUE(bool(imageProgress & FLAG_IS_ANIMATED) == true);
569
0
570
0
  // Ensure that we decoded the static version of the image.
571
0
  {
572
0
    LookupResult result =
573
0
      SurfaceCache::Lookup(ImageKey(image.get()),
574
0
                           RasterSurfaceKey(imageSize,
575
0
                                            DefaultSurfaceFlags(),
576
0
                                            PlaybackType::eStatic));
577
0
    ASSERT_EQ(MatchType::EXACT, result.Type());
578
0
    EXPECT_TRUE(bool(result.Surface()));
579
0
  }
580
0
581
0
  // Ensure that we didn't decode the animated version of the image.
582
0
  {
583
0
    LookupResult result =
584
0
      SurfaceCache::Lookup(ImageKey(image.get()),
585
0
                           RasterSurfaceKey(imageSize,
586
0
                                            DefaultSurfaceFlags(),
587
0
                                            PlaybackType::eAnimated));
588
0
    ASSERT_EQ(MatchType::NOT_FOUND, result.Type());
589
0
  }
590
0
591
0
  // Use GetFrame() to force a sync decode of the image, this time specifying
592
0
  // FRAME_CURRENT to ensure that we get an animated decode.
593
0
  RefPtr<SourceSurface> animatedSurface =
594
0
    image->GetFrame(imgIContainer::FRAME_CURRENT,
595
0
                    imgIContainer::FLAG_SYNC_DECODE);
596
0
597
0
  // Ensure that we decoded both frames of the animated version of the image.
598
0
  {
599
0
    LookupResult result =
600
0
      SurfaceCache::Lookup(ImageKey(image.get()),
601
0
                           RasterSurfaceKey(imageSize,
602
0
                                            DefaultSurfaceFlags(),
603
0
                                            PlaybackType::eAnimated));
604
0
    ASSERT_EQ(MatchType::EXACT, result.Type());
605
0
606
0
    EXPECT_TRUE(NS_SUCCEEDED(result.Surface().Seek(0)));
607
0
    EXPECT_TRUE(bool(result.Surface()));
608
0
609
0
    RawAccessFrameRef partialFrame = result.Surface().RawAccessRef(1);
610
0
    EXPECT_TRUE(bool(partialFrame));
611
0
  }
612
0
613
0
  // Ensure that the static version is still around.
614
0
  {
615
0
    LookupResult result =
616
0
      SurfaceCache::Lookup(ImageKey(image.get()),
617
0
                           RasterSurfaceKey(imageSize,
618
0
                                            DefaultSurfaceFlags(),
619
0
                                            PlaybackType::eStatic));
620
0
    ASSERT_EQ(MatchType::EXACT, result.Type());
621
0
    EXPECT_TRUE(bool(result.Surface()));
622
0
  }
623
0
}
624
625
TEST_F(ImageDecoders, AnimatedGIFWithFRAME_CURRENT)
626
0
{
627
0
  ImageTestCase testCase = GreenFirstFrameAnimatedGIFTestCase();
628
0
629
0
  // Verify that we can decode this test case and retrieve the entire sequence
630
0
  // of frames using imgIContainer::FRAME_CURRENT. This ensures that we
631
0
  // correctly trigger an animated decode rather than a single-frame decode when
632
0
  // imgIContainer::FRAME_CURRENT is requested.
633
0
634
0
  // Create an image.
635
0
  RefPtr<Image> image =
636
0
    ImageFactory::CreateAnonymousImage(nsDependentCString(testCase.mMimeType));
637
0
  ASSERT_TRUE(!image->HasError());
638
0
639
0
  nsCOMPtr<nsIInputStream> inputStream = LoadFile(testCase.mPath);
640
0
  ASSERT_TRUE(inputStream);
641
0
642
0
  // Figure out how much data we have.
643
0
  uint64_t length;
644
0
  nsresult rv = inputStream->Available(&length);
645
0
  ASSERT_TRUE(NS_SUCCEEDED(rv));
646
0
647
0
  // Write the data into the image.
648
0
  rv = image->OnImageDataAvailable(nullptr, nullptr, inputStream, 0,
649
0
                                   static_cast<uint32_t>(length));
650
0
  ASSERT_TRUE(NS_SUCCEEDED(rv));
651
0
652
0
  // Let the image know we've sent all the data.
653
0
  rv = image->OnImageDataComplete(nullptr, nullptr, NS_OK, true);
654
0
  ASSERT_TRUE(NS_SUCCEEDED(rv));
655
0
656
0
  RefPtr<ProgressTracker> tracker = image->GetProgressTracker();
657
0
  tracker->SyncNotifyProgress(FLAG_LOAD_COMPLETE);
658
0
659
0
  // Lock the image so its surfaces don't disappear during the test.
660
0
  image->LockImage();
661
0
662
0
  // Use GetFrame() to force a sync decode of the image, specifying
663
0
  // FRAME_CURRENT to ensure we get an animated decode.
664
0
  RefPtr<SourceSurface> surface =
665
0
    image->GetFrame(imgIContainer::FRAME_CURRENT,
666
0
                    imgIContainer::FLAG_SYNC_DECODE);
667
0
668
0
  // Ensure that the image's metadata meets our expectations.
669
0
  IntSize imageSize(0, 0);
670
0
  rv = image->GetWidth(&imageSize.width);
671
0
  EXPECT_TRUE(NS_SUCCEEDED(rv));
672
0
  rv = image->GetHeight(&imageSize.height);
673
0
  EXPECT_TRUE(NS_SUCCEEDED(rv));
674
0
675
0
  EXPECT_EQ(testCase.mSize.width, imageSize.width);
676
0
  EXPECT_EQ(testCase.mSize.height, imageSize.height);
677
0
678
0
  Progress imageProgress = tracker->GetProgress();
679
0
680
0
  EXPECT_TRUE(bool(imageProgress & FLAG_HAS_TRANSPARENCY) == false);
681
0
  EXPECT_TRUE(bool(imageProgress & FLAG_IS_ANIMATED) == true);
682
0
683
0
  // Ensure that we decoded both frames of the animated version of the image.
684
0
  {
685
0
    LookupResult result =
686
0
      SurfaceCache::Lookup(ImageKey(image.get()),
687
0
                           RasterSurfaceKey(imageSize,
688
0
                                            DefaultSurfaceFlags(),
689
0
                                            PlaybackType::eAnimated));
690
0
    ASSERT_EQ(MatchType::EXACT, result.Type());
691
0
692
0
    EXPECT_TRUE(NS_SUCCEEDED(result.Surface().Seek(0)));
693
0
    EXPECT_TRUE(bool(result.Surface()));
694
0
695
0
    RawAccessFrameRef partialFrame = result.Surface().RawAccessRef(1);
696
0
    EXPECT_TRUE(bool(partialFrame));
697
0
  }
698
0
699
0
  // Ensure that we didn't decode the static version of the image.
700
0
  {
701
0
    LookupResult result =
702
0
      SurfaceCache::Lookup(ImageKey(image.get()),
703
0
                           RasterSurfaceKey(imageSize,
704
0
                                            DefaultSurfaceFlags(),
705
0
                                            PlaybackType::eStatic));
706
0
    ASSERT_EQ(MatchType::NOT_FOUND, result.Type());
707
0
  }
708
0
709
0
  // Use GetFrame() to force a sync decode of the image, this time specifying
710
0
  // FRAME_FIRST to ensure that we get a single-frame decode.
711
0
  RefPtr<SourceSurface> animatedSurface =
712
0
    image->GetFrame(imgIContainer::FRAME_FIRST,
713
0
                    imgIContainer::FLAG_SYNC_DECODE);
714
0
715
0
  // Ensure that we decoded the static version of the image.
716
0
  {
717
0
    LookupResult result =
718
0
      SurfaceCache::Lookup(ImageKey(image.get()),
719
0
                           RasterSurfaceKey(imageSize,
720
0
                                            DefaultSurfaceFlags(),
721
0
                                            PlaybackType::eStatic));
722
0
    ASSERT_EQ(MatchType::EXACT, result.Type());
723
0
    EXPECT_TRUE(bool(result.Surface()));
724
0
  }
725
0
726
0
  // Ensure that both frames of the animated version are still around.
727
0
  {
728
0
    LookupResult result =
729
0
      SurfaceCache::Lookup(ImageKey(image.get()),
730
0
                           RasterSurfaceKey(imageSize,
731
0
                                            DefaultSurfaceFlags(),
732
0
                                            PlaybackType::eAnimated));
733
0
    ASSERT_EQ(MatchType::EXACT, result.Type());
734
0
735
0
    EXPECT_TRUE(NS_SUCCEEDED(result.Surface().Seek(0)));
736
0
    EXPECT_TRUE(bool(result.Surface()));
737
0
738
0
    RawAccessFrameRef partialFrame = result.Surface().RawAccessRef(1);
739
0
    EXPECT_TRUE(bool(partialFrame));
740
0
  }
741
0
}
742
743
TEST_F(ImageDecoders, AnimatedGIFWithExtraImageSubBlocks)
744
0
{
745
0
  ImageTestCase testCase = ExtraImageSubBlocksAnimatedGIFTestCase();
746
0
747
0
  // Verify that we can decode this test case and get two frames, even though
748
0
  // there are extra image sub blocks between the first and second frame. The
749
0
  // extra data shouldn't confuse the decoder or cause the decode to fail.
750
0
751
0
  // Create an image.
752
0
  RefPtr<Image> image =
753
0
    ImageFactory::CreateAnonymousImage(nsDependentCString(testCase.mMimeType));
754
0
  ASSERT_TRUE(!image->HasError());
755
0
756
0
  nsCOMPtr<nsIInputStream> inputStream = LoadFile(testCase.mPath);
757
0
  ASSERT_TRUE(inputStream);
758
0
759
0
  // Figure out how much data we have.
760
0
  uint64_t length;
761
0
  nsresult rv = inputStream->Available(&length);
762
0
  ASSERT_TRUE(NS_SUCCEEDED(rv));
763
0
764
0
  // Write the data into the image.
765
0
  rv = image->OnImageDataAvailable(nullptr, nullptr, inputStream, 0,
766
0
                                   static_cast<uint32_t>(length));
767
0
  ASSERT_TRUE(NS_SUCCEEDED(rv));
768
0
769
0
  // Let the image know we've sent all the data.
770
0
  rv = image->OnImageDataComplete(nullptr, nullptr, NS_OK, true);
771
0
  ASSERT_TRUE(NS_SUCCEEDED(rv));
772
0
773
0
  RefPtr<ProgressTracker> tracker = image->GetProgressTracker();
774
0
  tracker->SyncNotifyProgress(FLAG_LOAD_COMPLETE);
775
0
776
0
  // Use GetFrame() to force a sync decode of the image.
777
0
  RefPtr<SourceSurface> surface =
778
0
    image->GetFrame(imgIContainer::FRAME_CURRENT,
779
0
                    imgIContainer::FLAG_SYNC_DECODE);
780
0
781
0
  // Ensure that the image's metadata meets our expectations.
782
0
  IntSize imageSize(0, 0);
783
0
  rv = image->GetWidth(&imageSize.width);
784
0
  EXPECT_TRUE(NS_SUCCEEDED(rv));
785
0
  rv = image->GetHeight(&imageSize.height);
786
0
  EXPECT_TRUE(NS_SUCCEEDED(rv));
787
0
788
0
  EXPECT_EQ(testCase.mSize.width, imageSize.width);
789
0
  EXPECT_EQ(testCase.mSize.height, imageSize.height);
790
0
791
0
  Progress imageProgress = tracker->GetProgress();
792
0
793
0
  EXPECT_TRUE(bool(imageProgress & FLAG_HAS_TRANSPARENCY) == false);
794
0
  EXPECT_TRUE(bool(imageProgress & FLAG_IS_ANIMATED) == true);
795
0
796
0
  // Ensure that we decoded both frames of the image.
797
0
  LookupResult result =
798
0
    SurfaceCache::Lookup(ImageKey(image.get()),
799
0
                         RasterSurfaceKey(imageSize,
800
0
                                          DefaultSurfaceFlags(),
801
0
                                          PlaybackType::eAnimated));
802
0
  ASSERT_EQ(MatchType::EXACT, result.Type());
803
0
804
0
  EXPECT_TRUE(NS_SUCCEEDED(result.Surface().Seek(0)));
805
0
  EXPECT_TRUE(bool(result.Surface()));
806
0
807
0
  RawAccessFrameRef partialFrame = result.Surface().RawAccessRef(1);
808
0
  EXPECT_TRUE(bool(partialFrame));
809
0
}
810
811
TEST_F(ImageDecoders, TruncatedSmallGIFSingleChunk)
812
0
{
813
0
  CheckDecoderSingleChunk(TruncatedSmallGIFTestCase());
814
0
}
815
816
TEST_F(ImageDecoders, LargeICOWithBMPSingleChunk)
817
0
{
818
0
  CheckDecoderSingleChunk(LargeICOWithBMPTestCase());
819
0
}
820
821
TEST_F(ImageDecoders, LargeICOWithBMPMultiChunk)
822
0
{
823
0
  CheckDecoderMultiChunk(LargeICOWithBMPTestCase());
824
0
}
825
826
TEST_F(ImageDecoders, LargeICOWithPNGSingleChunk)
827
0
{
828
0
  CheckDecoderSingleChunk(LargeICOWithPNGTestCase());
829
0
}
830
831
TEST_F(ImageDecoders, LargeICOWithPNGMultiChunk)
832
0
{
833
0
  CheckDecoderMultiChunk(LargeICOWithPNGTestCase());
834
0
}
835
836
TEST_F(ImageDecoders, MultipleSizesICOSingleChunk)
837
0
{
838
0
  ImageTestCase testCase = GreenMultipleSizesICOTestCase();
839
0
840
0
  // Create an image.
841
0
  RefPtr<Image> image =
842
0
    ImageFactory::CreateAnonymousImage(nsDependentCString(testCase.mMimeType));
843
0
  ASSERT_TRUE(!image->HasError());
844
0
845
0
  nsCOMPtr<nsIInputStream> inputStream = LoadFile(testCase.mPath);
846
0
  ASSERT_TRUE(inputStream);
847
0
848
0
  // Figure out how much data we have.
849
0
  uint64_t length;
850
0
  nsresult rv = inputStream->Available(&length);
851
0
  ASSERT_TRUE(NS_SUCCEEDED(rv));
852
0
853
0
  // Write the data into the image.
854
0
  rv = image->OnImageDataAvailable(nullptr, nullptr, inputStream, 0,
855
0
                                   static_cast<uint32_t>(length));
856
0
  ASSERT_TRUE(NS_SUCCEEDED(rv));
857
0
858
0
  // Let the image know we've sent all the data.
859
0
  rv = image->OnImageDataComplete(nullptr, nullptr, NS_OK, true);
860
0
  ASSERT_TRUE(NS_SUCCEEDED(rv));
861
0
862
0
  RefPtr<ProgressTracker> tracker = image->GetProgressTracker();
863
0
  tracker->SyncNotifyProgress(FLAG_LOAD_COMPLETE);
864
0
865
0
  // Use GetFrame() to force a sync decode of the image.
866
0
  RefPtr<SourceSurface> surface =
867
0
    image->GetFrame(imgIContainer::FRAME_CURRENT,
868
0
                    imgIContainer::FLAG_SYNC_DECODE);
869
0
870
0
  // Ensure that the image's metadata meets our expectations.
871
0
  IntSize imageSize(0, 0);
872
0
  rv = image->GetWidth(&imageSize.width);
873
0
  EXPECT_TRUE(NS_SUCCEEDED(rv));
874
0
  rv = image->GetHeight(&imageSize.height);
875
0
  EXPECT_TRUE(NS_SUCCEEDED(rv));
876
0
877
0
  EXPECT_EQ(testCase.mSize.width, imageSize.width);
878
0
  EXPECT_EQ(testCase.mSize.height, imageSize.height);
879
0
880
0
  nsTArray<IntSize> nativeSizes;
881
0
  rv = image->GetNativeSizes(nativeSizes);
882
0
  EXPECT_TRUE(NS_SUCCEEDED(rv));
883
0
  ASSERT_EQ(6u, nativeSizes.Length());
884
0
885
0
  IntSize expectedSizes[] = {
886
0
    IntSize(16, 16),
887
0
    IntSize(32, 32),
888
0
    IntSize(64, 64),
889
0
    IntSize(128, 128),
890
0
    IntSize(256, 256),
891
0
    IntSize(256, 128)
892
0
  };
893
0
894
0
  for (int i = 0; i < 6; ++i) {
895
0
    EXPECT_EQ(expectedSizes[i], nativeSizes[i]);
896
0
  }
897
0
898
0
  RefPtr<Image> image90 =
899
0
    ImageOps::Orient(image, Orientation(Angle::D90, Flip::Unflipped));
900
0
  rv = image90->GetNativeSizes(nativeSizes);
901
0
  EXPECT_TRUE(NS_SUCCEEDED(rv));
902
0
  ASSERT_EQ(6u, nativeSizes.Length());
903
0
904
0
  for (int i = 0; i < 5; ++i) {
905
0
    EXPECT_EQ(expectedSizes[i], nativeSizes[i]);
906
0
  }
907
0
  EXPECT_EQ(IntSize(128, 256), nativeSizes[5]);
908
0
909
0
  RefPtr<Image> image180 =
910
0
    ImageOps::Orient(image, Orientation(Angle::D180, Flip::Unflipped));
911
0
  rv = image180->GetNativeSizes(nativeSizes);
912
0
  EXPECT_TRUE(NS_SUCCEEDED(rv));
913
0
  ASSERT_EQ(6u, nativeSizes.Length());
914
0
915
0
  for (int i = 0; i < 6; ++i) {
916
0
    EXPECT_EQ(expectedSizes[i], nativeSizes[i]);
917
0
  }
918
0
}