Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
Functions | Variables
CodecPartialTest.cpp File Reference
#include "include/codec/SkCodec.h"
#include "include/core/SkBitmap.h"
#include "include/core/SkData.h"
#include "include/core/SkImageInfo.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkStream.h"
#include "include/core/SkString.h"
#include "include/core/SkTypes.h"
#include "include/private/base/SkDebug.h"
#include "tests/CodecPriv.h"
#include "tests/FakeStreams.h"
#include "tests/Test.h"
#include "tools/Resources.h"
#include <algorithm>
#include <cstring>
#include <initializer_list>
#include <memory>
#include <utility>
#include <vector>

Go to the source code of this file.

Functions

static SkImageInfo standardize_info (SkCodec *codec)
 
static bool create_truth (sk_sp< SkData > data, SkBitmap *dst)
 
static bool compare_bitmaps (skiatest::Reporter *r, const SkBitmap &bm1, const SkBitmap &bm2)
 
static void test_partial (skiatest::Reporter *r, const char *name, const sk_sp< SkData > &file, size_t minBytes, size_t increment)
 
static void test_partial (skiatest::Reporter *r, const char *name, size_t minBytes=0)
 
 DEF_TEST (Codec_partial, r)
 
 DEF_TEST (Codec_partialWuffs, r)
 
 DEF_TEST (Codec_requiredFrame, r)
 
 DEF_TEST (Codec_partialAnim, r)
 
static void test_interleaved (skiatest::Reporter *r, const char *name)
 
 DEF_TEST (Codec_rewind, r)
 
 DEF_TEST (Codec_GifPreMap, r)
 
 DEF_TEST (Codec_emptyIDAT, r)
 
 DEF_TEST (Codec_incomplete, r)
 

Variables

static unsigned char gNoGlobalColorMap []
 

Function Documentation

◆ compare_bitmaps()

static bool compare_bitmaps ( skiatest::Reporter r,
const SkBitmap bm1,
const SkBitmap bm2 
)
static

Definition at line 47 of file CodecPartialTest.cpp.

47 {
48 const SkImageInfo& info = bm1.info();
49 if (info != bm2.info()) {
50 ERRORF(r, "Bitmaps have different image infos!");
51 return false;
52 }
53 const size_t rowBytes = info.minRowBytes();
54 for (int i = 0; i < info.height(); i++) {
55 if (0 != memcmp(bm1.getAddr(0, i), bm2.getAddr(0, i), rowBytes)) {
56 ERRORF(r, "Bitmaps have different pixels, starting on line %i!", i);
57 return false;
58 }
59 }
60
61 return true;
62}
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition DM.cpp:213
#define ERRORF(r,...)
Definition Test.h:293
void * getAddr(int x, int y) const
Definition SkBitmap.cpp:406
const SkImageInfo & info() const
Definition SkBitmap.h:139

◆ create_truth()

static bool create_truth ( sk_sp< SkData data,
SkBitmap dst 
)
static

Definition at line 36 of file CodecPartialTest.cpp.

36 {
37 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(std::move(data)));
38 if (!codec) {
39 return false;
40 }
41
42 const SkImageInfo info = standardize_info(codec.get());
43 dst->allocPixels(info);
44 return SkCodec::kSuccess == codec->getPixels(info, dst->getPixels(), dst->rowBytes());
45}
static SkImageInfo standardize_info(SkCodec *codec)
static std::unique_ptr< SkCodec > MakeFromData(sk_sp< SkData >, SkSpan< const SkCodecs::Decoder > decoders, SkPngChunkReader *=nullptr)
Definition SkCodec.cpp:241
@ kSuccess
Definition SkCodec.h:80
dst
Definition cp.py:12

◆ DEF_TEST() [1/8]

DEF_TEST ( Codec_emptyIDAT  ,
 
)

Definition at line 452 of file CodecPartialTest.cpp.

452 {
453 const char* name = "images/baby_tux.png";
455 if (!file) {
456 return;
457 }
458
459 // Truncate to the beginning of the IDAT, immediately after the IDAT tag.
460 file = SkData::MakeSubset(file.get(), 0, 80);
461
462 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(std::move(file)));
463 if (!codec) {
464 ERRORF(r, "Failed to create a codec for %s", name);
465 return;
466 }
467
468 SkBitmap bm;
469 const auto info = standardize_info(codec.get());
470 bm.allocPixels(info);
471
472 const auto result = codec->getPixels(info, bm.getPixels(), bm.rowBytes());
474}
sk_sp< SkData > GetResourceAsData(const char *resource)
Definition Resources.cpp:42
#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
@ kIncompleteInput
Definition SkCodec.h:84
static sk_sp< SkData > MakeSubset(const SkData *src, size_t offset, size_t length)
Definition SkData.cpp:173
GAsyncResult * result
const char * name
Definition fuchsia.cc:50

