Flutter Engine
The Flutter Engine
Classes | Functions
CodecTest.cpp File Reference
#include "include/codec/SkAndroidCodec.h"
#include "include/codec/SkCodec.h"
#include "include/codec/SkEncodedImageFormat.h"
#include "include/codec/SkGifDecoder.h"
#include "include/codec/SkJpegDecoder.h"
#include "include/codec/SkPngChunkReader.h"
#include "include/core/SkAlphaType.h"
#include "include/core/SkBitmap.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkColor.h"
#include "include/core/SkColorSpace.h"
#include "include/core/SkColorType.h"
#include "include/core/SkData.h"
#include "include/core/SkDataTable.h"
#include "include/core/SkImage.h"
#include "include/core/SkImageGenerator.h"
#include "include/core/SkImageInfo.h"
#include "include/core/SkPixmap.h"
#include "include/core/SkRect.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkSize.h"
#include "include/core/SkStream.h"
#include "include/core/SkString.h"
#include "include/core/SkTypes.h"
#include "include/encode/SkJpegEncoder.h"
#include "include/encode/SkPngEncoder.h"
#include "include/encode/SkWebpEncoder.h"
#include "include/private/base/SkAlign.h"
#include "include/private/base/SkDebug.h"
#include "include/private/base/SkMalloc.h"
#include "include/private/base/SkTemplates.h"
#include "modules/skcms/skcms.h"
#include "src/base/SkAutoMalloc.h"
#include "src/base/SkRandom.h"
#include "src/codec/SkCodecImageGenerator.h"
#include "src/core/SkColorSpacePriv.h"
#include "src/core/SkMD5.h"
#include "src/core/SkStreamPriv.h"
#include "tests/FakeStreams.h"
#include "tests/Test.h"
#include "tools/DecodeUtils.h"
#include "tools/Resources.h"
#include "tools/ToolUtils.h"
#include <png.h>
#include <pngconf.h>
#include <setjmp.h>
#include <algorithm>
#include <cstdint>
#include <cstring>
#include <initializer_list>
#include <memory>
#include <utility>
#include <vector>

Go to the source code of this file.

Classes

class  LimitedPeekingMemStream
 
class  LimitedRewindingStream
 

Functions

static SkMD5::Digest md5 (const SkBitmap &bm)
 
static void compare_to_good_digest (skiatest::Reporter *r, const SkMD5::Digest &goodDigest, const SkBitmap &bm)
 
template<typename Codec >
static void test_info (skiatest::Reporter *r, Codec *codec, const SkImageInfo &info, SkCodec::Result expectedResult, const SkMD5::Digest *goodDigest)
 
SkIRect generate_random_subset (SkRandom *rand, int w, int h)
 
static void test_incremental_decode (skiatest::Reporter *r, SkCodec *codec, const SkImageInfo &info, const SkMD5::Digest &goodDigest)
 
static void test_in_stripes (skiatest::Reporter *r, SkCodec *codec, const SkImageInfo &info, const SkMD5::Digest &goodDigest)
 
template<typename Codec >
static void test_codec (skiatest::Reporter *r, const char *path, Codec *codec, SkBitmap &bm, const SkImageInfo &info, const SkISize &size, SkCodec::Result expectedResult, SkMD5::Digest *digest, const SkMD5::Digest *goodDigest)
 
static bool supports_partial_scanlines (const char path[])
 
static void check_scanline_decode (skiatest::Reporter *r, SkCodec *codec, SkMD5::Digest *codecDigest, const SkImageInfo &info, const char path[], SkISize size, bool supportsScanlineDecoding, bool supportsIncomplete, bool supportsNewScanlineDecoding)
 
static void check_subset_decode (skiatest::Reporter *r, SkCodec *codec, const SkImageInfo &info, SkISize size, bool supportsSubsetDecoding, bool supportsIncomplete)
 
static void check_android_codec (skiatest::Reporter *r, std::unique_ptr< SkCodec > codec, const SkMD5::Digest &codecDigest, const SkImageInfo &info, const char path[], SkISize size, bool supportsScanlineDecoding, bool supportsSubsetDecoding, bool supportsIncomplete, bool supportsNewScanlineDecoding)
 
static void check_codec_image_generator (skiatest::Reporter *r, const SkMD5::Digest &codecDigest, const SkImageInfo &info, const char path[], bool supportsIncomplete)
 
static void check (skiatest::Reporter *r, const char path[], SkISize size, bool supportsScanlineDecoding, bool supportsSubsetDecoding, bool supportsIncomplete, bool supportsNewScanlineDecoding=false)
 
 DEF_TEST (Codec_wbmp, r)
 
 DEF_TEST (Codec_webp, r)
 
 DEF_TEST (Codec_bmp, r)
 
 DEF_TEST (Codec_ico, r)
 
 DEF_TEST (Codec_gif, r)
 
 DEF_TEST (Codec_jpg, r)
 
 DEF_TEST (Codec_png, r)
 
static void test_invalid_stream (skiatest::Reporter *r, const void *stream, size_t len)
 
 DEF_TEST (Codec_leaks, r)
 
 DEF_TEST (Codec_null, r)
 
static void test_dimensions (skiatest::Reporter *r, const char path[])
 
 DEF_TEST (Codec_Dimensions, r)
 
static void test_invalid (skiatest::Reporter *r, const char path[])
 
 DEF_TEST (Codec_Empty, r)
 
 DEF_TEST (Codec_webp_peek, r)
 
 DEF_TEST (Codec_wbmp_restrictive, r)
 
 DEF_TEST (Codec_wbmp_max_size, r)
 
 DEF_TEST (Codec_jpeg_rewind, r)
 
static void check_color_xform (skiatest::Reporter *r, const char *path)
 
 DEF_TEST (Codec_ColorXform, r)
 
static bool color_type_match (SkColorType origColorType, SkColorType codecColorType)
 
static bool alpha_type_match (SkAlphaType origAlphaType, SkAlphaType codecAlphaType)
 
static void check_round_trip (skiatest::Reporter *r, SkCodec *origCodec, const SkImageInfo &info)
 
 DEF_TEST (Codec_PngRoundTrip, r)
 
static void test_conversion_possible (skiatest::Reporter *r, const char *path, bool supportsScanlineDecoder, bool supportsIncrementalDecoder)
 
 DEF_TEST (Codec_F16ConversionPossible, r)
 
static void decode_frame (skiatest::Reporter *r, SkCodec *codec, size_t frame)
 
 DEF_TEST (Codec_skipFullParse, r)
 
 DEF_TEST (Codec_fallBack, r)
 
static void seek_and_decode (const char *file, std::unique_ptr< SkStream > stream, skiatest::Reporter *r)
 
 DEF_TEST (Wuffs_seek_and_decode, r)
 
 DEF_TEST (Codec_reusePng, r)
 
 DEF_TEST (Codec_rowsDecoded, r)
 
static void test_invalid_images (skiatest::Reporter *r, const char *path, SkCodec::Result expectedResult)
 
 DEF_TEST (Codec_InvalidImages, r)
 
static void test_invalid_header (skiatest::Reporter *r, const char *path)
 
 DEF_TEST (Codec_InvalidHeader, r)
 
 DEF_TEST (Codec_InvalidAnimated, r)
 
static void encode_format (SkDynamicMemoryWStream *stream, const SkPixmap &pixmap, SkEncodedImageFormat format)
 
static void test_encode_icc (skiatest::Reporter *r, SkEncodedImageFormat format)
 
 DEF_TEST (Codec_EncodeICC, r)
 
 DEF_TEST (Codec_webp_rowsDecoded, r)
 
 DEF_TEST (Codec_ossfuzz6274, r)
 
 DEF_TEST (Codec_78329453, r)
 
 DEF_TEST (Codec_A8, r)
 
 DEF_TEST (Codec_crbug807324, r)
 
 DEF_TEST (Codec_F16_noColorSpace, r)
 
 DEF_TEST (Codec_noConversion, r)
 
 DEF_TEST (Codec_kBGR_101010x_XR_SkColorType_supported, r)
 
 DEF_TEST (Codec_gif_notseekable, r)
 
 DEF_TEST (Codec_gif_notseekable2, r)
 
 DEF_TEST (Codec_gif_null_param, r)
 
 DEF_TEST (Codec_gif_can_preserve_original_data, r)
 
 DEF_TEST (Codec_jpeg_can_return_data_from_original_stream, r)
 

Function Documentation

◆ alpha_type_match()

static bool alpha_type_match ( SkAlphaType  origAlphaType,
SkAlphaType  codecAlphaType 
)
static

Definition at line 1115 of file CodecTest.cpp.

1115 {
1116 switch (origAlphaType) {
1119 return kUnpremul_SkAlphaType == codecAlphaType ||
1120 kPremul_SkAlphaType == codecAlphaType;
1121 default:
1122 return origAlphaType == codecAlphaType;
1123 }
1124}
kUnpremul_SkAlphaType
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition: SkAlphaType.h:29

◆ check()

static void check ( skiatest::Reporter r,
const char  path[],
SkISize  size,
bool  supportsScanlineDecoding,
bool  supportsSubsetDecoding,
bool  supportsIncomplete,
bool  supportsNewScanlineDecoding = false 
)
static

Definition at line 482 of file CodecTest.cpp.

488 {
489 // If we're testing incomplete decodes, let's run the same test on full decodes.
490 if (supportsIncomplete) {
491 check(r, path, size, supportsScanlineDecoding, supportsSubsetDecoding,
492 /*supportsIncomplete=*/false, supportsNewScanlineDecoding);
493 }
494
495 // Initialize a codec with a data stream.
496 std::unique_ptr<SkStream> stream(GetResourceAsStream(path));
497 if (!stream) {
498 return;
499 }
500
501 std::unique_ptr<SkCodec> codec;
502 if (supportsIncomplete) {
503 size_t length = stream->getLength();
505 } else {
506 codec = SkCodec::MakeFromStream(std::move(stream));
507 }
508 if (!codec) {
509 ERRORF(r, "Unable to decode '%s'", path);
510 return;
511 }
512
513 const SkImageInfo info = codec->getInfo().makeColorType(kN32_SkColorType);
514
515 // Run tests with this codec.
516 SkMD5::Digest codecDigest;
517 check_scanline_decode(r, codec.get(), &codecDigest, info, path, size, supportsScanlineDecoding,
518 supportsIncomplete, supportsNewScanlineDecoding);
519
520 check_subset_decode(r, codec.get(), info, size, supportsSubsetDecoding, supportsIncomplete);
521
522 check_android_codec(r, std::move(codec), codecDigest, info, path, size,
523 supportsScanlineDecoding, supportsSubsetDecoding, supportsIncomplete,
524 supportsNewScanlineDecoding);
525
526 check_codec_image_generator(r, codecDigest, info, path, supportsIncomplete);
527}
static void check_scanline_decode(skiatest::Reporter *r, SkCodec *codec, SkMD5::Digest *codecDigest, const SkImageInfo &info, const char path[], SkISize size, bool supportsScanlineDecoding, bool supportsIncomplete, bool supportsNewScanlineDecoding)
Definition: CodecTest.cpp:294
static void check_codec_image_generator(skiatest::Reporter *r, const SkMD5::Digest &codecDigest, const SkImageInfo &info, const char path[], bool supportsIncomplete)
Definition: CodecTest.cpp:452
static void check_subset_decode(skiatest::Reporter *r, SkCodec *codec, const SkImageInfo &info, SkISize size, bool supportsSubsetDecoding, bool supportsIncomplete)
Definition: CodecTest.cpp:384
static void check_android_codec(skiatest::Reporter *r, std::unique_ptr< SkCodec > codec, const SkMD5::Digest &codecDigest, const SkImageInfo &info, const char path[], SkISize size, bool supportsScanlineDecoding, bool supportsSubsetDecoding, bool supportsIncomplete, bool supportsNewScanlineDecoding)
Definition: CodecTest.cpp:426
static void check(skiatest::Reporter *r, const char path[], SkISize size, bool supportsScanlineDecoding, bool supportsSubsetDecoding, bool supportsIncomplete, bool supportsNewScanlineDecoding=false)
Definition: CodecTest.cpp:482
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
std::unique_ptr< SkStreamAsset > GetResourceAsStream(const char *resource, bool useFileStream)
Definition: Resources.cpp:31
#define ERRORF(r,...)
Definition: Test.h:293
static std::unique_ptr< SkCodec > MakeFromStream(std::unique_ptr< SkStream >, SkSpan< const SkCodecs::Decoder > decoders, Result *=nullptr, SkPngChunkReader *=nullptr, SelectionPolicy selectionPolicy=SelectionPolicy::kPreferStillImage)
Definition: SkCodec.cpp:163
static std::unique_ptr< SkCodec > MakeFromData(sk_sp< SkData >, SkSpan< const SkCodecs::Decoder > decoders, SkPngChunkReader *=nullptr)
Definition: SkCodec.cpp:241
static sk_sp< SkData > MakeFromStream(SkStream *, size_t size)
Definition: SkData.cpp:208
size_t length
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition: switches.h:57
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259

