OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2016 Google Inc. | 2 * Copyright 2016 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "gm.h" | 8 #include "gm.h" |
9 #include "SkAnimTimer.h" | 9 #include "SkAnimTimer.h" |
10 #include "SkCanvas.h" | 10 #include "SkCanvas.h" |
(...skipping 15 matching lines...) Expand all Loading... |
26 SkPaint paint; | 26 SkPaint paint; |
27 SkRect bounds; | 27 SkRect bounds; |
28 paint.measureText(errorText.c_str(), errorText.size(), &bounds); | 28 paint.measureText(errorText.c_str(), errorText.size(), &bounds); |
29 canvas->drawText(errorText.c_str(), errorText.size(), kOffset, bounds.he
ight() + kOffset, | 29 canvas->drawText(errorText.c_str(), errorText.size(), kOffset, bounds.he
ight() + kOffset, |
30 paint); | 30 paint); |
31 } | 31 } |
32 } | 32 } |
33 | 33 |
34 class AnimatedGifGM : public skiagm::GM { | 34 class AnimatedGifGM : public skiagm::GM { |
35 private: | 35 private: |
36 std::unique_ptr<SkCodec> fCodec; | 36 std::unique_ptr<SkCodec> fCodec; |
37 size_t fFrame; | 37 size_t fFrame; |
38 double fNextUpdate; | 38 double fNextUpdate; |
39 size_t fTotalFrames; | 39 size_t fTotalFrames; |
40 std::vector<SkBitmap> fFrames; | 40 std::vector<SkCodec::FrameInfo> fFrameInfos; |
| 41 std::vector<SkBitmap> fFrames; |
41 | 42 |
42 void drawBounds(SkCanvas* canvas) { | 43 void drawBounds(SkCanvas* canvas) { |
43 if (!fCodec) { | 44 if (!fCodec) { |
44 return; | 45 return; |
45 } | 46 } |
46 const SkIRect bounds = fCodec->getInfo().bounds().makeOutset(1, 1); | 47 const SkIRect bounds = fCodec->getInfo().bounds().makeOutset(1, 1); |
47 SkPaint boundsPaint; | 48 SkPaint boundsPaint; |
48 boundsPaint.setStyle(SkPaint::kStroke_Style); | 49 boundsPaint.setStyle(SkPaint::kStroke_Style); |
49 canvas->drawIRect(bounds, boundsPaint); | 50 canvas->drawIRect(bounds, boundsPaint); |
50 } | 51 } |
51 | 52 |
52 void drawFrame(SkCanvas* canvas, int frameIndex) { | 53 void drawFrame(SkCanvas* canvas, int frameIndex) { |
53 // FIXME: Create from an Image/ImageGenerator? | 54 // FIXME: Create from an Image/ImageGenerator? |
54 if (frameIndex >= (int) fFrames.size()) { | 55 if (frameIndex >= (int) fFrames.size()) { |
55 fFrames.resize(frameIndex + 1); | 56 fFrames.resize(frameIndex + 1); |
56 } | 57 } |
57 SkBitmap& bm = fFrames[frameIndex]; | 58 SkBitmap& bm = fFrames[frameIndex]; |
58 if (!bm.getPixels()) { | 59 if (!bm.getPixels()) { |
59 const SkImageInfo info = fCodec->getInfo().makeColorType(kN32_SkColo
rType); | 60 const SkImageInfo info = fCodec->getInfo().makeColorType(kN32_SkColo
rType); |
60 bm.allocPixels(info); | 61 bm.allocPixels(info); |
61 | 62 |
62 SkCodec::MultiFrameOptions multiOpts; | 63 SkCodec::MultiFrameOptions multiOpts; |
63 multiOpts.fIndex = frameIndex; | 64 multiOpts.fIndex = frameIndex; |
64 multiOpts.fHasPriorFrame = false; | 65 multiOpts.fHasPriorFrame = false; |
65 const size_t requiredFrame = fCodec->getRequiredFrame(frameIndex); | 66 const size_t requiredFrame = fFrameInfos[frameIndex].fRequiredFrame; |
66 if (requiredFrame != SkCodec::kIndependentFrame) { | 67 if (requiredFrame != SkCodec::kIndependentFrame) { |
67 SkASSERT(requiredFrame < fFrames.size()); | 68 SkASSERT(requiredFrame < fFrames.size()); |
68 SkBitmap& requiredBitmap = fFrames[requiredFrame]; | 69 SkBitmap& requiredBitmap = fFrames[requiredFrame]; |
69 // For simplicity, do not try to cache old frames | 70 // For simplicity, do not try to cache old frames |
70 if (requiredBitmap.getPixels() && requiredBitmap.copyTo(&bm)) { | 71 if (requiredBitmap.getPixels() && requiredBitmap.copyTo(&bm)) { |
71 multiOpts.fHasPriorFrame = true; | 72 multiOpts.fHasPriorFrame = true; |
72 } | 73 } |
73 } | 74 } |
74 | 75 |
75 SkCodec::Options opts; | 76 SkCodec::Options opts; |
(...skipping 17 matching lines...) Expand all Loading... |
93 | 94 |
94 private: | 95 private: |
95 SkString onShortName() override { | 96 SkString onShortName() override { |
96 return SkString("animatedGif"); | 97 return SkString("animatedGif"); |
97 } | 98 } |
98 | 99 |
99 SkISize onISize() override { | 100 SkISize onISize() override { |
100 if (this->initCodec()) { | 101 if (this->initCodec()) { |
101 SkISize dim = fCodec->getInfo().dimensions(); | 102 SkISize dim = fCodec->getInfo().dimensions(); |
102 // Wide enough to display all the frames. | 103 // Wide enough to display all the frames. |
103 dim.fWidth *= fCodec->getFrameCount(); | 104 dim.fWidth *= fTotalFrames; |
104 // Tall enough to show the row of frames plus an animating version. | 105 // Tall enough to show the row of frames plus an animating version. |
105 dim.fHeight *= 2; | 106 dim.fHeight *= 2; |
106 return dim; | 107 return dim; |
107 } | 108 } |
108 return SkISize::Make(640, 480); | 109 return SkISize::Make(640, 480); |
109 } | 110 } |
110 | 111 |
111 void onDrawBackground(SkCanvas* canvas) override { | 112 void onDrawBackground(SkCanvas* canvas) override { |
112 if (this->initCodec()) { | 113 if (this->initCodec()) { |
113 SkAutoCanvasRestore acr(canvas, true); | 114 SkAutoCanvasRestore acr(canvas, true); |
(...skipping 21 matching lines...) Expand all Loading... |
135 return false; | 136 return false; |
136 } | 137 } |
137 | 138 |
138 fCodec.reset(SkCodec::NewFromStream(stream.release())); | 139 fCodec.reset(SkCodec::NewFromStream(stream.release())); |
139 if (!fCodec) { | 140 if (!fCodec) { |
140 SkDebugf("Could create codec from %s", FLAGS_animatedGif[0]); | 141 SkDebugf("Could create codec from %s", FLAGS_animatedGif[0]); |
141 return false; | 142 return false; |
142 } | 143 } |
143 | 144 |
144 fFrame = 0; | 145 fFrame = 0; |
145 fTotalFrames = fCodec->getFrameCount(); | 146 fFrameInfos = fCodec->getFrameInfo(); |
| 147 fTotalFrames = fFrameInfos.size(); |
146 return true; | 148 return true; |
147 } | 149 } |
148 | 150 |
149 void onDraw(SkCanvas* canvas) { | 151 void onDraw(SkCanvas* canvas) { |
150 if (!fCodec) { | 152 if (!fCodec) { |
151 SkString errorText = SkStringPrintf("Nothing to draw; %s", FLAGS_ani
matedGif[0]); | 153 SkString errorText = SkStringPrintf("Nothing to draw; %s", FLAGS_ani
matedGif[0]); |
152 error(canvas, errorText); | 154 error(canvas, errorText); |
153 return; | 155 return; |
154 } | 156 } |
155 | 157 |
156 // Now draw it animated. | 158 // Now draw it animated. |
157 SkAutoCanvasRestore acr(canvas, true); | 159 SkAutoCanvasRestore acr(canvas, true); |
158 canvas->translate(0, fCodec->getInfo().height()); | 160 canvas->translate(0, fCodec->getInfo().height()); |
159 this->drawBounds(canvas); | 161 this->drawBounds(canvas); |
160 this->drawFrame(canvas, fFrame); | 162 this->drawFrame(canvas, fFrame); |
161 } | 163 } |
162 | 164 |
163 bool onAnimate(const SkAnimTimer& timer) override { | 165 bool onAnimate(const SkAnimTimer& timer) override { |
164 if (!fCodec || fTotalFrames == 1) { | 166 if (!fCodec || fTotalFrames == 1) { |
165 return false; | 167 return false; |
166 } | 168 } |
167 | 169 |
168 double secs = timer.msec() * .1; | 170 double secs = timer.msec() * .1; |
169 if (fNextUpdate < double(0)) { | 171 if (fNextUpdate < double(0)) { |
170 // This is a sentinel that we have not done any updates yet. | 172 // This is a sentinel that we have not done any updates yet. |
171 // I'm assuming this gets called *after* onOnceBeforeDraw, so our fi
rst frame should | 173 // I'm assuming this gets called *after* onOnceBeforeDraw, so our fi
rst frame should |
172 // already have been retrieved. | 174 // already have been retrieved. |
173 SkASSERT(fFrame == 0); | 175 SkASSERT(fFrame == 0); |
174 fNextUpdate = secs + fCodec->getFrameDuration(fFrame); | 176 fNextUpdate = secs + fFrameInfos[fFrame].fDuration; |
175 | 177 |
176 return true; | 178 return true; |
177 } | 179 } |
178 | 180 |
179 if (secs < fNextUpdate) { | 181 if (secs < fNextUpdate) { |
180 return true; | 182 return true; |
181 } | 183 } |
182 | 184 |
183 while (secs >= fNextUpdate) { | 185 while (secs >= fNextUpdate) { |
184 // Retrieve the next frame. | 186 // Retrieve the next frame. |
185 fFrame++; | 187 fFrame++; |
186 if (fFrame == fTotalFrames) { | 188 if (fFrame == fTotalFrames) { |
187 fFrame = 0; | 189 fFrame = 0; |
188 } | 190 } |
189 | 191 |
190 // Note that we loop here. This is not safe if we need to draw the i
ntermediate frame | 192 // Note that we loop here. This is not safe if we need to draw the i
ntermediate frame |
191 // in order to draw correctly. | 193 // in order to draw correctly. |
192 fNextUpdate += fCodec->getFrameDuration(fFrame); | 194 fNextUpdate += fFrameInfos[fFrame].fDuration; |
193 } | 195 } |
194 | 196 |
195 return true; | 197 return true; |
196 } | 198 } |
197 }; | 199 }; |
198 | 200 |
199 DEF_GM(return new AnimatedGifGM); | 201 DEF_GM(return new AnimatedGifGM); |
200 | 202 |
OLD | NEW |