◆ DEF_TEST() [2/8]

DEF_TEST ( Codec_GifPreMap  ,
 
)

Definition at line 399 of file CodecPartialTest.cpp.

399 {
401 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(data));
402 if (!codec) {
403 ERRORF(r, "failed to create codec");
404 return;
405 }
406
407 SkBitmap truth;
408 auto info = standardize_info(codec.get());
409 truth.allocPixels(info);
410
411 auto result = codec->getPixels(info, truth.getPixels(), truth.rowBytes());
413
414 // Truncate to 23 bytes, just before the color map. This should fail to decode.
415 //
416 // See also Codec_GifTruncated2 in GifTest.cpp for this magic 23.
418 REPORTER_ASSERT(r, codec);
419 if (codec) {
420 SkBitmap bm;
421 bm.allocPixels(info);
422 result = codec->getPixels(info, bm.getPixels(), bm.rowBytes());
423
425 }
426
427 // Again, truncate to 23 bytes, this time for an incremental decode. We
428 // cannot start an incremental decode until we have more data. If we did,
429 // we would be using the wrong color table.
430 HaltingStream* stream = new HaltingStream(data, 23);
431 codec = SkCodec::MakeFromStream(std::unique_ptr<SkStream>(stream));
432 REPORTER_ASSERT(r, codec);
433 if (codec) {
434 SkBitmap bm;
435 bm.allocPixels(info);
436 result = codec->startIncrementalDecode(info, bm.getPixels(), bm.rowBytes());
437
439
440 // Note that this is incrementalDecode, not startIncrementalDecode.
441 result = codec->incrementalDecode();
443
444 stream->addNewData(data->size());
445
446 result = codec->incrementalDecode();
448 compare_bitmaps(r, truth, bm);
449 }
450}
static bool compare_bitmaps(skiatest::Reporter *r, const SkBitmap &bm1, const SkBitmap &bm2)
static unsigned char gNoGlobalColorMap[]
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 sk_sp< SkData > MakeWithoutCopy(const void *data, size_t length)
Definition SkData.h:116
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
Definition switches.h:41

◆ DEF_TEST() [3/8]

DEF_TEST ( Codec_incomplete  ,
 
)

Definition at line 476 of file CodecPartialTest.cpp.

476 {
477 for (const char* name : { "images/baby_tux.png",
478 "images/baby_tux.webp",
479 "images/CMYK.jpg",
480 "images/color_wheel.gif",
481 "images/google_chrome.ico",
482 "images/rle.bmp",
483 "images/mandrill.wbmp",
484 }) {
486 if (!file) {
487 continue;
488 }
489
490 for (size_t len = 14; len <= file->size(); len += 5) {
492 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromStream(
493 std::make_unique<SkMemoryStream>(file->data(), len), &result));
494 if (codec) {
495 if (result != SkCodec::kSuccess) {
496 ERRORF(r, "Created an SkCodec for %s with %zu bytes, but "
497 "reported an error %i", name, len, (int)result);
498 }
499 break;
500 }
501
503 ERRORF(r, "Reported error %i for %s with %zu bytes",
504 (int)result, name, len);
505 break;
506 }
507 }
508 }
509}

◆ DEF_TEST() [4/8]

DEF_TEST ( Codec_partial  ,
 
)

Definition at line 139 of file CodecPartialTest.cpp.

139 {
140#if 0
141 // FIXME (scroggo): SkPngCodec needs to use SkStreamBuffer in order to
142 // support incremental decoding.
143 test_partial(r, "images/plane.png");
144 test_partial(r, "images/plane_interlaced.png");
145 test_partial(r, "images/yellow_rose.png");
146 test_partial(r, "images/index8.png");
147 test_partial(r, "images/color_wheel.png");
148 test_partial(r, "images/mandrill_256.png");
149 test_partial(r, "images/mandrill_32.png");
150 test_partial(r, "images/arrow.png");
151 test_partial(r, "images/randPixels.png");
152 test_partial(r, "images/baby_tux.png");
153#endif
154 test_partial(r, "images/box.gif");
155 test_partial(r, "images/randPixels.gif", 215);
156 test_partial(r, "images/color_wheel.gif");
157}
static void test_partial(skiatest::Reporter *r, const char *name, const sk_sp< SkData > &file, size_t minBytes, size_t increment)

