1/* 2 * Copyright 2018 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 "SkAndroidCodec.h" 9#include "SkAnimatedImage.h" 10#include "SkAnimTimer.h" 11#include "SkCanvas.h" 12#include "SkPaint.h" 13#include "SkPictureRecorder.h" 14#include "SkRect.h" 15#include "SkScalar.h" 16#include "SkString.h" 17 18#include "SampleCode.h" 19#include "Resources.h" 20 21static constexpr char kPauseKey = 'p'; 22static constexpr char kResetKey = 'r'; 23 24class SampleAnimatedImage : public SampleView { 25public: 26 SampleAnimatedImage() 27 : INHERITED() 28 , fYOffset(0) 29 {} 30 31protected: 32 void onDrawBackground(SkCanvas* canvas) override { 33 SkPaint paint; 34 paint.setAntiAlias(true); 35 constexpr SkScalar kTextSize = 20; 36 paint.setTextSize(kTextSize); 37 38 SkString str = SkStringPrintf("Press '%c' to start/pause; '%c' to reset.", 39 kPauseKey, kResetKey); 40 const char* text = str.c_str(); 41 SkRect bounds; 42 paint.measureText(text, strlen(text), &bounds); 43 fYOffset = bounds.height(); 44 45 canvas->drawText(text, strlen(text), 5, fYOffset, paint); 46 fYOffset *= 2; 47 } 48 49 void onDrawContent(SkCanvas* canvas) override { 50 if (!fImage) { 51 return; 52 } 53 54 canvas->translate(0, fYOffset); 55 56 canvas->drawDrawable(fImage.get()); 57 canvas->drawDrawable(fDrawable.get(), fImage->getBounds().width(), 0); 58 } 59 60 bool onAnimate(const SkAnimTimer& animTimer) override { 61 if (!fImage) { 62 return false; 63 } 64 65 const double lastWallTime = fLastWallTime; 66 fLastWallTime = animTimer.msec(); 67 68 if (fRunning) { 69 fCurrentTime += fLastWallTime - lastWallTime; 70 if (fCurrentTime > fTimeToShowNextFrame) { 71 fTimeToShowNextFrame += fImage->decodeNextFrame(); 72 if (fImage->isFinished()) { 73 fRunning = false; 74 } 75 } 76 } 77 78 return true; 79 } 80 81 void onOnceBeforeDraw() override { 82 sk_sp<SkData> file(GetResourceAsData("images/alphabetAnim.gif")); 83 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(file)); 84 if (!codec) { 85 return; 86 } 87 88 fImage = SkAnimatedImage::Make(SkAndroidCodec::MakeFromCodec(std::move(codec))); 89 if (!fImage) { 90 return; 91 } 92 93 fTimeToShowNextFrame = fImage->currentFrameDuration(); 94 SkPictureRecorder recorder; 95 auto canvas = recorder.beginRecording(fImage->getBounds()); 96 canvas->drawDrawable(fImage.get()); 97 fDrawable = recorder.finishRecordingAsDrawable(); 98 } 99 100 bool onQuery(SkEvent* evt) override { 101 if (SampleCode::TitleQ(*evt)) { 102 SampleCode::TitleR(evt, "AnimatedImage"); 103 return true; 104 } 105 106 SkUnichar uni; 107 if (fImage && SampleCode::CharQ(*evt, &uni)) { 108 switch (uni) { 109 case kPauseKey: 110 fRunning = !fRunning; 111 if (fImage->isFinished()) { 112 // fall through 113 } else { 114 return true; 115 } 116 case kResetKey: 117 fImage->reset(); 118 fCurrentTime = fLastWallTime; 119 fTimeToShowNextFrame = fCurrentTime + fImage->currentFrameDuration(); 120 return true; 121 default: 122 break; 123 } 124 } 125 return this->INHERITED::onQuery(evt); 126 } 127 128private: 129 sk_sp<SkAnimatedImage> fImage; 130 sk_sp<SkDrawable> fDrawable; 131 SkScalar fYOffset; 132 bool fRunning = false; 133 double fCurrentTime = 0.0; 134 double fLastWallTime = 0.0; 135 double fTimeToShowNextFrame = 0.0; 136 typedef SampleView INHERITED; 137}; 138 139/////////////////////////////////////////////////////////////////////////////// 140 141static SkView* MyFactory() { 142 return new SampleAnimatedImage; 143} 144 145static SkViewRegister reg(MyFactory); 146