◆ check_android_codec()

static void check_android_codec ( skiatest::Reporter r,
std::unique_ptr< SkCodec codec,
const SkMD5::Digest codecDigest,
const SkImageInfo info,
const char  path[],
SkISize  size,
bool  supportsScanlineDecoding,
bool  supportsSubsetDecoding,
bool  supportsIncomplete,
bool  supportsNewScanlineDecoding 
)
static

Definition at line 426 of file CodecTest.cpp.

435 {
436 if (supportsScanlineDecoding || supportsSubsetDecoding || supportsNewScanlineDecoding) {
437 auto androidCodec = SkAndroidCodec::MakeFromCodec(std::move(codec));
438 if (!androidCodec) {
439 ERRORF(r, "Unable to decode '%s'", path);
440 return;
441 }
442
443 SkBitmap bm;
444 SkMD5::Digest androidCodecDigest;
445 const SkCodec::Result expectedResult = supportsIncomplete ? SkCodec::kIncompleteInput
447 test_codec(r, path, androidCodec.get(), bm, info, size, expectedResult, &androidCodecDigest,
448 &codecDigest);
449 }
450}
static void test_codec(skiatest::Reporter *r, const char *path, Codec *codec, SkBitmap &bm, const SkImageInfo &info, const SkISize &size, SkCodec::Result expectedResult, SkMD5::Digest *digest, const SkMD5::Digest *goodDigest)
Definition: CodecTest.cpp:187
static std::unique_ptr< SkAndroidCodec > MakeFromCodec(std::unique_ptr< SkCodec >)
Result
Definition: SkCodec.h:76
@ kIncompleteInput
Definition: SkCodec.h:84
@ kSuccess
Definition: SkCodec.h:80

◆ check_codec_image_generator()

static void check_codec_image_generator ( skiatest::Reporter r,
const SkMD5::Digest codecDigest,
const SkImageInfo info,
const char  path[],
bool  supportsIncomplete 
)
static

Definition at line 452 of file CodecTest.cpp.

456 {
457 // Test SkCodecImageGenerator
458 if (!supportsIncomplete) {
459 std::unique_ptr<SkStream> stream(GetResourceAsStream(path));
460 sk_sp<SkData> fullData(SkData::MakeFromStream(stream.get(), stream->getLength()));
461 std::unique_ptr<SkImageGenerator> gen(
463 SkBitmap bm;
464 bm.allocPixels(info);
465 REPORTER_ASSERT(r, gen->getPixels(info, bm.getPixels(), bm.rowBytes()));
466 compare_to_good_digest(r, codecDigest, bm);
467
468#if !defined(SK_PNG_DISABLE_TESTS) && defined(SK_ENABLE_ANDROID_UTILS)
469 // Test using FrontBufferedStream, as Android does
470 auto bufferedStream = android::skia::FrontBufferedStream::Make(
472 REPORTER_ASSERT(r, bufferedStream);
473 std::unique_ptr<SkCodec> codec = SkCodec::MakeFromStream(std::move(bufferedStream));
474 REPORTER_ASSERT(r, codec);
475 if (codec) {
476 test_info(r, codec.get(), info, SkCodec::kSuccess, &codecDigest);
477 }
478#endif
479 }
480}
static void compare_to_good_digest(skiatest::Reporter *r, const SkMD5::Digest &goodDigest, const SkBitmap &bm)
Definition: CodecTest.cpp:93
static void test_info(skiatest::Reporter *r, Codec *codec, const SkImageInfo &info, SkCodec::Result expectedResult, const SkMD5::Digest *goodDigest)
Definition: CodecTest.cpp:106
#define REPORTER_ASSERT(r, cond,...)
Definition: Test.h:286
void allocPixels(const SkImageInfo &info, size_t rowBytes)
Definition: SkBitmap.cpp:258
size_t rowBytes() const
Definition: SkBitmap.h:238
void * getPixels() const
Definition: SkBitmap.h:283
static std::unique_ptr< SkImageGenerator > MakeFromEncodedCodec(sk_sp< SkData >, std::optional< SkAlphaType >=std::nullopt)
static constexpr size_t MinBufferedBytesNeeded()
Definition: SkCodec.h:71
static std::unique_ptr< SkMemoryStream > Make(sk_sp< SkData > data)
Definition: SkStream.cpp:314
static std::unique_ptr< SkStreamRewindable > Make(std::unique_ptr< SkStream > stream, size_t minBufferSize)
def gen()
Definition: dom.py:77
Definition: gen.py:1

◆ check_color_xform()

static void check_color_xform ( skiatest::Reporter r,
const char *  path 
)
static

Definition at line 1076 of file CodecTest.cpp.

1076 {
1077 std::unique_ptr<SkAndroidCodec> codec(SkAndroidCodec::MakeFromStream(GetResourceAsStream(path)));
1078
1080 opts.fSampleSize = 3;
1081 const int subsetWidth = codec->getInfo().width() / 2;
1082 const int subsetHeight = codec->getInfo().height() / 2;
1083 SkIRect subset = SkIRect::MakeWH(subsetWidth, subsetHeight);
1084 opts.fSubset = &subset;
1085
1086 const int dstWidth = subsetWidth / opts.fSampleSize;
1087 const int dstHeight = subsetHeight / opts.fSampleSize;
1089 SkImageInfo dstInfo = codec->getInfo().makeWH(dstWidth, dstHeight)
1090 .makeColorType(kN32_SkColorType)
1091 .makeColorSpace(colorSpace);
1092
1093 size_t rowBytes = dstInfo.minRowBytes();
1094 SkAutoMalloc pixelStorage(dstInfo.computeByteSize(rowBytes));
1095 SkCodec::Result result = codec->getAndroidPixels(dstInfo, pixelStorage.get(), rowBytes, &opts);
1097}
static std::unique_ptr< SkAndroidCodec > MakeFromStream(std::unique_ptr< SkStream >, SkPngChunkReader *=nullptr)
static sk_sp< SkColorSpace > MakeRGB(const skcms_TransferFunction &transferFn, const skcms_Matrix3x3 &toXYZ)
GAsyncResult * result
static constexpr skcms_Matrix3x3 kAdobeRGB
Definition: SkColorSpace.h:77
static constexpr skcms_TransferFunction k2Dot2
Definition: SkColorSpace.h:48
const SkIRect * fSubset
Definition: SkCodec.h:347
Definition: SkRect.h:32
static constexpr SkIRect MakeWH(int32_t w, int32_t h)
Definition: SkRect.h:56
SkImageInfo makeWH(int newWidth, int newHeight) const
Definition: SkImageInfo.h:444
size_t minRowBytes() const
Definition: SkImageInfo.h:517
size_t computeByteSize(size_t rowBytes) const
SkImageInfo makeColorSpace(sk_sp< SkColorSpace > cs) const
SkImageInfo makeColorType(SkColorType newColorType) const
Definition: SkImageInfo.h:475

◆ check_round_trip()

static void check_round_trip ( skiatest::Reporter r,
SkCodec origCodec,
const SkImageInfo info 
)
static

Definition at line 1126 of file CodecTest.cpp.

1126 {
1127 SkBitmap bm1;
1128 bm1.allocPixels(info);
1129 SkCodec::Result result = origCodec->getPixels(info, bm1.getPixels(), bm1.rowBytes());
1131
1132 // Encode the image to png.
1135
1136 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(stream.detachAsData()));
1137 REPORTER_ASSERT(r, color_type_match(info.colorType(), codec->getInfo().colorType()));
1138 REPORTER_ASSERT(r, alpha_type_match(info.alphaType(), codec->getInfo().alphaType()));
1139
1140 SkBitmap bm2;
1141 bm2.allocPixels(info);
1142 result = codec->getPixels(info, bm2.getPixels(), bm2.rowBytes());
1144
1145 REPORTER_ASSERT(r, md5(bm1) == md5(bm2));
1146}
static SkMD5::Digest md5(const SkBitmap &bm)
Definition: CodecTest.cpp:77
static bool alpha_type_match(SkAlphaType origAlphaType, SkAlphaType codecAlphaType)
Definition: CodecTest.cpp:1115
static bool color_type_match(SkColorType origColorType, SkColorType codecColorType)
Definition: CodecTest.cpp:1104
#define SkASSERT_RELEASE(cond)
Definition: SkAssert.h:100
const SkPixmap & pixmap() const
Definition: SkBitmap.h:133
Result getPixels(const SkImageInfo &info, void *pixels, size_t rowBytes, const Options *)
Definition: SkCodec.cpp:467
SK_API bool Encode(SkWStream *dst, const SkPixmap &src, const Options &options)

◆ check_scanline_decode()

static void check_scanline_decode ( skiatest::Reporter r,
SkCodec codec,
SkMD5::Digest codecDigest,
const SkImageInfo info,
const char  path[],
SkISize  size,
bool  supportsScanlineDecoding,
bool  supportsIncomplete,
bool  supportsNewScanlineDecoding 
)
static

Definition at line 294 of file CodecTest.cpp.

302 {
303
304 // Test full image decodes with SkCodec
305 SkBitmap bm;
306 const SkCodec::Result expectedResult = supportsIncomplete ? SkCodec::kIncompleteInput
308 test_codec(r, path, codec, bm, info, size, expectedResult, codecDigest, nullptr);
309
310 // Scanline decoding follows.
311 if (supportsNewScanlineDecoding && !supportsIncomplete) {
312 test_incremental_decode(r, codec, info, *codecDigest);
313 // This is only supported by codecs that use incremental decoding to
314 // support subset decodes - png and jpeg (once SkJpegCodec is
315 // converted).
316 if (SkStrEndsWith(path, "png") || SkStrEndsWith(path, "PNG")) {
317 test_in_stripes(r, codec, info, *codecDigest);
318 }
319 }
320
321 // Need to call startScanlineDecode() first.
322 REPORTER_ASSERT(r, codec->getScanlines(bm.getAddr(0, 0), 1, 0) == 0);
323 REPORTER_ASSERT(r, !codec->skipScanlines(1));
324 const SkCodec::Result startResult = codec->startScanlineDecode(info);
325 if (supportsScanlineDecoding) {
327
328 REPORTER_ASSERT(r, startResult == SkCodec::kSuccess);
329
330 for (int y = 0; y < info.height(); y++) {
331 const int lines = codec->getScanlines(bm.getAddr(0, y), 1, 0);
332 if (!supportsIncomplete) {
333 REPORTER_ASSERT(r, 1 == lines);
334 }
335 }
336 // verify that scanline decoding gives the same result.
338 compare_to_good_digest(r, *codecDigest, bm);
339 }
340
341 // Cannot continue to decode scanlines beyond the end
342 REPORTER_ASSERT(r, codec->getScanlines(bm.getAddr(0, 0), 1, 0)
343 == 0);
344
345 // Interrupting a scanline decode with a full decode starts from
346 // scratch
347 {
349 const int lines = codec->getScanlines(bm.getAddr(0, 0), 1, 0);
350 if (!supportsIncomplete) {
351 REPORTER_ASSERT(r, lines == 1);
352 }
353 REPORTER_ASSERT(r, codec->getPixels(bm.info(), bm.getPixels(), bm.rowBytes())
354 == expectedResult);
355 REPORTER_ASSERT(r, codec->getScanlines(bm.getAddr(0, 0), 1, 0)
356 == 0);
357 REPORTER_ASSERT(r, codec->skipScanlines(1)
358 == 0);
359 }
360
361 // Test partial scanline decodes
362 if (supports_partial_scanlines(path) && info.width() >= 3) {
364 int width = info.width();
365 int height = info.height();
366 SkIRect subset = SkIRect::MakeXYWH(2 * (width / 3), 0, width / 3, height);
367 options.fSubset = &subset;
368
369 const auto partialStartResult = codec->startScanlineDecode(info, &options);
370 REPORTER_ASSERT(r, partialStartResult == SkCodec::kSuccess);
371
372 for (int y = 0; y < height; y++) {
373 const int lines = codec->getScanlines(bm.getAddr(0, y), 1, 0);
374 if (!supportsIncomplete) {
375 REPORTER_ASSERT(r, 1 == lines);
376 }
377 }
378 }
379 } else {
380 REPORTER_ASSERT(r, startResult == SkCodec::kUnimplemented);
381 }
382}
static bool supports_partial_scanlines(const char path[])
Definition: CodecTest.cpp:280
static void test_incremental_decode(skiatest::Reporter *r, SkCodec *codec, const SkImageInfo &info, const SkMD5::Digest &goodDigest)
Definition: CodecTest.cpp:131
static void test_in_stripes(skiatest::Reporter *r, SkCodec *codec, const SkImageInfo &info, const SkMD5::Digest &goodDigest)
Definition: CodecTest.cpp:145
const char * options
constexpr SkColor SK_ColorYELLOW
Definition: SkColor.h:139
bool SkStrEndsWith(const char string[], const char suffixStr[])
Definition: SkString.cpp:68
void * getAddr(int x, int y) const
Definition: SkBitmap.cpp:406
const SkImageInfo & info() const
Definition: SkBitmap.h:139
void eraseColor(SkColor4f) const
Definition: SkBitmap.cpp:442
int getScanlines(void *dst, int countLines, size_t rowBytes)
Definition: SkCodec.cpp:694
Result startScanlineDecode(const SkImageInfo &dstInfo, const Options *options)
Definition: SkCodec.cpp:635
@ kTopDown_SkScanlineOrder
Definition: SkCodec.h:581
SkScanlineOrder getScanlineOrder() const
Definition: SkCodec.h:613
@ kUnimplemented
Definition: SkCodec.h:123
bool skipScanlines(int countLines)
Definition: SkCodec.cpp:713
double y
int32_t height
int32_t width
static constexpr SkIRect MakeXYWH(int32_t x, int32_t y, int32_t w, int32_t h)
Definition: SkRect.h:104