◆ DEF_TEST() [5/8]

DEF_TEST ( Codec_partialAnim  ,
 
)

Definition at line 227 of file CodecPartialTest.cpp.

227 {
228 auto path = "images/test640x479.gif";
230 if (!file) {
231 return;
232 }
233
234 // This stream will be owned by fullCodec, but we hang on to the pointer
235 // to determine frame offsets.
236 std::unique_ptr<SkCodec> fullCodec(SkCodec::MakeFromStream(std::make_unique<SkMemoryStream>(file)));
237 const auto info = standardize_info(fullCodec.get());
238
239 // frameByteCounts stores the number of bytes to decode a particular frame.
240 // - [0] is the number of bytes for the header
241 // - frames[i] requires frameByteCounts[i+1] bytes to decode
242 const std::vector<size_t> frameByteCounts = { 455, 69350, 1344, 1346, 1327 };
243 std::vector<SkBitmap> frames;
244 for (size_t i = 0; true; i++) {
247
248 SkCodec::Options opts;
249 opts.fFrameIndex = i;
250 const SkCodec::Result result = fullCodec->getPixels(info, frame.getPixels(),
251 frame.rowBytes(), &opts);
252
254 // We need to distinguish between a partial frame and no more frames.
255 // getFrameInfo lets us do this, since it tells the number of frames
256 // not considering whether they are complete.
257 // FIXME: Should we use a different Result?
258 if (fullCodec->getFrameInfo().size() > i) {
259 // This is a partial frame.
260 frames.push_back(frame);
261 }
262 break;
263 }
264
265 if (result != SkCodec::kSuccess) {
266 ERRORF(r, "Failed to decode frame %zu from %s", i, path);
267 return;
268 }
269
270 frames.push_back(frame);
271 }
272
273 // Now decode frames partially, then completely, and compare to the original.
274 HaltingStream* haltingStream = new HaltingStream(file, frameByteCounts[0]);
275 std::unique_ptr<SkCodec> partialCodec(SkCodec::MakeFromStream(
276 std::unique_ptr<SkStream>(haltingStream)));
277 if (!partialCodec) {
278 ERRORF(r, "Failed to create a partial codec from %s with %zu bytes out of %zu",
279 path, frameByteCounts[0], file->size());
280 return;
281 }
282
283 SkASSERT(frameByteCounts.size() > frames.size());
284 for (size_t i = 0; i < frames.size(); i++) {
285 const size_t fullFrameBytes = frameByteCounts[i + 1];
286 const size_t firstHalf = fullFrameBytes / 2;
287 const size_t secondHalf = fullFrameBytes - firstHalf;
288
289 haltingStream->addNewData(firstHalf);
290 auto frameInfo = partialCodec->getFrameInfo();
291 REPORTER_ASSERT(r, frameInfo.size() == i + 1);
292 REPORTER_ASSERT(r, !frameInfo[i].fFullyReceived);
293
296
297 SkCodec::Options opts;
298 opts.fFrameIndex = i;
299 SkCodec::Result result = partialCodec->startIncrementalDecode(info,
300 frame.getPixels(), frame.rowBytes(), &opts);
301 if (result != SkCodec::kSuccess) {
302 ERRORF(r, "Failed to start incremental decode for %s on frame %zu",
303 path, i);
304 return;
305 }
306
307 result = partialCodec->incrementalDecode();
309
310 haltingStream->addNewData(secondHalf);
311 result = partialCodec->incrementalDecode();
313
314 frameInfo = partialCodec->getFrameInfo();
315 REPORTER_ASSERT(r, frameInfo.size() == i + 1);
316 REPORTER_ASSERT(r, frameInfo[i].fFullyReceived);
317 if (!compare_bitmaps(r, frames[i], frame)) {
318 ERRORF(r, "\tfailure was on frame %zu", i);
319 SkString name = SkStringPrintf("expected_%zu", i);
320 write_bm(name.c_str(), frames[i]);
321
322 name = SkStringPrintf("actual_%zu", i);
323 write_bm(name.c_str(), frame);
324 }
325 }
326}
void write_bm(const char *name, const SkBitmap &bm)
Definition CodecPriv.h:33
#define SkASSERT(cond)
Definition SkAssert.h:116
SK_API SkString static SkString SkStringPrintf()
Definition SkString.h:287
void addNewData(size_t extra)
Definition FakeStreams.h:69
@ kInvalidInput
Definition SkCodec.h:109
double frame
Definition examples.cpp:31
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

◆ DEF_TEST() [6/8]

