1/*
2 * Copyright 2013 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "Benchmark.h"
9#include "Resources.h"
10#include "SkBitmap.h"
11#include "SkData.h"
12#include "SkForceLinking.h"
13#include "SkImageDecoder.h"
14#include "SkOSFile.h"
15#include "SkStream.h"
16#include "SkString.h"
17
18__SK_FORCE_IMAGE_DECODER_LINKING;
19
20class SkCanvas;
21
22class SkipZeroesBench : public Benchmark {
23public:
24    SkipZeroesBench(const char* filename, bool skipZeroes)
25    : fName("SkipZeroes_")
26    , fDecoder(NULL)
27    , fFilename(filename)
28    , fStream()
29    , fSkipZeroes(skipZeroes)
30    , fValid(false) {
31        fName.append(filename);
32        if (skipZeroes) {
33            fName.append("_skip_zeroes");
34        } else {
35            fName.append("_write_zeroes");
36        }
37    }
38
39    virtual bool isSuitableFor(Backend backend) SK_OVERRIDE {
40        return backend == kNonRendering_Backend;
41    }
42
43protected:
44    virtual const char* onGetName() SK_OVERRIDE {
45        return fName.c_str();
46    }
47
48    virtual void onPreDraw() SK_OVERRIDE {
49        SkString resourcePath = GetResourcePath();
50        if (resourcePath.isEmpty()) {
51            fValid = false;
52            return;
53        }
54
55        SkString fullPath = SkOSPath::SkPathJoin(resourcePath.c_str(),
56                                                 fFilename.c_str());
57        SkFILEStream fileStream(fullPath.c_str());
58        fValid = fileStream.isValid() && fileStream.getLength() > 0;
59        if (fValid) {
60            const size_t size = fileStream.getLength();
61            void* data = sk_malloc_throw(size);
62            if (fileStream.read(data, size) < size) {
63                fValid = false;
64            } else {
65                SkAutoTUnref<SkData> skdata(SkData::NewFromMalloc(data, size));
66                fStream.setData(skdata.get());
67                fDecoder.reset(SkImageDecoder::Factory(&fStream));
68                if (fDecoder.get()) {
69                    fDecoder->setSkipWritingZeroes(fSkipZeroes);
70                } else {
71                    fValid = false;
72                }
73            }
74        }
75    }
76
77    virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE {
78        if (!fValid) {
79#ifdef SK_DEBUG
80            SkDebugf("stream was invalid: %s\n", fFilename.c_str());
81#endif
82            return;
83        }
84        // Decode a bunch of times
85        SkBitmap bm;
86        for (int i = 0; i < loops; ++i) {
87            SkDEBUGCODE(bool success =) fDecoder->decode(&fStream, &bm,
88                                                         SkImageDecoder::kDecodePixels_Mode);
89#ifdef SK_DEBUG
90            if (!success) {
91                SkDebugf("failed to decode %s\n", fFilename.c_str());
92                return;
93            }
94#endif
95            SkDEBUGCODE(success =) fStream.rewind();
96#ifdef SK_DEBUG
97            if (!success) {
98                SkDebugf("failed to rewind %s\n", fFilename.c_str());
99                return;
100            }
101#endif
102        }
103    }
104
105private:
106    SkString                        fName;
107    SkAutoTDelete<SkImageDecoder>   fDecoder;
108    const SkString                  fFilename;
109    SkMemoryStream                  fStream;
110    bool                            fSkipZeroes;
111    bool                            fValid;
112
113    typedef Benchmark INHERITED;
114};
115
116// Enable the true version once the feature is checked in.
117DEF_BENCH( return SkNEW_ARGS(SkipZeroesBench, ("arrow.png", true)));
118DEF_BENCH( return SkNEW_ARGS(SkipZeroesBench, ("arrow.png", false)));
119