blob: 5f4fe71cb0f6ff836c0e82ab9fa66fb0b1ff5936 [file] [log] [blame]
scroggo19b91532016-10-24 09:03:26 -07001/*
2 * Copyright 2016 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 "gm.h"
Matt Sarett68b8e3d2017-04-28 11:15:22 -04009#include "sk_tool_utils.h"
scroggo19b91532016-10-24 09:03:26 -070010#include "SkAnimTimer.h"
11#include "SkCanvas.h"
12#include "SkCodec.h"
13#include "SkColor.h"
14#include "SkCommandLineFlags.h"
15#include "SkPaint.h"
16#include "SkString.h"
17#include "Resources.h"
18
19#include <vector>
20
21DEFINE_string(animatedGif, "test640x479.gif", "Animated gif in resources folder");
22
23namespace {
24 void error(SkCanvas* canvas, const SkString& errorText) {
25 constexpr SkScalar kOffset = 5.0f;
26 canvas->drawColor(SK_ColorRED);
27 SkPaint paint;
28 SkRect bounds;
29 paint.measureText(errorText.c_str(), errorText.size(), &bounds);
Cary Clark2a475ea2017-04-28 15:35:12 -040030 canvas->drawString(errorText, kOffset, bounds.height() + kOffset,
scroggo19b91532016-10-24 09:03:26 -070031 paint);
32 }
33}
34
35class AnimatedGifGM : public skiagm::GM {
36private:
37 std::unique_ptr<SkCodec> fCodec;
Leon Scroggins III249b8e32017-04-17 12:46:33 -040038 int fFrame;
scroggo19b91532016-10-24 09:03:26 -070039 double fNextUpdate;
Leon Scroggins III249b8e32017-04-17 12:46:33 -040040 int fTotalFrames;
scroggo19b91532016-10-24 09:03:26 -070041 std::vector<SkCodec::FrameInfo> fFrameInfos;
42 std::vector<SkBitmap> fFrames;
43
44 void drawFrame(SkCanvas* canvas, int frameIndex) {
45 // FIXME: Create from an Image/ImageGenerator?
46 if (frameIndex >= (int) fFrames.size()) {
47 fFrames.resize(frameIndex + 1);
48 }
49 SkBitmap& bm = fFrames[frameIndex];
50 if (!bm.getPixels()) {
51 const SkImageInfo info = fCodec->getInfo().makeColorType(kN32_SkColorType);
52 bm.allocPixels(info);
53
54 SkCodec::Options opts;
55 opts.fFrameIndex = frameIndex;
56 opts.fHasPriorFrame = false;
Leon Scroggins III249b8e32017-04-17 12:46:33 -040057 const int requiredFrame = fFrameInfos[frameIndex].fRequiredFrame;
scroggo19b91532016-10-24 09:03:26 -070058 if (requiredFrame != SkCodec::kNone) {
Leon Scroggins III249b8e32017-04-17 12:46:33 -040059 SkASSERT(requiredFrame >= 0
60 && static_cast<size_t>(requiredFrame) < fFrames.size());
scroggo19b91532016-10-24 09:03:26 -070061 SkBitmap& requiredBitmap = fFrames[requiredFrame];
62 // For simplicity, do not try to cache old frames
Matt Sarett68b8e3d2017-04-28 11:15:22 -040063 if (requiredBitmap.getPixels() &&
64 sk_tool_utils::copy_to(&bm, requiredBitmap.colorType(), requiredBitmap)) {
scroggo19b91532016-10-24 09:03:26 -070065 opts.fHasPriorFrame = true;
66 }
67 }
68
69 if (SkCodec::kSuccess != fCodec->getPixels(info, bm.getPixels(),
70 bm.rowBytes(), &opts,
71 nullptr, nullptr)) {
72 SkDebugf("Could not getPixels for frame %i: %s", frameIndex, FLAGS_animatedGif[0]);
73 return;
74 }
75 }
76
77 canvas->drawBitmap(bm, 0, 0);
78 }
79
80public:
81 AnimatedGifGM()
82 : fFrame(0)
83 , fNextUpdate (-1)
84 , fTotalFrames (-1) {}
85
86private:
87 SkString onShortName() override {
88 return SkString("animatedGif");
89 }
90
91 SkISize onISize() override {
92 if (this->initCodec()) {
93 SkISize dim = fCodec->getInfo().dimensions();
94 // Wide enough to display all the frames.
95 dim.fWidth *= fTotalFrames;
96 // Tall enough to show the row of frames plus an animating version.
97 dim.fHeight *= 2;
98 return dim;
99 }
100 return SkISize::Make(640, 480);
101 }
102
103 void onDrawBackground(SkCanvas* canvas) override {
scroggocf280a42016-10-24 09:59:53 -0700104 canvas->clear(SK_ColorWHITE);
scroggo19b91532016-10-24 09:03:26 -0700105 if (this->initCodec()) {
106 SkAutoCanvasRestore acr(canvas, true);
Leon Scroggins III249b8e32017-04-17 12:46:33 -0400107 for (int frameIndex = 0; frameIndex < fTotalFrames; frameIndex++) {
scroggo19b91532016-10-24 09:03:26 -0700108 this->drawFrame(canvas, frameIndex);
Jim Van Verth3cfdf6c2016-10-26 09:45:23 -0400109 canvas->translate(SkIntToScalar(fCodec->getInfo().width()), 0);
scroggo19b91532016-10-24 09:03:26 -0700110 }
111 }
112 }
113
114 bool initCodec() {
115 if (fCodec) {
116 return true;
117 }
118 if (FLAGS_animatedGif.isEmpty()) {
119 SkDebugf("Nothing specified for --animatedGif!");
120 return false;
121 }
122
123 std::unique_ptr<SkStream> stream(GetResourceAsStream(FLAGS_animatedGif[0]));
124 if (!stream) {
125 return false;
126 }
127
128 fCodec.reset(SkCodec::NewFromStream(stream.release()));
129 if (!fCodec) {
130 SkDebugf("Could create codec from %s", FLAGS_animatedGif[0]);
131 return false;
132 }
133
134 fFrame = 0;
135 fFrameInfos = fCodec->getFrameInfo();
136 fTotalFrames = fFrameInfos.size();
137 return true;
138 }
139
140 void onDraw(SkCanvas* canvas) override {
141 if (!fCodec) {
142 SkString errorText = SkStringPrintf("Nothing to draw; %s", FLAGS_animatedGif[0]);
143 error(canvas, errorText);
144 return;
145 }
146
147 SkAutoCanvasRestore acr(canvas, true);
Jim Van Verth3cfdf6c2016-10-26 09:45:23 -0400148 canvas->translate(0, SkIntToScalar(fCodec->getInfo().height()));
scroggo19b91532016-10-24 09:03:26 -0700149 this->drawFrame(canvas, fFrame);
150 }
151
152 bool onAnimate(const SkAnimTimer& timer) override {
153 if (!fCodec || fTotalFrames == 1) {
154 return false;
155 }
156
157 double secs = timer.msec() * .1;
158 if (fNextUpdate < double(0)) {
159 // This is a sentinel that we have not done any updates yet.
160 // I'm assuming this gets called *after* onOnceBeforeDraw, so our first frame should
161 // already have been retrieved.
162 SkASSERT(fFrame == 0);
163 fNextUpdate = secs + fFrameInfos[fFrame].fDuration;
164
165 return true;
166 }
167
168 if (secs < fNextUpdate) {
169 return true;
170 }
171
172 while (secs >= fNextUpdate) {
173 // Retrieve the next frame.
174 fFrame++;
175 if (fFrame == fTotalFrames) {
176 fFrame = 0;
177 }
178
179 // Note that we loop here. This is not safe if we need to draw the intermediate frame
180 // in order to draw correctly.
181 fNextUpdate += fFrameInfos[fFrame].fDuration;
182 }
183
184 return true;
185 }
186};
187
188DEF_GM(return new AnimatedGifGM);
189