◆ check_subset_decode()

static void check_subset_decode ( skiatest::Reporter r,
SkCodec codec,
const SkImageInfo info,
SkISize  size,
bool  supportsSubsetDecoding,
bool  supportsIncomplete 
)
static

Definition at line 384 of file CodecTest.cpp.

389 {
390 // This function tests decoding subsets, and will decode a handful of randomly-sized subsets.
391 // Do not attempt to decode subsets of an image of only one pixel, since there is no
392 // meaningful subset.
393 if (size.width() * size.height() == 1) {
394 return;
395 }
396
397 SkRandom rand;
398 SkIRect subset;
399 SkCodec::Options opts;
400 opts.fSubset = &subset;
401 for (int i = 0; i < 5; i++) {
402 subset = generate_random_subset(&rand, size.width(), size.height());
403 SkASSERT(!subset.isEmpty());
404 const bool supported = codec->getValidSubset(&subset);
405 REPORTER_ASSERT(r, supported == supportsSubsetDecoding);
406
407 SkImageInfo subsetInfo = info.makeDimensions(subset.size());
408 SkBitmap bm;
409 bm.allocPixels(subsetInfo);
410 const auto result = codec->getPixels(bm.info(), bm.getPixels(), bm.rowBytes(), &opts);
411
412 if (supportsSubsetDecoding) {
413 if (!supportsIncomplete) {
415 }
416 // Webp is the only codec that supports subsets, and it will have modified the subset
417 // to have even left/top.
418 REPORTER_ASSERT(r, SkIsAlign2(subset.fLeft) && SkIsAlign2(subset.fTop));
419 } else {
420 // No subsets will work.
422 }
423 }
424}
SkIRect generate_random_subset(SkRandom *rand, int w, int h)
Definition: CodecTest.cpp:119
static constexpr bool SkIsAlign2(T x)
Definition: SkAlign.h:19
#define SkASSERT(cond)
Definition: SkAssert.h:116
bool getValidSubset(SkIRect *desiredSubset) const
Definition: SkCodec.h:285
constexpr SkISize size() const
Definition: SkRect.h:172
int32_t fTop
smaller y-axis bounds
Definition: SkRect.h:34
bool isEmpty() const
Definition: SkRect.h:202
int32_t fLeft
smaller x-axis bounds
Definition: SkRect.h:33

◆ color_type_match()

static bool color_type_match ( SkColorType  origColorType,
SkColorType  codecColorType 
)
static

Definition at line 1104 of file CodecTest.cpp.

1104 {
1105 switch (origColorType) {
1108 return kRGBA_8888_SkColorType == codecColorType ||
1109 kBGRA_8888_SkColorType == codecColorType;
1110 default:
1111 return origColorType == codecColorType;
1112 }
1113}
@ kBGRA_8888_SkColorType
pixel with 8 bits for blue, green, red, alpha; in 32-bit word
Definition: SkColorType.h:26
@ kRGBA_8888_SkColorType
pixel with 8 bits for red, green, blue, alpha; in 32-bit word
Definition: SkColorType.h:24

◆ compare_to_good_digest()

static void compare_to_good_digest ( skiatest::Reporter r,
const SkMD5::Digest goodDigest,
const SkBitmap bm 
)
static

Compute the digest for bm and compare it to a known good digest.

Parameters
rReporter to assert that bm's digest matches goodDigest.
goodDigestThe known good digest to compare to.
bmThe bitmap to test.

Definition at line 93 of file CodecTest.cpp.

94 {
95 SkMD5::Digest digest = md5(bm);
96 REPORTER_ASSERT(r, digest == goodDigest);
97}

◆ decode_frame()

static void decode_frame ( skiatest::Reporter r,
SkCodec codec,
size_t  frame 
)
static

Definition at line 1250 of file CodecTest.cpp.

1250 {
1251 SkBitmap bm;
1252 auto info = codec->getInfo().makeColorType(kN32_SkColorType);
1253 bm.allocPixels(info);
1254
1255 SkCodec::Options opts;
1256 opts.fFrameIndex = frame;
1258 bm.getPixels(), bm.rowBytes(), &opts));
1259}
SkImageInfo getInfo() const
Definition: SkCodec.h:228
double frame
Definition: examples.cpp:31

◆ DEF_TEST() [1/40]

DEF_TEST ( Codec_78329453  ,
 
)

Definition at line 1756 of file CodecTest.cpp.

1756 {
1757 if (GetResourcePath().isEmpty()) {
1758 return;
1759 }
1760
1761 const char* file = "images/b78329453.jpeg";
1762 auto data = GetResourceAsData(file);
1763 if (!data) {
1764 ERRORF(r, "Missing %s", file);
1765 return;
1766 }
1767
1769 if (!codec) {
1770 ERRORF(r, "failed to create codec from %s", file);
1771 return;
1772 }
1773
1774 // A bug in jpeg_skip_scanlines resulted in an infinite loop for this specific
1775 // sample size on this image. Other sample sizes could have had the same result,
1776 // but the ones tested by DM happen to not.
1777 constexpr int kSampleSize = 19;
1778 const auto size = codec->getSampledDimensions(kSampleSize);
1779 auto info = codec->getInfo().makeDimensions(size);
1780 SkBitmap bm;
1781 bm.allocPixels(info);
1783
1785 options.fSampleSize = kSampleSize;
1786 auto result = codec->getAndroidPixels(info, bm.getPixels(), bm.rowBytes(), &options);
1787 if (result != SkCodec::kSuccess) {
1788 ERRORF(r, "failed to decode with error %s", SkCodec::ResultToString(result));
1789 }
1790}
sk_sp< SkData > GetResourceAsData(const char *resource)
Definition: Resources.cpp:42
SkString GetResourcePath(const char *resource)
Definition: Resources.cpp:23
constexpr SkColor SK_ColorTRANSPARENT
Definition: SkColor.h:99
static const char * ResultToString(Result)
Definition: SkCodec.cpp:880
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63

◆ DEF_TEST() [2/40]

DEF_TEST ( Codec_A8  ,
 
)

Definition at line 1792 of file CodecTest.cpp.

1792 {
1793 if (GetResourcePath().isEmpty()) {
1794 return;
1795 }
1796
1797 const char* file = "images/mandrill_cmyk.jpg";
1798 auto data = GetResourceAsData(file);
1799 if (!data) {
1800 ERRORF(r, "missing %s", file);
1801 return;
1802 }
1803
1804 auto codec = SkCodec::MakeFromData(std::move(data));
1805 auto info = codec->getInfo().makeColorType(kAlpha_8_SkColorType);
1806 SkBitmap bm;
1807 bm.allocPixels(info);
1808 REPORTER_ASSERT(r, codec->getPixels(bm.pixmap()) == SkCodec::kInvalidConversion);
1809}
@ kAlpha_8_SkColorType
pixel with alpha in 8-bit byte
Definition: SkColorType.h:21
@ kInvalidConversion
Definition: SkCodec.h:96

◆ DEF_TEST() [3/40]

DEF_TEST ( Codec_bmp  ,
 
)

Definition at line 539 of file CodecTest.cpp.

539 {
540 check(r, "images/randPixels.bmp", SkISize::Make(8, 8), true, false, true);
541 check(r, "images/rle.bmp", SkISize::Make(320, 240), true, false, true);
542}
static constexpr SkISize Make(int32_t w, int32_t h)
Definition: SkSize.h:20

◆ DEF_TEST() [4/40]

DEF_TEST ( Codec_ColorXform  ,
 
)

Definition at line 1099 of file CodecTest.cpp.

1099 {
1100 check_color_xform(r, "images/mandrill_512_q075.jpg");
1101 check_color_xform(r, "images/mandrill_512.png");
1102}
static void check_color_xform(skiatest::Reporter *r, const char *path)
Definition: CodecTest.cpp:1076

◆ DEF_TEST() [5/40]

DEF_TEST ( Codec_crbug807324  ,
 
)

Definition at line 1811 of file CodecTest.cpp.

1811 {
1812 if (GetResourcePath().isEmpty()) {
1813 return;
1814 }
1815
1816 const char* file = "images/crbug807324.png";
1818 if (!image) {
1819 ERRORF(r, "Missing %s", file);
1820 return;
1821 }
1822
1823 const int kWidth = image->width();
1824 const int kHeight = image->height();
1825
1826 SkBitmap bm;
1828 ERRORF(r, "Could not allocate pixels (%i x %i)", kWidth, kHeight);
1829 return;
1830 }
1831
1833
1834 SkCanvas canvas(bm);
1835 canvas.drawImage(image, 0, 0);
1836
1837 for (int i = 0; i < kWidth; ++i)
1838 for (int j = 0; j < kHeight; ++j) {
1839 if (*bm.getAddr32(i, j) == SK_ColorTRANSPARENT) {
1840 ERRORF(r, "image should not be transparent! %i, %i is 0", i, j);
1841 return;
1842 }
1843 }
1844}
uint32_t * getAddr32(int x, int y) const
Definition: SkBitmap.h:1260
bool tryAllocPixels(const SkImageInfo &info, size_t rowBytes)
Definition: SkBitmap.cpp:271
int width() const
Definition: SkImage.h:285
int height() const
Definition: SkImage.h:291
sk_sp< const SkImage > image
Definition: SkRecords.h:269
sk_sp< SkImage > GetResourceAsImage(const char *resource)
Definition: DecodeUtils.h:25
static SkImageInfo MakeN32Premul(int width, int height)
constexpr size_t kHeight
constexpr size_t kWidth

◆ DEF_TEST() [6/40]

DEF_TEST ( Codec_Dimensions  ,
 
)

Definition at line 673 of file CodecTest.cpp.

