| // Copyright 2018 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "topaz/bin/ui/skottie_viewer/view.h" |
| |
| #include <lib/fsl/vmo/vector.h> |
| |
| #include "src/lib/fxl/logging.h" |
| #include "third_party/skia/include/core/SkColor.h" |
| |
| namespace skottie { |
| |
| constexpr float kSecondsPerNanosecond = .000'000'001f; |
| |
| View::View(scenic::ViewContextTransitional view_context) |
| : SkiaView(std::move(view_context), "Skottie View"), player_binding_(this) { |
| outgoing_services().AddService(loader_bindings_.GetHandler(this)); |
| } |
| |
| void View::Load(fuchsia::mem::Buffer payload, |
| fuchsia::skia::skottie::Options options, |
| LoadCallback callback) { |
| std::vector<uint8_t> data; |
| if (!fsl::VectorFromVmo(payload, &data)) { |
| FXL_LOG(ERROR) << "VectorFromVmo failed"; |
| return; |
| } |
| |
| start_time_ = 0L; |
| background_color_ = options.background_color; |
| loop_ = options.loop; |
| playing_ = options.autoplay; |
| |
| class Logger final : public skottie::Logger { |
| public: |
| // |skottie::Logger| |
| void log(skottie::Logger::Level level, const char message[], |
| const char json[]) override { |
| error_ = error_ || level == skottie::Logger::Level::kError; |
| buffer_ << message << (json ? json : "") << std::endl; |
| } |
| |
| bool has_errors() { return error_; } |
| std::string log() { return buffer_.str(); } |
| |
| private: |
| bool error_; |
| std::ostringstream buffer_; |
| }; |
| |
| auto logger = sk_make_sp<Logger>(); |
| skottie::Animation::Builder builder; |
| animation_ = builder.setLogger(logger).make( |
| reinterpret_cast<const char*>(data.data()), data.size()); |
| |
| fuchsia::skia::skottie::Status status; |
| status.error = logger->has_errors(); |
| status.message = logger->log(); |
| |
| fidl::InterfaceHandle<fuchsia::skia::skottie::Player> player; |
| if (animation_) { |
| duration_ = animation_->duration(); |
| status.duration = animation_->duration(); |
| player_binding_.Bind(player.NewRequest()); |
| } |
| |
| callback(std::move(status), std::move(player)); |
| } |
| |
| void View::Seek(float t) { |
| position_ = t; |
| start_time_ = 0L; |
| InvalidateScene(); |
| } |
| |
| void View::Play() { |
| playing_ = true; |
| InvalidateScene(); |
| } |
| |
| void View::Pause() { |
| playing_ = false; |
| InvalidateScene(); |
| } |
| |
| void View::OnSceneInvalidated( |
| fuchsia::images::PresentationInfo presentation_info) { |
| if (animation_ && playing_) { |
| SkCanvas* canvas = AcquireCanvas(); |
| if (!canvas) |
| return; |
| |
| uint64_t presentation_time = presentation_info.presentation_time; |
| if (!start_time_) { |
| start_time_ = presentation_time; |
| } |
| |
| float d = animation_->duration(); |
| float t = (presentation_time - start_time_) * kSecondsPerNanosecond + |
| position_ * animation_->duration(); |
| animation_->seek(std::fmod(t, d) / d); |
| |
| canvas->clear(background_color_); |
| |
| Draw(canvas); |
| |
| ReleaseAndSwapCanvas(); |
| |
| // Animate. |
| InvalidateScene(); |
| } |
| } |
| |
| void View::Draw(SkCanvas* canvas) { |
| FXL_DCHECK(animation_); |
| |
| const auto rect = |
| SkRect::MakeSize(SkSize::Make(logical_size().x, logical_size().y)); |
| |
| SkAutoCanvasRestore acr(canvas, true); |
| animation_->render(canvas, &rect); |
| } |
| |
| } // namespace skottie |