| 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 |