673 {
674 // JPG
675 test_dimensions(r, "images/CMYK.jpg");
676 test_dimensions(r, "images/color_wheel.jpg");
677 test_dimensions(r, "images/grayscale.jpg");
678 test_dimensions(r, "images/mandrill_512_q075.jpg");
679 test_dimensions(r, "images/randPixels.jpg");
680
681 // Decoding small images with very large scaling factors is a potential
682 // source of bugs and crashes. We disable these tests in Gold because
683 // tiny images are not very useful to look at.
684 // Here we make sure that we do not crash or access illegal memory when
685 // performing scaled decodes on small images.
686 test_dimensions(r, "images/1x1.png");
687 test_dimensions(r, "images/2x2.png");
688 test_dimensions(r, "images/3x3.png");
689 test_dimensions(r, "images/3x1.png");
690 test_dimensions(r, "images/1x1.png");
691 test_dimensions(r, "images/16x1.png");
692 test_dimensions(r, "images/1x16.png");
693 test_dimensions(r, "images/mandrill_16.png");
694
695 // RAW
696// Disable RAW tests for Win32.
697#if defined(SK_CODEC_DECODES_RAW) && (!defined(_WIN32))
698 test_dimensions(r, "images/sample_1mp.dng");
699 test_dimensions(r, "images/sample_1mp_rotated.dng");
700 test_dimensions(r, "images/dng_with_preview.dng");
701#endif
702}
static void test_dimensions(skiatest::Reporter *r, const char path[])
Definition: CodecTest.cpp:636

◆ DEF_TEST() [7/40]

DEF_TEST ( Codec_Empty  ,
 
)

Definition at line 714 of file CodecTest.cpp.

714 {
715 if (GetResourcePath().isEmpty()) {
716 return;
717 }
718
719 // Test images that should not be able to create a codec
720 test_invalid(r, "empty_images/zero-dims.gif");
721 test_invalid(r, "empty_images/zero-embedded.ico");
722 test_invalid(r, "empty_images/zero-width.bmp");
723 test_invalid(r, "empty_images/zero-height.bmp");
724 test_invalid(r, "empty_images/zero-width.jpg");
725 test_invalid(r, "empty_images/zero-height.jpg");
726 test_invalid(r, "empty_images/zero-width.png");
727 test_invalid(r, "empty_images/zero-height.png");
728 test_invalid(r, "empty_images/zero-width.wbmp");
729 test_invalid(r, "empty_images/zero-height.wbmp");
730 // This image is an ico with an embedded mask-bmp. This is illegal.
731 test_invalid(r, "invalid_images/mask-bmp-ico.ico");
732 // It is illegal for a webp frame to not be fully contained by the canvas.
733 test_invalid(r, "invalid_images/invalid-offset.webp");
734#if defined(SK_CODEC_DECODES_RAW) && (!defined(_WIN32))
735 test_invalid(r, "empty_images/zero_height.tiff");
736#endif
737 test_invalid(r, "invalid_images/b37623797.ico");
738 test_invalid(r, "invalid_images/osfuzz6295.webp");
739 test_invalid(r, "invalid_images/osfuzz6288.bmp");
740 test_invalid(r, "invalid_images/ossfuzz6347");
741}
static void test_invalid(skiatest::Reporter *r, const char path[])
Definition: CodecTest.cpp:704

◆ DEF_TEST() [8/40]

DEF_TEST ( Codec_EncodeICC  ,
 
)

Definition at line 1692 of file CodecTest.cpp.

1692 {
1696}
static void test_encode_icc(skiatest::Reporter *r, SkEncodedImageFormat format)
Definition: CodecTest.cpp:1657

◆ DEF_TEST() [9/40]

DEF_TEST ( Codec_F16_noColorSpace  ,
 
)

Definition at line 1846 of file CodecTest.cpp.

1846 {
1847 const char* path = "images/color_wheel.png";
1848 auto data = GetResourceAsData(path);
1849 if (!data) {
1850 return;
1851 }
1852
1853 auto codec = SkCodec::MakeFromData(std::move(data));
1854 SkImageInfo info = codec->getInfo().makeColorType(kRGBA_F16_SkColorType)
1855 .makeColorSpace(nullptr);
1856 test_info(r, codec.get(), info, SkCodec::kSuccess, nullptr);
1857}
@ kRGBA_F16_SkColorType
pixel with half floats for red, green, blue, alpha;
Definition: SkColorType.h:38

◆ DEF_TEST() [10/40]

DEF_TEST ( Codec_F16ConversionPossible  ,
 
)

Definition at line 1244 of file CodecTest.cpp.

1244 {
1245 test_conversion_possible(r, "images/color_wheel.webp", false, false);
1246 test_conversion_possible(r, "images/mandrill_512_q075.jpg", true, false);
1247 test_conversion_possible(r, "images/yellow_rose.png", false, true);
1248}
static void test_conversion_possible(skiatest::Reporter *r, const char *path, bool supportsScanlineDecoder, bool supportsIncrementalDecoder)
Definition: CodecTest.cpp:1189

◆ DEF_TEST() [11/40]

DEF_TEST ( Codec_fallBack  ,
 
)

Definition at line 1340 of file CodecTest.cpp.

1340 {
1341 // SkAndroidCodec needs to be able to fall back to scanline decoding
1342 // if incremental decoding does not work. Make sure this does not
1343 // require a rewind.
1344
1345 // Formats that currently do not support incremental decoding
1346 auto files = {
1347 "images/CMYK.jpg",
1348 "images/color_wheel.ico",
1349 "images/mandrill.wbmp",
1350 "images/randPixels.bmp",
1351 };
1352 for (auto file : files) {
1354 if (!stream) {
1355 SkDebugf("Missing resources (%s). Set --resourcePath.\n", file);
1356 return;
1357 }
1358
1359 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromStream(std::move(stream)));
1360 if (!codec) {
1361 ERRORF(r, "Failed to create codec for %s,", file);
1362 continue;
1363 }
1364
1365 SkImageInfo info = codec->getInfo().makeColorType(kN32_SkColorType);
1366 SkBitmap bm;
1367 bm.allocPixels(info);
1368
1369 if (SkCodec::kUnimplemented != codec->startIncrementalDecode(info, bm.getPixels(),
1370 bm.rowBytes())) {
1371 ERRORF(r, "Is scanline decoding now implemented for %s?", file);
1372 continue;
1373 }
1374
1375 // Scanline decoding should not require a rewind.
1376 SkCodec::Result result = codec->startScanlineDecode(info);
1377 if (SkCodec::kSuccess != result) {
1378 ERRORF(r, "Scanline decoding failed for %s with %i", file, result);
1379 }
1380 }
1381}
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
static std::unique_ptr< SkStream > Make(const char path[], size_t limit)
Definition: CodecTest.cpp:1299

◆ DEF_TEST() [12/40]

DEF_TEST ( Codec_gif  ,
 
)

Definition at line 553 of file CodecTest.cpp.

553 {
554 check(r, "images/box.gif", SkISize::Make(200, 55), false, false, true, true);
555 check(r, "images/color_wheel.gif", SkISize::Make(128, 128), false, false, true, true);
556 // randPixels.gif is too small to test incomplete
557 check(r, "images/randPixels.gif", SkISize::Make(8, 8), false, false, false, true);
558}

◆ DEF_TEST() [13/40]

DEF_TEST ( Codec_gif_can_preserve_original_data  ,
 
)

Definition at line 2021 of file CodecTest.cpp.

2021 {
2022 constexpr char path[] = "images/flightAnim.gif";
2024 if (!data) {
2025 SkDebugf("Missing resource '%s'\n", path);
2026 return;
2027 }
2028
2030 auto codec = SkGifDecoder::Decode(data, &result, nullptr);
2032 REPORTER_ASSERT(r, codec);
2033
2036 REPORTER_ASSERT(r, image->width() == 320, "width %d != 320", image->width());
2037 REPORTER_ASSERT(r, image->height() == 240, "height %d != 240", image->height());
2040 "AlphaType is wrong %d",
2041 image->alphaType());
2042
2043 // The whole point of DeferredFromCodec is that it allows the client
2044 // to hold onto the original image data for later.
2045 sk_sp<SkData> encodedData = image->refEncodedData();
2046 REPORTER_ASSERT(r, encodedData != nullptr);
2047 // The returned data should the same as what went in.
2048 REPORTER_ASSERT(r, encodedData->size() == data->size());
2049 REPORTER_ASSERT(r, encodedData->bytes() == data->bytes());
2050}
const uint8_t * bytes() const
Definition: SkData.h:43
size_t size() const
Definition: SkData.h:30
SkAlphaType alphaType() const
Definition: SkImage.cpp:154
sk_sp< SkData > refEncodedData() const
Definition: SkImage.cpp:214
SK_API sk_sp< SkImage > DeferredImage(std::unique_ptr< SkCodec > codec, std::optional< SkAlphaType > alphaType=std::nullopt)
SK_API std::unique_ptr< SkCodec > Decode(std::unique_ptr< SkStream >, SkCodec::Result *, SkCodecs::DecodeContext=nullptr)

◆ DEF_TEST() [14/40]

DEF_TEST ( Codec_gif_notseekable  ,
 
)

Definition at line 1921 of file CodecTest.cpp.

