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