| // Copyright 2019 Google LLC. |
| // Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. |
| |
| #include "tools/skottie_ios_app/SkottieUIView.h" |
| |
| #include "tools/skottie_ios_app/SkAnimationDraw.h" |
| #include "tools/skottie_ios_app/SkTimeKeeper.h" |
| |
| #include "include/core/SkCanvas.h" |
| #include "include/core/SkPaint.h" |
| #include "include/core/SkSurface.h" |
| #include "include/core/SkTime.h" |
| #include "include/utils/mac/SkCGUtils.h" |
| |
| #include "modules/skottie/include/Skottie.h" |
| |
| @implementation SkottieUIView { |
| SkAnimationDraw fDraw; |
| SkTimeKeeper fClock; |
| SkBitmap fBackBuffer; |
| } |
| |
| - (void)drawRect:(CGRect)rect { |
| double next = fClock.paused() ? 0 : (1.0 / 30.0) + SkTime::GetNSecs() * 1e-9; |
| [super drawRect:rect]; |
| // TODO(halcanary): Use the rect and the InvalidationController to speed up rendering. |
| if (rect.size.width > 0 && rect.size.height > 0 && fDraw) { |
| CGSize size = [self bounds].size; |
| SkISize iSize = {(int)size.width, (int)size.height}; |
| |
| if (fBackBuffer.drawsNothing() || iSize != fBackBuffer.dimensions()) { |
| fBackBuffer.allocN32Pixels(iSize.fWidth, iSize.fHeight); |
| } |
| fBackBuffer.eraseColor(SK_ColorTRANSPARENT); |
| { |
| SkCanvas canvas(fBackBuffer); |
| if (!fClock.paused()) { |
| fDraw.seek(fClock.currentTime()); |
| } |
| fDraw.draw({(float)size.width, (float)size.height}, &canvas); |
| } |
| SkCGDrawBitmap(UIGraphicsGetCurrentContext(), fBackBuffer, 0, 0); |
| } |
| if (next) { |
| [NSTimer scheduledTimerWithTimeInterval:std::max(0.0, next - SkTime::GetNSecs() * 1e-9) |
| target:self |
| selector:@selector(setNeedsDisplay) |
| userInfo:nil |
| repeats:NO]; |
| } |
| } |
| |
| - (BOOL)loadAnimation:(NSData*) data { |
| fDraw.load((const void*)[data bytes], (size_t)[data length]); |
| fClock.setDuration(fDraw.duration()); |
| [self setNeedsDisplay]; |
| return (bool)fDraw; |
| } |
| |
| - (void)setStopAtEnd:(BOOL)stop{ fClock.setStopAtEnd(stop); } |
| |
| - (float)animationDurationSeconds { return fClock.duration(); } |
| |
| - (float)currentTime { return fDraw ? fClock.currentTime() : 0; } |
| |
| - (void)seek:(float)seconds { |
| if (fDraw) { |
| fClock.seek(seconds); |
| [self setNeedsDisplay]; |
| } |
| } |
| |
| - (CGSize)size { return {(CGFloat)fDraw.size().width(), (CGFloat)fDraw.size().height()}; } |
| |
| - (BOOL)togglePaused { |
| fClock.togglePaused(); |
| [self setNeedsDisplay]; |
| return fClock.paused(); |
| } |
| |
| - (BOOL)isPaused { return fClock.paused(); } |
| @end |