1921 {
1922 constexpr char path[] = "images/flightAnim.gif";
1924 if (!data) {
1925 SkDebugf("Missing resource '%s'\n", path);
1926 return;
1927 }
1928
1929 // Verify that using a non-seekable stream works the same as a seekable one for
1930 // decoding the first frame.
1931 const SkMD5::Digest goodDigest = [data, &r]() {
1932 auto codec = SkCodec::MakeFromStream(std::make_unique<SkMemoryStream>(data),
1933 nullptr, nullptr,
1935 REPORTER_ASSERT(r, codec->getFrameCount() == 60);
1936 const auto info = codec->getInfo();
1937
1938 SkBitmap bm;
1939 bm.allocPixels(info);
1940
1941 SkCodec::Result result = codec->getPixels(info, bm.getPixels(), bm.rowBytes());
1943 return md5(bm);
1944 }();
1945
1946 auto codec = SkCodec::MakeFromStream(std::make_unique<NonseekableStream>(std::move(data)),
1947 nullptr, nullptr,
1949 REPORTER_ASSERT(r, codec->getFrameCount() == 1);
1950
1951 test_info(r, codec.get(), codec->getInfo(), SkCodec::kSuccess, &goodDigest);
1952}

◆ DEF_TEST() [15/40]

DEF_TEST ( Codec_gif_notseekable2  ,
 
)

Definition at line 1954 of file CodecTest.cpp.

1954 {
1955 constexpr char path[] = "images/flightAnim.gif";
1957 if (!data) {
1958 SkDebugf("Missing resource '%s'\n", path);
1959 return;
1960 }
1961
1962 // Verify that using a non-seekable stream works the same as a seekable one for
1963 // decoding a later frame.
1965 options.fFrameIndex = 5;
1966
1967 const SkMD5::Digest goodDigest = [data, &r, &options]() {
1968 auto codec = SkCodec::MakeFromStream(std::make_unique<SkMemoryStream>(data),
1969 nullptr, nullptr,
1971 REPORTER_ASSERT(r, codec->getFrameCount() == 60);
1972 const auto info = codec->getInfo();
1973
1974 SkBitmap bm;
1975 bm.allocPixels(info);
1976
1977 SkCodec::Result result = codec->getPixels(info, bm.getPixels(), bm.rowBytes(), &options);
1979 return md5(bm);
1980 }();
1981
1982 // This should copy the non seekable stream.
1983 auto codec = SkCodec::MakeFromStream(std::make_unique<NonseekableStream>(std::move(data)),
1984 nullptr, nullptr,
1986 REPORTER_ASSERT(r, codec->getFrameCount() == 60);
1987
1988 SkBitmap bm;
1989 bm.allocPixels(codec->getInfo());
1990
1991 SkCodec::Result result = codec->getPixels(codec->getInfo(), bm.getPixels(), bm.rowBytes(),
1992 &options);
1994 compare_to_good_digest(r, goodDigest, bm);
1995}

◆ DEF_TEST() [16/40]

DEF_TEST ( Codec_gif_null_param  ,
 
)

Definition at line 1997 of file CodecTest.cpp.

1997 {
1998 constexpr char path[] = "images/flightAnim.gif";
2000 if (!data) {
2001 SkDebugf("Missing resource '%s'\n", path);
2002 return;
2003 }
2004
2006 auto codec = SkGifDecoder::Decode(std::make_unique<SkMemoryStream>(std::move(data)),
2007 &result, nullptr);
2009 REPORTER_ASSERT(r, codec);
2010
2011 auto [image, res] = codec->getImage();
2014 REPORTER_ASSERT(r, image->width() == 320, "width %d != 320", image->width());
2015 REPORTER_ASSERT(r, image->height() == 240, "height %d != 240", image->height());
2016
2017 // Decoding the image this way loses the original data.
2019}

◆ DEF_TEST() [17/40]

DEF_TEST ( Codec_ico  ,
 
)

Definition at line 544 of file CodecTest.cpp.

544 {
545 // FIXME: We are not ready to test incomplete ICOs
546 // These two tests examine interestingly different behavior:
547 // Decodes an embedded BMP image
548 check(r, "images/color_wheel.ico", SkISize::Make(128, 128), true, false, false);
549 // Decodes an embedded PNG image
550 check(r, "images/google_chrome.ico", SkISize::Make(256, 256), false, false, false, true);
551}

◆ DEF_TEST() [18/40]

DEF_TEST ( Codec_InvalidAnimated  ,
 
)

Definition at line 1603 of file CodecTest.cpp.

1603 {
1604 // ASAN will complain if there is an issue.
1605 auto path = "invalid_images/skbug6046.gif";
1607 if (!stream) {
1608 return;
1609 }
1610
1611 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromStream(std::move(stream)));
1612 REPORTER_ASSERT(r, codec);
1613 if (!codec) {
1614 return;
1615 }
1616
1617 const auto info = codec->getInfo().makeColorType(kN32_SkColorType);
1618 SkBitmap bm;
1619 bm.allocPixels(info);
1620
1621 auto frameInfos = codec->getFrameInfo();
1622 SkCodec::Options opts;
1623 for (int i = 0; static_cast<size_t>(i) < frameInfos.size(); i++) {
1624 opts.fFrameIndex = i;
1625 const auto reqFrame = frameInfos[i].fRequiredFrame;
1626 opts.fPriorFrame = reqFrame == i - 1 ? reqFrame : SkCodec::kNoFrame;
1627 auto result = codec->startIncrementalDecode(info, bm.getPixels(), bm.rowBytes(), &opts);
1628
1629 if (result != SkCodec::kSuccess) {
1630 ERRORF(r, "Failed to start decoding frame %i (out of %zu) with error %i\n", i,
1631 frameInfos.size(), result);
1632 continue;
1633 }
1634
1635 codec->incrementalDecode();
1636 }
1637}
static constexpr int kNoFrame
Definition: SkCodec.h:650

◆ DEF_TEST() [19/40]

DEF_TEST ( Codec_InvalidHeader  ,
 
)

Definition at line 1528 of file CodecTest.cpp.

1528 {
1529 test_invalid_header(r, "invalid_images/int_overflow.ico");
1530
1531 // These files report values that have caused problems with SkFILEStreams.
1532 // They are invalid, and should not create SkCodecs.
1533 test_invalid_header(r, "invalid_images/b33651913.bmp");
1534 test_invalid_header(r, "invalid_images/b34778578.bmp");
1535}
static void test_invalid_header(skiatest::Reporter *r, const char *path)
Definition: CodecTest.cpp:1515

◆ DEF_TEST() [20/40]

DEF_TEST ( Codec_InvalidImages  ,
 
)

Definition at line 1494 of file CodecTest.cpp.

1494 {
1495 test_invalid_images(r, "invalid_images/b33251605.bmp", SkCodec::kIncompleteInput);
1496 test_invalid_images(r, "invalid_images/bad_palette.png", SkCodec::kInvalidInput);
1497 test_invalid_images(r, "invalid_images/many-progressive-scans.jpg", SkCodec::kInvalidInput);
1498
1499 // An earlier revision of this test case passed kErrorInInput (instead of
1500 // kSuccess) as the third argument (expectedResult). However, after
1501 // https://skia-review.googlesource.com/c/skia/+/414417 `SkWuffsCodec:
1502 // ignore too much pixel data` combined with
1503 // https://github.com/google/wuffs/commit/e44920d3 `Let gif "ignore too
1504 // much" quirk skip lzw errors`, the codec silently accepts skbug5887.gif
1505 // (without the ASAN buffer-overflow violation that lead to that test case
1506 // in the first place), even though it's technically an invalid GIF.
1507 //
1508 // Note that, in practice, real world GIF decoders already diverge (in
1509 // different ways) from the GIF specification. For compatibility, (ad hoc)
1510 // implementation often trumps specification.
1511 // https://github.com/google/wuffs/blob/e44920d3/test/data/artificial-gif/frame-out-of-bounds.gif.make-artificial.txt#L30-L31
1512 test_invalid_images(r, "invalid_images/skbug5887.gif", SkCodec::kSuccess);
1513}
static void test_invalid_images(skiatest::Reporter *r, const char *path, SkCodec::Result expectedResult)
Definition: CodecTest.cpp:1480
@ kInvalidInput
Definition: SkCodec.h:109

◆ DEF_TEST() [21/40]

DEF_TEST ( Codec_jpeg_can_return_data_from_original_stream  ,
 
)

Definition at line 2052 of file CodecTest.cpp.

2052 {
2053 constexpr char path[] = "images/dog.jpg";
2054 // stream will be an SkFILEStream, not a SkMemoryStream (exercised above)
2055 std::unique_ptr<SkStreamAsset> stream = GetResourceAsStream(path, true);
2056 if (!stream) {
2057 SkDebugf("Missing resource '%s'\n", path);
2058 return;
2059 }
2060 size_t expectedBytes = stream->getLength();
2061
2063 auto codec = SkJpegDecoder::Decode(std::move(stream), &result, nullptr);
2065 REPORTER_ASSERT(r, codec);
2066
2069 REPORTER_ASSERT(r, image->width() == 180, "width %d != 180", image->width());
2070 REPORTER_ASSERT(r, image->height() == 180, "height %d != 180", image->height());
2073 "AlphaType is wrong %d",
2074 image->alphaType());
2075
2076 // The whole point of DeferredFromCodec is that it allows the client
2077 // to hold onto the original image data for later.
2078 sk_sp<SkData> encodedData = image->refEncodedData();
2079 REPORTER_ASSERT(r, encodedData != nullptr);
2080 // The returned data should the same as what went in.
2081 REPORTER_ASSERT(r, encodedData->size() == expectedBytes);
2082 REPORTER_ASSERT(r, SkJpegDecoder::IsJpeg(encodedData->data(), encodedData->size()));
2083}
const void * data() const
Definition: SkData.h:37
SK_API bool IsJpeg(const void *, size_t)
SK_API std::unique_ptr< SkCodec > Decode(std::unique_ptr< SkStream >, SkCodec::Result *, SkCodecs::DecodeContext=nullptr)

◆ DEF_TEST() [22/40]

DEF_TEST ( Codec_jpeg_rewind  ,
 
)

Definition at line 1026 of file CodecTest.cpp.

1026 {
1027 const char* path = "images/mandrill_512_q075.jpg";
1029 if (!data) {
1030 return;
1031 }
1032
1033 data = SkData::MakeSubset(data.get(), 0, data->size() / 2);
1034 std::unique_ptr<SkAndroidCodec> codec(SkAndroidCodec::MakeFromData(data));
1035 if (!codec) {
1036 ERRORF(r, "Unable to create codec '%s'.", path);
1037 return;
1038 }
1039
1040 const int width = codec->getInfo().width();
1041 const int height = codec->getInfo().height();
1042 size_t rowBytes = sizeof(SkPMColor) * width;
1043 SkAutoMalloc pixelStorage(height * rowBytes);
1044
1045 // Perform a sampled decode.
1047 opts.fSampleSize = 12;
1048 auto sampledInfo = codec->getInfo().makeWH(width / 12, height / 12);
1049 auto result = codec->getAndroidPixels(sampledInfo, pixelStorage.get(), rowBytes, &opts);
1051
1052 // Rewind the codec and perform a full image decode.
1053 result = codec->getPixels(codec->getInfo(), pixelStorage.get(), rowBytes);
1055
1056 // Now perform a subset decode.
1057 {
1058 opts.fSampleSize = 1;
1059 SkIRect subset = SkIRect::MakeWH(100, 100);
1060 opts.fSubset = &subset;
1061 result = codec->getAndroidPixels(codec->getInfo().makeWH(100, 100), pixelStorage.get(),
1062 rowBytes, &opts);
1063 // Though we only have half the data, it is enough to decode this subset.
1065 }
1066
1067 // Perform another full image decode. ASAN will detect if we look at the subset when it is
1068 // out of scope. This would happen if we depend on the old state in the codec.
1069 // This tests two layers of bugs: both SkJpegCodec::readRows and SkCodec::fillIncompleteImage
1070 // used to look at the old subset.
1071 opts.fSubset = nullptr;
1072 result = codec->getAndroidPixels(codec->getInfo(), pixelStorage.get(), rowBytes, &opts);
1074}
uint32_t SkPMColor
Definition: SkColor.h:205
static std::unique_ptr< SkAndroidCodec > MakeFromData(sk_sp< SkData >, SkPngChunkReader *=nullptr)
static sk_sp< SkData > MakeSubset(const SkData *src, size_t offset, size_t length)
Definition: SkData.cpp:173

◆ DEF_TEST() [23/40]

DEF_TEST ( Codec_jpg  ,
 
)

Definition at line 560 of file CodecTest.cpp.

560 {
561 check(r, "images/CMYK.jpg", SkISize::Make(642, 516), true, false, true);
562 check(r, "images/color_wheel.jpg", SkISize::Make(128, 128), true, false, true);
563 // grayscale.jpg is too small to test incomplete
564 check(r, "images/grayscale.jpg", SkISize::Make(128, 128), true, false, false);
565 check(r, "images/mandrill_512_q075.jpg", SkISize::Make(512, 512), true, false, true);
566 // randPixels.jpg is too small to test incomplete
567 check(r, "images/randPixels.jpg", SkISize::Make(8, 8), true, false, false);
568}

◆ DEF_TEST() [24/40]

DEF_TEST ( Codec_kBGR_101010x_XR_SkColorType_supported  ,
 
)

Definition at line 1903 of file CodecTest.cpp.

1903 {
1904 SkBitmap srcBm;
1905 SkImageInfo srcInfo = SkImageInfo()
1906 .makeWH(100, 100)
1911 srcBm.allocPixels(srcInfo);
1914 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(stream.detachAsData()));
1915 SkBitmap dstBm;
1916 dstBm.allocPixels(dstInfo);
1917 bool success = codec->getPixels(dstInfo, dstBm.getPixels(), dstBm.rowBytes());
1918 REPORTER_ASSERT(r, SkCodec::kSuccess == success);
1919}
@ kOpaque_SkAlphaType
pixel is opaque
Definition: SkAlphaType.h:28
@ kBGR_101010x_XR_SkColorType
pixel with 10 bits each for blue, green, red; in 32-bit word, extended range
Definition: SkColorType.h:31
static sk_sp< SkColorSpace > MakeSRGB()
SkImageInfo makeAlphaType(SkAlphaType newAlphaType) const
Definition: SkImageInfo.h:466

◆ DEF_TEST() [25/40]

DEF_TEST ( Codec_leaks  ,
 
)

Definition at line 608 of file CodecTest.cpp.

608 {
609 // No codec should claim this as their format, so this tests SkCodec::NewFromStream.
610 const char nonSupportedStream[] = "hello world";
611 // The other strings should look like the beginning of a file type, so we'll call some
612 // internal version of NewFromStream, which must also delete the stream on failure.
613 const unsigned char emptyPng[] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a };
614 const unsigned char emptyJpeg[] = { 0xFF, 0xD8, 0xFF };
615 const char emptyWebp[] = "RIFF1234WEBPVP";
616 const char emptyBmp[] = { 'B', 'M' };
617 const char emptyIco[] = { '\x00', '\x00', '\x01', '\x00' };
618 const char emptyGif[] = "GIFVER";
619
620 test_invalid_stream(r, nonSupportedStream, sizeof(nonSupportedStream));
621 test_invalid_stream(r, emptyPng, sizeof(emptyPng));
622 test_invalid_stream(r, emptyJpeg, sizeof(emptyJpeg));
623 test_invalid_stream(r, emptyWebp, sizeof(emptyWebp));
624 test_invalid_stream(r, emptyBmp, sizeof(emptyBmp));
625 test_invalid_stream(r, emptyIco, sizeof(emptyIco));
626 test_invalid_stream(r, emptyGif, sizeof(emptyGif));
627}
static void test_invalid_stream(skiatest::Reporter *r, const void *stream, size_t len)
Definition: CodecTest.cpp:598