DEF_TEST ( Codec_partialWuffs  ,
 
)

Definition at line 159 of file CodecPartialTest.cpp.

159 {
160 const char* path = "images/alphabetAnim.gif";
161 auto file = GetResourceAsData(path);
162 if (!file) {
163 ERRORF(r, "missing %s", path);
164 } else {
165 // This is the end of the first frame. SkCodec will treat this as a
166 // single frame gif.
167 file = SkData::MakeSubset(file.get(), 0, 153);
168 // Start with 100 to get a partial decode, then add the rest of the
169 // first frame to decode a full image.
170 test_partial(r, path, file, 100, 53);
171 }
172}

◆ DEF_TEST() [7/8]

DEF_TEST ( Codec_requiredFrame  ,
 
)

Definition at line 176 of file CodecPartialTest.cpp.

176 {
177 auto path = "images/colorTables.gif";
179 if (!file) {
180 return;
181 }
182
183 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(file));
184 if (!codec) {
185 ERRORF(r, "Failed to create codec from %s", path);
186 return;
187 }
188
189 auto frameInfo = codec->getFrameInfo();
190 if (frameInfo.size() <= 1) {
191 ERRORF(r, "Test is uninteresting with 0 or 1 frames");
192 return;
193 }
194
195 HaltingStream* stream(nullptr);
196 std::unique_ptr<SkCodec> partialCodec(nullptr);
197 for (size_t i = 0; !partialCodec; i++) {
198 if (file->size() == i) {
199 ERRORF(r, "Should have created a partial codec for %s", path);
200 return;
201 }
202 stream = new HaltingStream(file, i);
203 partialCodec = SkCodec::MakeFromStream(std::unique_ptr<SkStream>(stream));
204 }
205
206 std::vector<SkCodec::FrameInfo> partialInfo;
207 size_t frameToCompare = 0;
208 while (true) {
209 partialInfo = partialCodec->getFrameInfo();
210 for (; frameToCompare < partialInfo.size(); frameToCompare++) {
211 REPORTER_ASSERT(r, partialInfo[frameToCompare].fRequiredFrame
212 == frameInfo[frameToCompare].fRequiredFrame);
213 }
214
215 if (frameToCompare == frameInfo.size()) {
216 break;
217 }
218
219 if (stream->getLength() == file->size()) {
220 ERRORF(r, "Should have found all frames for %s", path);
221 return;
222 }
223 stream->addNewData(1);
224 }
225}

◆ DEF_TEST() [8/8]

DEF_TEST ( Codec_rewind  ,
 
)

Definition at line 368 of file CodecPartialTest.cpp.

368 {
369 test_interleaved(r, "images/plane.png");
370 test_interleaved(r, "images/plane_interlaced.png");
371 test_interleaved(r, "images/box.gif");
372}
static void test_interleaved(skiatest::Reporter *r, const char *name)

◆ standardize_info()

static SkImageInfo standardize_info ( SkCodec codec)
static

Definition at line 29 of file CodecPartialTest.cpp.

29 {
30 SkImageInfo defaultInfo = codec->getInfo();
31 // Note: This drops the SkColorSpace, allowing the equality check between two
32 // different codecs created from the same file to have the same SkImageInfo.
33 return SkImageInfo::MakeN32Premul(defaultInfo.width(), defaultInfo.height());
34}
SkImageInfo getInfo() const
Definition SkCodec.h:228
static SkImageInfo MakeN32Premul(int width, int height)
int width() const
int height() const

◆ test_interleaved()

static void test_interleaved ( skiatest::Reporter r,
const char *  name 
)
static

Definition at line 331 of file CodecPartialTest.cpp.

331 {
333 if (!file) {
334 return;
335 }
336 const size_t halfSize = file->size() / 2;
337 std::unique_ptr<SkCodec> partialCodec(SkCodec::MakeFromStream(
338 std::make_unique<HaltingStream>(std::move(file), halfSize)));
339 if (!partialCodec) {
340 ERRORF(r, "Failed to create codec for %s", name);
341 return;
342 }
343
344 const SkImageInfo info = standardize_info(partialCodec.get());
345 SkBitmap incremental;
346 incremental.allocPixels(info);
347
348 const SkCodec::Result startResult = partialCodec->startIncrementalDecode(info,
349 incremental.getPixels(), incremental.rowBytes());
350 if (startResult != SkCodec::kSuccess) {
351 ERRORF(r, "Failed to start incremental decode\n");
352 return;
353 }
354
355 SkCodec::Result result = partialCodec->incrementalDecode();
357
359 full.allocPixels(info);
360 result = partialCodec->getPixels(info, full.getPixels(), full.rowBytes());
362
363 // Now incremental decode will fail
364 result = partialCodec->incrementalDecode();
366}
@ kInvalidParameters
Definition SkCodec.h:105
Definition full.py:1

