| OLD | NEW | 
|---|
| (Empty) |  | 
|  | 1 /* | 
|  | 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" | 
|  | 9 #include "SkAnimTimer.h" | 
|  | 10 #include "SkCanvas.h" | 
|  | 11 #include "SkCodec.h" | 
|  | 12 #include "SkColor.h" | 
|  | 13 #include "SkCommandLineFlags.h" | 
|  | 14 #include "SkPaint.h" | 
|  | 15 #include "SkString.h" | 
|  | 16 #include "Resources.h" | 
|  | 17 | 
|  | 18 #include <vector> | 
|  | 19 | 
|  | 20 DEFINE_string(animatedGif, "test640x479.gif", "Animated gif in resources folder"
     ); | 
|  | 21 | 
|  | 22 namespace { | 
|  | 23     void error(SkCanvas* canvas, const SkString& errorText) { | 
|  | 24         constexpr SkScalar kOffset = 5.0f; | 
|  | 25         canvas->drawColor(SK_ColorRED); | 
|  | 26         SkPaint paint; | 
|  | 27         SkRect bounds; | 
|  | 28         paint.measureText(errorText.c_str(), errorText.size(), &bounds); | 
|  | 29         canvas->drawText(errorText.c_str(), errorText.size(), kOffset, bounds.he
     ight() + kOffset, | 
|  | 30                          paint); | 
|  | 31     } | 
|  | 32 } | 
|  | 33 | 
|  | 34 class AnimatedGifGM : public skiagm::GM { | 
|  | 35 private: | 
|  | 36     std::unique_ptr<SkCodec>        fCodec; | 
|  | 37     size_t                          fFrame; | 
|  | 38     double                          fNextUpdate; | 
|  | 39     size_t                          fTotalFrames; | 
|  | 40     std::vector<SkCodec::FrameInfo> fFrameInfos; | 
|  | 41     std::vector<SkBitmap>           fFrames; | 
|  | 42 | 
|  | 43     void drawFrame(SkCanvas* canvas, int frameIndex) { | 
|  | 44         // FIXME: Create from an Image/ImageGenerator? | 
|  | 45         if (frameIndex >= (int) fFrames.size()) { | 
|  | 46             fFrames.resize(frameIndex + 1); | 
|  | 47         } | 
|  | 48         SkBitmap& bm = fFrames[frameIndex]; | 
|  | 49         if (!bm.getPixels()) { | 
|  | 50             const SkImageInfo info = fCodec->getInfo().makeColorType(kN32_SkColo
     rType); | 
|  | 51             bm.allocPixels(info); | 
|  | 52 | 
|  | 53             SkCodec::Options opts; | 
|  | 54             opts.fFrameIndex = frameIndex; | 
|  | 55             opts.fHasPriorFrame = false; | 
|  | 56             const size_t requiredFrame = fFrameInfos[frameIndex].fRequiredFrame; | 
|  | 57             if (requiredFrame != SkCodec::kNone) { | 
|  | 58                 SkASSERT(requiredFrame < fFrames.size()); | 
|  | 59                 SkBitmap& requiredBitmap = fFrames[requiredFrame]; | 
|  | 60                 // For simplicity, do not try to cache old frames | 
|  | 61                 if (requiredBitmap.getPixels() && requiredBitmap.copyTo(&bm)) { | 
|  | 62                     opts.fHasPriorFrame = true; | 
|  | 63                 } | 
|  | 64             } | 
|  | 65 | 
|  | 66             if (SkCodec::kSuccess != fCodec->getPixels(info, bm.getPixels(), | 
|  | 67                                                        bm.rowBytes(), &opts, | 
|  | 68                                                        nullptr, nullptr)) { | 
|  | 69                 SkDebugf("Could not getPixels for frame %i: %s", frameIndex, FLA
     GS_animatedGif[0]); | 
|  | 70                 return; | 
|  | 71             } | 
|  | 72         } | 
|  | 73 | 
|  | 74         canvas->drawBitmap(bm, 0, 0); | 
|  | 75     } | 
|  | 76 | 
|  | 77 public: | 
|  | 78     AnimatedGifGM() | 
|  | 79     : fFrame(0) | 
|  | 80     , fNextUpdate (-1) | 
|  | 81     , fTotalFrames (-1) {} | 
|  | 82 | 
|  | 83 private: | 
|  | 84     SkString onShortName() override { | 
|  | 85         return SkString("animatedGif"); | 
|  | 86     } | 
|  | 87 | 
|  | 88     SkISize onISize() override { | 
|  | 89         if (this->initCodec()) { | 
|  | 90             SkISize dim = fCodec->getInfo().dimensions(); | 
|  | 91             // Wide enough to display all the frames. | 
|  | 92             dim.fWidth *= fTotalFrames; | 
|  | 93             // Tall enough to show the row of frames plus an animating version. | 
|  | 94             dim.fHeight *= 2; | 
|  | 95             return dim; | 
|  | 96         } | 
|  | 97         return SkISize::Make(640, 480); | 
|  | 98     } | 
|  | 99 | 
|  | 100     void onDrawBackground(SkCanvas* canvas) override { | 
|  | 101         if (this->initCodec()) { | 
|  | 102             SkAutoCanvasRestore acr(canvas, true); | 
|  | 103             for (size_t frameIndex = 0; frameIndex < fTotalFrames; frameIndex++)
      { | 
|  | 104                 this->drawFrame(canvas, frameIndex); | 
|  | 105                 canvas->translate(fCodec->getInfo().width(), 0); | 
|  | 106             } | 
|  | 107         } | 
|  | 108     } | 
|  | 109 | 
|  | 110     bool initCodec() { | 
|  | 111         if (fCodec) { | 
|  | 112             return true; | 
|  | 113         } | 
|  | 114         if (FLAGS_animatedGif.isEmpty()) { | 
|  | 115             SkDebugf("Nothing specified for --animatedGif!"); | 
|  | 116             return false; | 
|  | 117         } | 
|  | 118 | 
|  | 119         std::unique_ptr<SkStream> stream(GetResourceAsStream(FLAGS_animatedGif[0
     ])); | 
|  | 120         if (!stream) { | 
|  | 121             return false; | 
|  | 122         } | 
|  | 123 | 
|  | 124         fCodec.reset(SkCodec::NewFromStream(stream.release())); | 
|  | 125         if (!fCodec) { | 
|  | 126             SkDebugf("Could create codec from %s", FLAGS_animatedGif[0]); | 
|  | 127             return false; | 
|  | 128         } | 
|  | 129 | 
|  | 130         fFrame = 0; | 
|  | 131         fFrameInfos = fCodec->getFrameInfo(); | 
|  | 132         fTotalFrames = fFrameInfos.size(); | 
|  | 133         return true; | 
|  | 134     } | 
|  | 135 | 
|  | 136     void onDraw(SkCanvas* canvas) override { | 
|  | 137         if (!fCodec) { | 
|  | 138             SkString errorText = SkStringPrintf("Nothing to draw; %s", FLAGS_ani
     matedGif[0]); | 
|  | 139             error(canvas, errorText); | 
|  | 140             return; | 
|  | 141         } | 
|  | 142 | 
|  | 143         SkAutoCanvasRestore acr(canvas, true); | 
|  | 144         canvas->translate(0, fCodec->getInfo().height()); | 
|  | 145         this->drawFrame(canvas, fFrame); | 
|  | 146     } | 
|  | 147 | 
|  | 148     bool onAnimate(const SkAnimTimer& timer) override { | 
|  | 149         if (!fCodec || fTotalFrames == 1) { | 
|  | 150             return false; | 
|  | 151         } | 
|  | 152 | 
|  | 153         double secs = timer.msec() * .1; | 
|  | 154         if (fNextUpdate < double(0)) { | 
|  | 155             // This is a sentinel that we have not done any updates yet. | 
|  | 156             // I'm assuming this gets called *after* onOnceBeforeDraw, so our fi
     rst frame should | 
|  | 157             // already have been retrieved. | 
|  | 158             SkASSERT(fFrame == 0); | 
|  | 159             fNextUpdate = secs + fFrameInfos[fFrame].fDuration; | 
|  | 160 | 
|  | 161             return true; | 
|  | 162         } | 
|  | 163 | 
|  | 164         if (secs < fNextUpdate) { | 
|  | 165             return true; | 
|  | 166         } | 
|  | 167 | 
|  | 168         while (secs >= fNextUpdate) { | 
|  | 169             // Retrieve the next frame. | 
|  | 170             fFrame++; | 
|  | 171             if (fFrame == fTotalFrames) { | 
|  | 172                 fFrame = 0; | 
|  | 173             } | 
|  | 174 | 
|  | 175             // Note that we loop here. This is not safe if we need to draw the i
     ntermediate frame | 
|  | 176             // in order to draw correctly. | 
|  | 177             fNextUpdate += fFrameInfos[fFrame].fDuration; | 
|  | 178         } | 
|  | 179 | 
|  | 180         return true; | 
|  | 181     } | 
|  | 182 }; | 
|  | 183 | 
|  | 184 DEF_GM(return new AnimatedGifGM); | 
|  | 185 | 
| OLD | NEW | 
|---|