◆ DEF_TEST() [26/40]

DEF_TEST ( Codec_noConversion  ,
 
)

Definition at line 1862 of file CodecTest.cpp.

1862 {
1863 const struct Rec {
1864 const char* name;
1865 SkColor color;
1866 } recs[] = {
1867 { "images/cmyk_yellow_224_224_32.jpg", 0xFFD8FC04 },
1868 { "images/wide_gamut_yellow_224_224_64.jpeg",0xFFE0E040 },
1869 };
1870
1871 for (const auto& rec : recs) {
1872 auto data = GetResourceAsData(rec.name);
1873 if (!data) {
1874 continue;
1875 }
1876
1877 auto codec = SkCodec::MakeFromData(std::move(data));
1878 if (!codec) {
1879 ERRORF(r, "Failed to create a codec from %s", rec.name);
1880 continue;
1881 }
1882
1883 const auto* profile = codec->getICCProfile();
1884 if (!profile) {
1885 ERRORF(r, "Expected %s to have a profile", rec.name);
1886 continue;
1887 }
1888
1889 auto cs = SkColorSpace::Make(*profile);
1890 REPORTER_ASSERT(r, !cs.get());
1891
1892 SkImageInfo info = codec->getInfo().makeColorSpace(nullptr);
1893 SkBitmap bm;
1894 bm.allocPixels(info);
1895 if (codec->getPixels(info, bm.getPixels(), bm.rowBytes()) != SkCodec::kSuccess) {
1896 ERRORF(r, "Failed to decode %s", rec.name);
1897 continue;
1898 }
1899 REPORTER_ASSERT(r, bm.getColor(0, 0) == rec.color);
1900 }
1901}
uint32_t SkColor
Definition: SkColor.h:37
SkColor getColor(int x, int y) const
Definition: SkBitmap.h:874
static sk_sp< SkColorSpace > Make(const skcms_ICCProfile &)
DlColor color
DEF_SWITCHES_START aot vmservice shared library name
Definition: switches.h:32

◆ DEF_TEST() [27/40]

DEF_TEST ( Codec_null  ,
 
)

Definition at line 629 of file CodecTest.cpp.

629 {
630 // Attempting to create an SkCodec or an SkAndroidCodec with null should not
631 // crash.
634}

◆ DEF_TEST() [28/40]

DEF_TEST ( Codec_ossfuzz6274  ,
 
)

Definition at line 1743 of file CodecTest.cpp.

1743 {
1744 if (GetResourcePath().isEmpty()) {
1745 return;
1746 }
1747
1748 const char* file = "invalid_images/ossfuzz6274.gif";
1750
1751 if (image) {
1752 ERRORF(r, "Invalid data gave non-nullptr image");
1753 }
1754}

◆ DEF_TEST() [29/40]

DEF_TEST ( Codec_png  ,
 
)

Definition at line 570 of file CodecTest.cpp.

570 {
571 check(r, "images/arrow.png", SkISize::Make(187, 312), false, false, true, true);
572 check(r, "images/baby_tux.png", SkISize::Make(240, 246), false, false, true, true);
573 check(r, "images/color_wheel.png", SkISize::Make(128, 128), false, false, true, true);
574 // half-transparent-white-pixel.png is too small to test incomplete
575 check(r, "images/half-transparent-white-pixel.png", SkISize::Make(1, 1), false, false, false, true);
576 check(r, "images/mandrill_128.png", SkISize::Make(128, 128), false, false, true, true);
577 // mandrill_16.png is too small (relative to embedded sRGB profile) to test incomplete
578 check(r, "images/mandrill_16.png", SkISize::Make(16, 16), false, false, false, true);
579 check(r, "images/mandrill_256.png", SkISize::Make(256, 256), false, false, true, true);
580 check(r, "images/mandrill_32.png", SkISize::Make(32, 32), false, false, true, true);
581 check(r, "images/mandrill_512.png", SkISize::Make(512, 512), false, false, true, true);
582 check(r, "images/mandrill_64.png", SkISize::Make(64, 64), false, false, true, true);
583 check(r, "images/plane.png", SkISize::Make(250, 126), false, false, true, true);
584 check(r, "images/plane_interlaced.png", SkISize::Make(250, 126), false, false, true, true);
585 check(r, "images/randPixels.png", SkISize::Make(8, 8), false, false, true, true);
586 check(r, "images/yellow_rose.png", SkISize::Make(400, 301), false, false, true, true);
587}

◆ DEF_TEST() [30/40]

DEF_TEST ( Codec_PngRoundTrip  ,
 
)

Definition at line 1148 of file CodecTest.cpp.

1148 {
1149 auto codec = SkCodec::MakeFromStream(GetResourceAsStream("images/mandrill_512_q075.jpg"));
1150
1151 SkColorType colorTypesOpaque[] = {
1153 };
1154 for (SkColorType colorType : colorTypesOpaque) {
1155 SkImageInfo newInfo = codec->getInfo().makeColorType(colorType);
1156 check_round_trip(r, codec.get(), newInfo);
1157 }
1158
1159 codec = SkCodec::MakeFromStream(GetResourceAsStream("images/grayscale.jpg"));
1160 check_round_trip(r, codec.get(), codec->getInfo());
1161
1162 codec = SkCodec::MakeFromStream(GetResourceAsStream("images/yellow_rose.png"));
1163
1164 SkColorType colorTypesWithAlpha[] = {
1166 };
1167 SkAlphaType alphaTypes[] = {
1169 };
1170 for (SkColorType colorType : colorTypesWithAlpha) {
1171 for (SkAlphaType alphaType : alphaTypes) {
1172 // Set color space to nullptr because color correct premultiplies do not round trip.
1173 SkImageInfo newInfo = codec->getInfo().makeColorType(colorType)
1174 .makeAlphaType(alphaType)
1175 .makeColorSpace(nullptr);
1176 check_round_trip(r, codec.get(), newInfo);
1177 }
1178 }
1179
1180 codec = SkCodec::MakeFromStream(GetResourceAsStream("images/index8.png"));
1181
1182 for (SkAlphaType alphaType : alphaTypes) {
1183 SkImageInfo newInfo = codec->getInfo().makeAlphaType(alphaType)
1184 .makeColorSpace(nullptr);
1185 check_round_trip(r, codec.get(), newInfo);
1186 }
1187}
static void check_round_trip(skiatest::Reporter *r, SkCodec *origCodec, const SkImageInfo &info)
Definition: CodecTest.cpp:1126
SkAlphaType
Definition: SkAlphaType.h:26
SkColorType
Definition: SkColorType.h:19
@ kRGB_565_SkColorType
pixel with 5 bits red, 6 bits green, 5 bits blue, in 16-bit word
Definition: SkColorType.h:22
static SkColorType colorType(AImageDecoder *decoder, const AImageDecoderHeaderInfo *headerInfo)

◆ DEF_TEST() [31/40]

DEF_TEST ( Codec_reusePng  ,
 
)

Definition at line 1424 of file CodecTest.cpp.

1424 {
1425 std::unique_ptr<SkStream> stream(GetResourceAsStream("images/plane.png"));
1426 if (!stream) {
1427 return;
1428 }
1429
1430 std::unique_ptr<SkAndroidCodec> codec(SkAndroidCodec::MakeFromStream(std::move(stream)));
1431 if (!codec) {
1432 ERRORF(r, "Failed to create codec\n");
1433 return;
1434 }
1435
1437 opts.fSampleSize = 5;
1438 auto size = codec->getSampledDimensions(opts.fSampleSize);
1439 auto info = codec->getInfo().makeDimensions(size).makeColorType(kN32_SkColorType);
1440 SkBitmap bm;
1441 bm.allocPixels(info);
1442 auto result = codec->getAndroidPixels(info, bm.getPixels(), bm.rowBytes(), &opts);
1444
1445 info = codec->getInfo().makeColorType(kN32_SkColorType);
1446 bm.allocPixels(info);
1447 opts.fSampleSize = 1;
1448 result = codec->getAndroidPixels(info, bm.getPixels(), bm.rowBytes(), &opts);
1450}

◆ DEF_TEST() [32/40]

DEF_TEST ( Codec_rowsDecoded  ,
 
)

Definition at line 1452 of file CodecTest.cpp.

1452 {
1453 auto file = "images/plane_interlaced.png";
1454 std::unique_ptr<SkStream> stream(GetResourceAsStream(file));
1455 if (!stream) {
1456 return;
1457 }
1458
1459 // This is enough to read the header etc, but no rows.
1460 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(SkData::MakeFromStream(stream.get(), 99)));
1461 if (!codec) {
1462 ERRORF(r, "Failed to create codec\n");
1463 return;
1464 }
1465
1466 auto info = codec->getInfo().makeColorType(kN32_SkColorType);
1467 SkBitmap bm;
1468 bm.allocPixels(info);
1469 auto result = codec->startIncrementalDecode(info, bm.getPixels(), bm.rowBytes());
1471
1472 // This is an arbitrary value. The important fact is that it is not zero, and rowsDecoded
1473 // should get set to zero by incrementalDecode.
1474 int rowsDecoded = 77;
1475 result = codec->incrementalDecode(&rowsDecoded);
1477 REPORTER_ASSERT(r, rowsDecoded == 0);
1478}

◆ DEF_TEST() [33/40]

DEF_TEST ( Codec_skipFullParse  ,
 
)

Definition at line 1263 of file CodecTest.cpp.

1263 {
1264 auto path = "images/test640x479.gif";
1265 auto streamObj = GetResourceAsStream(path);
1266 if (!streamObj) {
1267 return;
1268 }
1269 SkStream* stream = streamObj.get();
1270
1271 // Note that we cheat and hold on to the stream pointer, but SkCodec will
1272 // take ownership. We will not refer to the stream after the SkCodec
1273 // deletes it.
1274 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromStream(std::move(streamObj)));
1275 if (!codec) {
1276 ERRORF(r, "Failed to create codec for %s", path);
1277 return;
1278 }
1279
1280 REPORTER_ASSERT(r, stream->hasPosition());
1281 const size_t sizePosition = stream->getPosition();
1282 REPORTER_ASSERT(r, stream->hasLength() && sizePosition < stream->getLength());
1283
1284 // This should read more of the stream, but not the whole stream.
1285 decode_frame(r, codec.get(), 0);
1286 const size_t positionAfterFirstFrame = stream->getPosition();
1287 REPORTER_ASSERT(r, positionAfterFirstFrame > sizePosition
1288 && positionAfterFirstFrame < stream->getLength());
1289
1290 // There is more data in the stream.
1291 auto frameInfo = codec->getFrameInfo();
1292 REPORTER_ASSERT(r, frameInfo.size() == 4);
1293 REPORTER_ASSERT(r, stream->getPosition() > positionAfterFirstFrame);
1294}
static void decode_frame(skiatest::Reporter *r, SkCodec *codec, size_t frame)
Definition: CodecTest.cpp:1250

◆ DEF_TEST() [34/40]

DEF_TEST ( Codec_wbmp  ,
 
)

Definition at line 529 of file CodecTest.cpp.

529 {
530 check(r, "images/mandrill.wbmp", SkISize::Make(512, 512), true, false, true);
531}

◆ DEF_TEST() [35/40]

DEF_TEST ( Codec_wbmp_max_size  ,
 
)

Definition at line 1002 of file CodecTest.cpp.

