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 "include/android/SkAnimatedImage.h" 9 #include "include/codec/SkAndroidCodec.h" 10 #include "include/core/SkCanvas.h" 11 #include "include/core/SkFont.h" 12 #include "include/core/SkPaint.h" 13 #include "include/core/SkPictureRecorder.h" 14 #include "include/core/SkRect.h" 15 #include "include/core/SkScalar.h" 16 #include "include/core/SkString.h" 17 #include "tools/Resources.h" 18 #include "tools/fonts/FontToolUtils.h" 19 #include "tools/timer/TimeUtils.h" 20 #include "tools/viewer/Slide.h" 21 22 static constexpr char kPauseKey = 'p'; 23 static constexpr char kResetKey = 'r'; 24 25 class AnimatedImageSlide : public Slide { 26 sk_sp<SkAnimatedImage> fImage; 27 sk_sp<SkDrawable> fDrawable; 28 SkScalar fYOffset = 0; 29 bool fRunning = false; 30 double fCurrentTime = 0.0; 31 double fLastWallTime = 0.0; 32 double fTimeToShowNextFrame = 0.0; 33 34 public: AnimatedImageSlide()35 AnimatedImageSlide() { fName = "AnimatedImage"; } 36 draw(SkCanvas * canvas)37 void draw(SkCanvas* canvas) override { 38 SkFont font = ToolUtils::DefaultFont(); 39 font.setSize(20); 40 41 SkString str = SkStringPrintf("Press '%c' to start/pause; '%c' to reset.", 42 kPauseKey, kResetKey); 43 const char* text = str.c_str(); 44 SkRect bounds; 45 font.measureText(text, strlen(text), SkTextEncoding::kUTF8, &bounds); 46 fYOffset = bounds.height(); 47 48 canvas->drawSimpleText(text, strlen(text), SkTextEncoding::kUTF8, 5, fYOffset, font, SkPaint()); 49 fYOffset *= 2; 50 51 if (!fImage) { 52 return; 53 } 54 55 canvas->translate(0, fYOffset); 56 57 canvas->drawDrawable(fImage.get()); 58 canvas->drawDrawable(fDrawable.get(), fImage->getBounds().width(), 0); 59 } 60 animate(double nanos)61 bool animate(double nanos) override { 62 if (!fImage) { 63 return false; 64 } 65 66 const double lastWallTime = fLastWallTime; 67 fLastWallTime = TimeUtils::NanosToMSec(nanos); 68 69 if (fRunning) { 70 fCurrentTime += fLastWallTime - lastWallTime; 71 if (fCurrentTime > fTimeToShowNextFrame) { 72 fTimeToShowNextFrame += fImage->decodeNextFrame(); 73 if (fImage->isFinished()) { 74 fRunning = false; 75 } 76 } 77 } 78 79 return true; 80 } 81 load(SkScalar w,SkScalar h)82 void load(SkScalar w, SkScalar h) override { 83 sk_sp<SkData> file(GetResourceAsData("images/alphabetAnim.gif")); 84 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(file)); 85 if (!codec) { 86 return; 87 } 88 89 fImage = SkAnimatedImage::Make(SkAndroidCodec::MakeFromCodec(std::move(codec))); 90 if (!fImage) { 91 return; 92 } 93 94 fTimeToShowNextFrame = fImage->currentFrameDuration(); 95 SkPictureRecorder recorder; 96 auto canvas = recorder.beginRecording(fImage->getBounds()); 97 canvas->drawDrawable(fImage.get()); 98 fDrawable = recorder.finishRecordingAsDrawable(); 99 } 100 onChar(SkUnichar uni)101 bool onChar(SkUnichar uni) override { 102 if (fImage) { 103 switch (uni) { 104 case kPauseKey: 105 fRunning = !fRunning; 106 if (!fImage->isFinished()) { 107 return true; 108 } 109 [[fallthrough]]; 110 case kResetKey: 111 fImage->reset(); 112 fCurrentTime = fLastWallTime; 113 fTimeToShowNextFrame = fCurrentTime + fImage->currentFrameDuration(); 114 return true; 115 default: 116 break; 117 } 118 } 119 return false; 120 } 121 }; 122 123 DEF_SLIDE( return new AnimatedImageSlide(); ) 124