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