1002 {
1003 const unsigned char maxSizeWbmp[] = { 0x00, 0x00, // Header
1004 0x83, 0xFF, 0x7F, // W: 65535
1005 0x83, 0xFF, 0x7F }; // H: 65535
1006 std::unique_ptr<SkStream> stream(new SkMemoryStream(maxSizeWbmp, sizeof(maxSizeWbmp), false));
1007 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromStream(std::move(stream)));
1008
1009 REPORTER_ASSERT(r, codec);
1010 if (!codec) return;
1011
1012 REPORTER_ASSERT(r, codec->getInfo().width() == 65535);
1013 REPORTER_ASSERT(r, codec->getInfo().height() == 65535);
1014
1015 // Now test an image which is too big. Any image with a larger header (i.e.
1016 // has bigger width/height) is also too big.
1017 const unsigned char tooBigWbmp[] = { 0x00, 0x00, // Header
1018 0x84, 0x80, 0x00, // W: 65536
1019 0x84, 0x80, 0x00 }; // H: 65536
1020 stream = std::make_unique<SkMemoryStream>(tooBigWbmp, sizeof(tooBigWbmp), false);
1021 codec = SkCodec::MakeFromStream(std::move(stream));
1022
1023 REPORTER_ASSERT(r, !codec);
1024}

◆ DEF_TEST() [36/40]

DEF_TEST ( Codec_wbmp_restrictive  ,
 
)

Definition at line 976 of file CodecTest.cpp.

976 {
977 const char* path = "images/mandrill.wbmp";
978 std::unique_ptr<SkStream> stream(GetResourceAsStream(path));
979 if (!stream) {
980 return;
981 }
982
983 // Modify the stream to contain a second byte with some bits set.
984 auto data = SkCopyStreamToData(stream.get());
985 uint8_t* writeableData = static_cast<uint8_t*>(data->writable_data());
986 writeableData[1] = static_cast<uint8_t>(~0x9F);
987
988 // SkCodec should support this.
989 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(data));
990 REPORTER_ASSERT(r, codec);
991 if (!codec) {
992 return;
993 }
994 test_info(r, codec.get(), codec->getInfo(), SkCodec::kSuccess, nullptr);
995}
sk_sp< SkData > SkCopyStreamToData(SkStream *stream)
Definition: SkStream.cpp:937

◆ DEF_TEST() [37/40]

DEF_TEST ( Codec_webp  ,
 
)

Definition at line 533 of file CodecTest.cpp.

533 {
534 check(r, "images/baby_tux.webp", SkISize::Make(386, 395), false, true, true);
535 check(r, "images/color_wheel.webp", SkISize::Make(128, 128), false, true, true);
536 check(r, "images/yellow_rose.webp", SkISize::Make(400, 301), false, true, true);
537}

◆ DEF_TEST() [38/40]

DEF_TEST ( Codec_webp_peek  ,
 
)

Definition at line 950 of file CodecTest.cpp.

950 {
951 constexpr char path[] = "images/baby_tux.webp";
953 if (!data) {
954 SkDebugf("Missing resource '%s'\n", path);
955 return;
956 }
957
958 // The limit is less than webp needs to peek or read.
959 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromStream(
960 std::make_unique<LimitedPeekingMemStream>(data, 25)));
961 REPORTER_ASSERT(r, codec);
962
963 test_info(r, codec.get(), codec->getInfo(), SkCodec::kSuccess, nullptr);
964
965 // Similarly, a stream which does not peek should still succeed.
966 codec = SkCodec::MakeFromStream(std::make_unique<LimitedPeekingMemStream>(data, 0));
967 REPORTER_ASSERT(r, codec);
968
969 test_info(r, codec.get(), codec->getInfo(), SkCodec::kSuccess, nullptr);
970}

◆ DEF_TEST() [39/40]

DEF_TEST ( Codec_webp_rowsDecoded  ,
 
)

Definition at line 1698 of file CodecTest.cpp.

1698 {
1699 const char* path = "images/baby_tux.webp";
1701 if (!data) {
1702 return;
1703 }
1704
1705 // Truncate this file so that the header is available but no rows can be
1706 // decoded. This should create a codec but fail to decode.
1707 size_t truncatedSize = 5000;
1708 sk_sp<SkData> subset = SkData::MakeSubset(data.get(), 0, truncatedSize);
1709 std::unique_ptr<SkCodec> codec = SkCodec::MakeFromData(std::move(subset));
1710 if (!codec) {
1711 ERRORF(r, "Failed to create a codec for %s truncated to only %zu bytes",
1712 path, truncatedSize);
1713 return;
1714 }
1715
1716 test_info(r, codec.get(), codec->getInfo(), SkCodec::kInvalidInput, nullptr);
1717}

◆ DEF_TEST() [40/40]

DEF_TEST ( Wuffs_seek_and_decode  ,
 
)

Definition at line 1409 of file CodecTest.cpp.

1409 {
1410 const char* file = "images/flightAnim.gif";
1412 seek_and_decode(file, std::move(stream), r);
1413
1414#if defined(SK_ENABLE_ANDROID_UTILS)
1415 // Test using FrontBufferedStream, as Android does
1416 auto bufferedStream = android::skia::FrontBufferedStream::Make(
1418 seek_and_decode(file, std::move(bufferedStream), r);
1419#endif
1420}
static void seek_and_decode(const char *file, std::unique_ptr< SkStream > stream, skiatest::Reporter *r)
Definition: CodecTest.cpp:1383

◆ encode_format()

static void encode_format ( SkDynamicMemoryWStream stream,
const SkPixmap pixmap,
SkEncodedImageFormat  format 
)
static

Definition at line 1639 of file CodecTest.cpp.

1640 {
1641 switch (format) {
1644 break;
1647 break;
1650 break;
1651 default:
1652 SkASSERT(false);
1653 break;
1654 }
1655}
uint32_t uint32_t * format
SK_API bool Encode(SkWStream *dst, const SkPixmap &src, const Options &options)
SK_API bool Encode(SkWStream *dst, const SkPixmap &src, const Options &options)

◆ generate_random_subset()

SkIRect generate_random_subset ( SkRandom rand,
int  w,
int  h 
)

Definition at line 119 of file CodecTest.cpp.

119 {
121 do {
122 rect.fLeft = rand->nextRangeU(0, w);
123 rect.fTop = rand->nextRangeU(0, h);
124 rect.fRight = rand->nextRangeU(0, w);
125 rect.fBottom = rand->nextRangeU(0, h);
126 rect.sort();
127 } while (rect.isEmpty());
128 return rect;
129}
uint32_t nextRangeU(uint32_t min, uint32_t max)
Definition: SkRandom.h:80
sk_sp< SkBlender > blender SkRect rect
Definition: SkRecords.h:350
SkScalar w
SkScalar h

◆ md5()

static SkMD5::Digest md5 ( const SkBitmap bm)
static

Definition at line 77 of file CodecTest.cpp.

77 {
78 SkASSERT(bm.getPixels());
79 SkMD5 md5;
80 size_t rowLen = bm.info().bytesPerPixel() * bm.width();
81 for (int y = 0; y < bm.height(); ++y) {
82 md5.write(bm.getAddr(0, y), rowLen);
83 }
84 return md5.finish();
85}
int width() const
Definition: SkBitmap.h:149
int height() const
Definition: SkBitmap.h:158
Definition: SkMD5.h:19
int bytesPerPixel() const
Definition: SkImageInfo.h:492

◆ seek_and_decode()

static void seek_and_decode ( const char *  file,
std::unique_ptr< SkStream stream,
skiatest::Reporter r 
)
static

Definition at line 1383 of file CodecTest.cpp.

1384 {
1385 if (!stream) {
1386 SkDebugf("Missing resources (%s). Set --resourcePath.\n", file);
1387 return;
1388 }
1389
1390 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromStream(std::move(stream)));
1391 if (!codec) {
1392 ERRORF(r, "Failed to create codec for %s,", file);
1393 return;
1394 }
1395
1396 // Trigger reading through the stream, so that decoding the first frame will
1397 // require a rewind.
1398 (void) codec->getFrameCount();
1399
1400 SkImageInfo info = codec->getInfo().makeColorType(kN32_SkColorType);
1401 SkBitmap bm;
1402 bm.allocPixels(info);
1403 auto result = codec->getPixels(bm.pixmap());
1404 if (result != SkCodec::kSuccess) {
1405 ERRORF(r, "Failed to decode %s with error %s", file, SkCodec::ResultToString(result));
1406 }
1407}

◆ supports_partial_scanlines()

static bool supports_partial_scanlines ( const char  path[])
static

Definition at line 280 of file CodecTest.cpp.

280 {
281 static const char* const exts[] = {
282 "jpg", "jpeg", "png", "webp",
283 "JPG", "JPEG", "PNG", "WEBP"
284 };
285
286 for (uint32_t i = 0; i < std::size(exts); i++) {
287 if (SkStrEndsWith(path, exts[i])) {
288 return true;
289 }
290 }
291 return false;
292}

◆ test_codec()

template<typename Codec >
static void test_codec ( skiatest::Reporter r,
const char *  path,
Codec *  codec,
SkBitmap bm,
const SkImageInfo info,
const SkISize size,
SkCodec::Result  expectedResult,
SkMD5::Digest digest,
const SkMD5::Digest goodDigest 
)
static

Definition at line 187 of file CodecTest.cpp.

189 {
190
191 REPORTER_ASSERT(r, info.dimensions() == size);
192 bm.allocPixels(info);
193
194 SkCodec::Result result = codec->getPixels(info, bm.getPixels(), bm.rowBytes());
195 REPORTER_ASSERT(r, result == expectedResult);
196
197 *digest = md5(bm);
198 if (goodDigest) {
199 REPORTER_ASSERT(r, *digest == *goodDigest);
200 }
201
202 {
203 // Test decoding to 565
204 SkImageInfo info565 = info.makeColorType(kRGB_565_SkColorType);
205 if (info.alphaType() == kOpaque_SkAlphaType) {
206 // Decoding to 565 should succeed.
207 SkBitmap bm565;
208 bm565.allocPixels(info565);
209
210 // This will allow comparison even if the image is incomplete.
212
213 auto actualResult = codec->getPixels(info565, bm565.getPixels(), bm565.rowBytes());
214 if (actualResult == expectedResult) {
215 SkMD5::Digest digest565 = md5(bm565);
216
217 // A request for non-opaque should also succeed.
218 for (auto alpha : { kPremul_SkAlphaType, kUnpremul_SkAlphaType }) {
219 info565 = info565.makeAlphaType(alpha);
220 test_info(r, codec, info565, expectedResult, &digest565);
221 }
222 } else {
223 ERRORF(r, "Decoding %s to 565 failed with result \"%s\"\n\t\t\t\texpected:\"%s\"",
224 path,
225 SkCodec::ResultToString(actualResult),
226 SkCodec::ResultToString(expectedResult));
227 }
228 } else {
229 test_info(r, codec, info565, SkCodec::kInvalidConversion, nullptr);
230 }
231 }
232
233 if (codec->getInfo().colorType() == kGray_8_SkColorType) {
234 SkImageInfo grayInfo = codec->getInfo();
235 SkBitmap grayBm;
236 grayBm.allocPixels(grayInfo);
237
239
240 REPORTER_ASSERT(r, expectedResult == codec->getPixels(grayInfo,
241 grayBm.getPixels(), grayBm.rowBytes()));
242
243 SkMD5::Digest grayDigest = md5(grayBm);
244
245 for (auto alpha : { kPremul_SkAlphaType, kUnpremul_SkAlphaType }) {
246 grayInfo = grayInfo.makeAlphaType(alpha);
247 test_info(r, codec, grayInfo, expectedResult, &grayDigest);
248 }
249 }
250
251 // Verify that re-decoding gives the same result. It is interesting to check this after
252 // a decode to 565, since choosing to decode to 565 may result in some of the decode
253 // options being modified. These options should return to their defaults on another
254 // decode to kN32, so the new digest should match the old digest.
255 test_info(r, codec, info, expectedResult, digest);
256
257 {
258 // Check alpha type conversions
259 if (info.alphaType() == kOpaque_SkAlphaType) {
260 test_info(r, codec, info.makeAlphaType(kUnpremul_SkAlphaType),
261 expectedResult, digest);
262 test_info(r, codec, info.makeAlphaType(kPremul_SkAlphaType),
263 expectedResult, digest);
264 } else {
265 // Decoding to opaque should fail
266 test_info(r, codec, info.makeAlphaType(kOpaque_SkAlphaType),
268 SkAlphaType otherAt = info.alphaType();
269 if (kPremul_SkAlphaType == otherAt) {
270 otherAt = kUnpremul_SkAlphaType;
271 } else {
272 otherAt = kPremul_SkAlphaType;
273 }
274 // The other non-opaque alpha type should always succeed, but not match.
275 test_info(r, codec, info.makeAlphaType(otherAt), expectedResult, nullptr);
276 }
277 }
278}
@ kGray_8_SkColorType
pixel with grayscale level in 8-bit byte
Definition: SkColorType.h:35
constexpr SkColor SK_ColorBLACK
Definition: SkColor.h:103

◆ test_conversion_possible()

static void test_conversion_possible ( skiatest::Reporter r,
const char *  path,
bool  supportsScanlineDecoder,
bool  supportsIncrementalDecoder 
)
static

Definition at line 1189 of file CodecTest.cpp.

1191 {
1192 std::unique_ptr<SkStream> stream(GetResourceAsStream(path));
1193 if (!stream) {
1194 return;
1195 }
1196
1197 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromStream(std::move(stream)));
1198 if (!codec) {
1199 ERRORF(r, "failed to create a codec for %s", path);
1200 return;
1201 }
1202
1203 SkImageInfo infoF16 = codec->getInfo().makeColorType(kRGBA_F16_SkColorType);
1204
1205 SkBitmap bm;
1206 bm.allocPixels(infoF16);
1207 SkCodec::Result result = codec->getPixels(infoF16, bm.getPixels(), bm.rowBytes());
1209
1210 result = codec->startScanlineDecode(infoF16);
1211 if (supportsScanlineDecoder) {
1213 } else {
1216 }
1217
1218 result = codec->startIncrementalDecode(infoF16, bm.getPixels(), bm.rowBytes());
1219 if (supportsIncrementalDecoder) {
1221 } else {
1224 }
1225
1226 infoF16 = infoF16.makeColorSpace(infoF16.colorSpace()->makeLinearGamma());
1227 result = codec->getPixels(infoF16, bm.getPixels(), bm.rowBytes());
1229 result = codec->startScanlineDecode(infoF16);
1230 if (supportsScanlineDecoder) {
1232 } else {
1234 }
1235
1236 result = codec->startIncrementalDecode(infoF16, bm.getPixels(), bm.rowBytes());
1237 if (supportsIncrementalDecoder) {
1239 } else {
1241 }
1242}
sk_sp< SkColorSpace > makeLinearGamma() const
SkColorSpace * colorSpace() const