◆ test_partial() [1/2]

static void test_partial ( skiatest::Reporter r,
const char *  name,
const sk_sp< SkData > &  file,
size_t  minBytes,
size_t  increment 
)
static

Definition at line 64 of file CodecPartialTest.cpp.

65 {
66 SkBitmap truth;
67 if (!create_truth(file, &truth)) {
68 ERRORF(r, "Failed to decode %s\n", name);
69 return;
70 }
71
72 // Now decode part of the file
73 HaltingStream* stream = new HaltingStream(file, minBytes);
74
75 // Note that we cheat and hold on to a pointer to stream, though it is owned by
76 // partialCodec.
77 auto partialCodec = SkCodec::MakeFromStream(std::unique_ptr<SkStream>(stream));
78 if (!partialCodec) {
79 ERRORF(r, "Failed to create codec for %s with %zu bytes", name, minBytes);
80 return;
81 }
82
83 const SkImageInfo info = standardize_info(partialCodec.get());
84 SkASSERT(info == truth.info());
85 SkBitmap incremental;
86 incremental.allocPixels(info);
87
88 while (true) {
89 const SkCodec::Result startResult = partialCodec->startIncrementalDecode(info,
90 incremental.getPixels(), incremental.rowBytes());
91 if (startResult == SkCodec::kSuccess) {
92 break;
93 }
94
95 if (stream->isAllDataReceived()) {
96 ERRORF(r, "Failed to start incremental decode\n");
97 return;
98 }
99
100 stream->addNewData(increment);
101 }
102
103 while (true) {
104 // This imitates how Chromium calls getFrameCount before resuming a decode.
105 partialCodec->getFrameCount();
106
107 const SkCodec::Result result = partialCodec->incrementalDecode();
108
109 if (result == SkCodec::kSuccess) {
110 break;
111 }
112
114
115 if (stream->isAllDataReceived()) {
116 ERRORF(r, "Failed to completely decode %s", name);
117 return;
118 }
119
120 stream->addNewData(increment);
121 }
122
123 // compare to original
124 compare_bitmaps(r, truth, incremental);
125}
static bool create_truth(sk_sp< SkData > data, SkBitmap *dst)

◆ test_partial() [2/2]

static void test_partial ( skiatest::Reporter r,
const char *  name,
size_t  minBytes = 0 
)
static

Definition at line 127 of file CodecPartialTest.cpp.

127 {
129 if (!file) {
130 SkDebugf("missing resource %s\n", name);
131 return;
132 }
133
134 // This size is arbitrary, but deliberately different from the buffer size used by SkPngCodec.
135 constexpr size_t kIncrement = 1000;
136 test_partial(r, name, file, std::max(file->size() / 2, minBytes), kIncrement);
137}
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1

Variable Documentation

◆ gNoGlobalColorMap

unsigned char gNoGlobalColorMap[]
static
Initial value:
= {
0x47, 0x49, 0x46, 0x38, 0x39, 0x61,
0x0A, 0x00, 0x0A, 0x00, 0x11, 0x00, 0x00,
0x2C, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x81,
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
0x02, 0x16, 0x8C, 0x2D, 0x99, 0x87, 0x2A, 0x1C, 0xDC, 0x33, 0xA0, 0x02, 0x75,
0xEC, 0x95, 0xFA, 0xA8, 0xDE, 0x60, 0x8C, 0x04, 0x91, 0x4C, 0x01, 0x00,
0x3B,
}

Definition at line 377 of file CodecPartialTest.cpp.

377 {
378 // Header
379 0x47, 0x49, 0x46, 0x38, 0x39, 0x61,
380
381 // Logical screen descriptor
382 0x0A, 0x00, 0x0A, 0x00, 0x11, 0x00, 0x00,
383
384 // Image descriptor
385 0x2C, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x81,
386
387 // Local color table
388 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
389
390 // Image data
391 0x02, 0x16, 0x8C, 0x2D, 0x99, 0x87, 0x2A, 0x1C, 0xDC, 0x33, 0xA0, 0x02, 0x75,
392 0xEC, 0x95, 0xFA, 0xA8, 0xDE, 0x60, 0x8C, 0x04, 0x91, 0x4C, 0x01, 0x00,
393
394 // Trailer
395 0x3B,
396};