◆ test_dimensions()

static void test_dimensions ( skiatest::Reporter r,
const char  path[] 
)
static

Definition at line 636 of file CodecTest.cpp.

636 {
637 // Create the codec from the resource file
638 std::unique_ptr<SkStream> stream(GetResourceAsStream(path));
639 if (!stream) {
640 return;
641 }
642 std::unique_ptr<SkAndroidCodec> codec(SkAndroidCodec::MakeFromStream(std::move(stream)));
643 if (!codec) {
644 ERRORF(r, "Unable to create codec '%s'", path);
645 return;
646 }
647
648 // Check that the decode is successful for a variety of scales
649 for (int sampleSize = 1; sampleSize < 32; sampleSize++) {
650 // Scale the output dimensions
651 SkISize scaledDims = codec->getSampledDimensions(sampleSize);
652 SkImageInfo scaledInfo = codec->getInfo()
653 .makeDimensions(scaledDims)
654 .makeColorType(kN32_SkColorType);
655
656 // Set up for the decode
657 size_t rowBytes = scaledDims.width() * sizeof(SkPMColor);
658 size_t totalBytes = scaledInfo.computeByteSize(rowBytes);
659 AutoTMalloc<SkPMColor> pixels(totalBytes);
660
662 options.fSampleSize = sampleSize;
664 codec->getAndroidPixels(scaledInfo, pixels.get(), rowBytes, &options);
665 if (result != SkCodec::kSuccess) {
666 ERRORF(r, "Failed to decode %s with sample size %i; error: %s", path, sampleSize,
668 }
669 }
670}
Definition: SkSize.h:16
constexpr int32_t width() const
Definition: SkSize.h:36
SkImageInfo makeDimensions(SkISize newSize) const
Definition: SkImageInfo.h:454

◆ test_encode_icc()

static void test_encode_icc ( skiatest::Reporter r,
SkEncodedImageFormat  format 
)
static

Definition at line 1657 of file CodecTest.cpp.

1657 {
1658 // Test with sRGB color space.
1659 SkBitmap srgbBitmap;
1661 srgbBitmap.allocPixels(srgbInfo);
1662 *srgbBitmap.getAddr32(0, 0) = 0;
1663 SkPixmap pixmap;
1664 srgbBitmap.peekPixels(&pixmap);
1665 SkDynamicMemoryWStream srgbBuf;
1666 encode_format(&srgbBuf, pixmap, format);
1667 sk_sp<SkData> srgbData = srgbBuf.detachAsData();
1668 std::unique_ptr<SkCodec> srgbCodec(SkCodec::MakeFromData(srgbData));
1669 REPORTER_ASSERT(r, srgbCodec->getInfo().colorSpace() == sk_srgb_singleton());
1670
1671 // Test with P3 color space.
1674 pixmap.setColorSpace(p3);
1675 encode_format(&p3Buf, pixmap, format);
1676 sk_sp<SkData> p3Data = p3Buf.detachAsData();
1677 std::unique_ptr<SkCodec> p3Codec(SkCodec::MakeFromData(p3Data));
1678 REPORTER_ASSERT(r, p3Codec->getInfo().colorSpace()->gammaCloseToSRGB());
1679 skcms_Matrix3x3 mat0, mat1;
1680 bool success = p3->toXYZD50(&mat0);
1681 REPORTER_ASSERT(r, success);
1682 success = p3Codec->getInfo().colorSpace()->toXYZD50(&mat1);
1683 REPORTER_ASSERT(r, success);
1684
1685 for (int i = 0; i < 3; i++) {
1686 for (int j = 0; j < 3; j++) {
1687 REPORTER_ASSERT(r, color_space_almost_equal(mat0.vals[i][j], mat1.vals[i][j]));
1688 }
1689 }
1690}
static void encode_format(SkDynamicMemoryWStream *stream, const SkPixmap &pixmap, SkEncodedImageFormat format)
Definition: CodecTest.cpp:1639
static bool color_space_almost_equal(float a, float b)
SkColorSpace * sk_srgb_singleton()
bool peekPixels(SkPixmap *pixmap) const
Definition: SkBitmap.cpp:635
bool toXYZD50(skcms_Matrix3x3 *toXYZD50) const
sk_sp< SkData > detachAsData()
Definition: SkStream.cpp:707
void setColorSpace(sk_sp< SkColorSpace > colorSpace)
Definition: SkPixmap.cpp:57
static constexpr skcms_Matrix3x3 kDisplayP3
Definition: SkColorSpace.h:87
static constexpr skcms_TransferFunction kSRGB
Definition: SkColorSpace.h:45
static SkImageInfo MakeS32(int width, int height, SkAlphaType at)
float vals[3][3]
Definition: skcms_public.h:27

◆ test_in_stripes()

static void test_in_stripes ( skiatest::Reporter r,
SkCodec codec,
const SkImageInfo info,
const SkMD5::Digest goodDigest 
)
static

Definition at line 145 of file CodecTest.cpp.

146 {
147 SkBitmap bm;
148 bm.allocPixels(info);
150
151 const int height = info.height();
152 // Note that if numStripes does not evenly divide height there will be an extra
153 // stripe.
154 const int numStripes = 4;
155
156 if (numStripes > height) {
157 // Image is too small.
158 return;
159 }
160
161 const int stripeHeight = height / numStripes;
162
163 // Iterate through the image twice. Once to decode odd stripes, and once for even.
164 for (int oddEven = 1; oddEven >= 0; oddEven--) {
165 for (int y = oddEven * stripeHeight; y < height; y += 2 * stripeHeight) {
166 SkIRect subset = SkIRect::MakeLTRB(0, y, info.width(),
167 std::min(y + stripeHeight, height));
169 options.fSubset = &subset;
171 bm.rowBytes(), &options)) {
172 ERRORF(r, "failed to start incremental decode!\ttop: %i\tbottom%i\n",
173 subset.top(), subset.bottom());
174 return;
175 }
176 if (SkCodec::kSuccess != codec->incrementalDecode()) {
177 ERRORF(r, "failed incremental decode starting from line %i\n", y);
178 return;
179 }
180 }
181 }
182
183 compare_to_good_digest(r, goodDigest, bm);
184}
Result startIncrementalDecode(const SkImageInfo &dstInfo, void *dst, size_t rowBytes, const Options *)
Definition: SkCodec.cpp:575
Result incrementalDecode(int *rowsDecoded=nullptr)
Definition: SkCodec.h:498
static float min(float r, float g, float b)
Definition: hsl.cpp:48
constexpr int32_t top() const
Definition: SkRect.h:120
static constexpr SkIRect MakeLTRB(int32_t l, int32_t t, int32_t r, int32_t b)
Definition: SkRect.h:91
constexpr int32_t bottom() const
Definition: SkRect.h:134

◆ test_incremental_decode()

static void test_incremental_decode ( skiatest::Reporter r,
SkCodec codec,
const SkImageInfo info,
const SkMD5::Digest goodDigest 
)
static

Definition at line 131 of file CodecTest.cpp.

132 {
133 SkBitmap bm;
134 bm.allocPixels(info);
135
137 bm.rowBytes()));
138
140
141 compare_to_good_digest(r, goodDigest, bm);
142}

◆ test_info()

template<typename Codec >
static void test_info ( skiatest::Reporter r,
Codec *  codec,
const SkImageInfo info,
SkCodec::Result  expectedResult,
const SkMD5::Digest goodDigest 
)
static

Test decoding an SkCodec to a particular SkImageInfo.

Calling getPixels(info) should return expectedResult, and if goodDigest is non nullptr, the resulting decode should match.

Definition at line 106 of file CodecTest.cpp.

107 {
108 SkBitmap bm;
109 bm.allocPixels(info);
110
111 SkCodec::Result result = codec->getPixels(info, bm.getPixels(), bm.rowBytes());
112 REPORTER_ASSERT(r, result == expectedResult);
113
114 if (goodDigest) {
115 compare_to_good_digest(r, *goodDigest, bm);
116 }
117}

◆ test_invalid()

static void test_invalid ( skiatest::Reporter r,
const char  path[] 
)
static

Definition at line 704 of file CodecTest.cpp.

704 {
706 if (!data) {
707 ERRORF(r, "Failed to get resource %s", path);
708 return;
709 }
710
712}

◆ test_invalid_header()

static void test_invalid_header ( skiatest::Reporter r,
const char *  path 
)
static

Definition at line 1515 of file CodecTest.cpp.

1515 {
1516 auto data = GetResourceAsData(path);
1517 if (!data) {
1518 return;
1519 }
1520 std::unique_ptr<SkStreamAsset> stream(new SkMemoryStream(std::move(data)));
1521 if (!stream) {
1522 return;
1523 }
1524 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromStream(std::move(stream)));
1525 REPORTER_ASSERT(r, !codec);
1526}

◆ test_invalid_images()

static void test_invalid_images ( skiatest::Reporter r,
const char *  path,
SkCodec::Result  expectedResult 
)
static

Definition at line 1480 of file CodecTest.cpp.

1481 {
1483 if (!stream) {
1484 return;
1485 }
1486
1487 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromStream(std::move(stream)));
1488 REPORTER_ASSERT(r, codec);
1489
1490 test_info(r, codec.get(), codec->getInfo().makeColorType(kN32_SkColorType), expectedResult,
1491 nullptr);
1492}

◆ test_invalid_stream()

static void test_invalid_stream ( skiatest::Reporter r,
const void *  stream,
size_t  len 
)
static

Definition at line 598 of file CodecTest.cpp.

598 {
599 // Neither of these calls should return a codec. Bots should catch us if we leaked anything.
601 std::make_unique<SkMemoryStream>(stream, len, false)));
603 std::make_unique<SkMemoryStream>(stream, len, false)));
604}