From 493280782430b76251145cfb7d78d6d33b65c1d1 Mon Sep 17 00:00:00 2001 From: Florin Malita Date: Mon, 8 Jan 2018 12:51:12 -0500 Subject: [skotty,sksg] Initial image support TBR= Change-Id: Ib3c918b1d746e4f190ae05708681f2d5519afdb2 Reviewed-on: https://skia-review.googlesource.com/91980 Reviewed-by: Florin Malita Commit-Queue: Florin Malita --- experimental/skotty/Skotty.cpp | 79 ++++++++++++++++++++++++++++++++++++----- experimental/skotty/Skotty.h | 15 ++++++-- experimental/sksg/SkSGImage.cpp | 29 +++++++++++++++ experimental/sksg/SkSGImage.h | 49 +++++++++++++++++++++++++ 4 files changed, 162 insertions(+), 10 deletions(-) create mode 100644 experimental/sksg/SkSGImage.cpp create mode 100644 experimental/sksg/SkSGImage.h (limited to 'experimental') diff --git a/experimental/skotty/Skotty.cpp b/experimental/skotty/Skotty.cpp index b331547316..077640b695 100644 --- a/experimental/skotty/Skotty.cpp +++ b/experimental/skotty/Skotty.cpp @@ -12,14 +12,17 @@ #include "SkottyPriv.h" #include "SkottyProperties.h" #include "SkData.h" +#include "SkImage.h" #include "SkMakeUnique.h" +#include "SkOSPath.h" #include "SkPaint.h" #include "SkPath.h" #include "SkPoint.h" #include "SkSGColor.h" #include "SkSGDraw.h" -#include "SkSGInvalidationController.h" #include "SkSGGroup.h" +#include "SkSGImage.h" +#include "SkSGInvalidationController.h" #include "SkSGMerge.h" #include "SkSGPath.h" #include "SkSGRect.h" @@ -42,6 +45,7 @@ namespace { using AssetMap = SkTHashMap; struct AttachContext { + const ResourceProvider& fResources; const AssetMap& fAssets; SkTArray>& fAnimators; }; @@ -550,11 +554,43 @@ sk_sp AttachSolidLayer(const Json::Value& layer, AttachContext return nullptr; } -sk_sp AttachImageLayer(const Json::Value& layer, AttachContext*) { +sk_sp AttachImageAsset(const Json::Value& jimage, AttachContext* ctx) { + SkASSERT(jimage.isObject()); + + const auto name = ParseString(jimage["p"], ""), + path = ParseString(jimage["u"], ""); + if (name.isEmpty()) + return nullptr; + + // TODO: plumb resource paths explicitly to ResourceProvider? + const auto resName = path.isEmpty() ? name : SkOSPath::Join(path.c_str(), name.c_str()); + const auto resStream = ctx->fResources.openStream(resName.c_str()); + if (!resStream || !resStream->hasLength()) { + LOG("!! Could not load image resource: %s\n", resName.c_str()); + return nullptr; + } + + // TODO: non-intrisic image sizing + return sksg::Image::Make( + SkImage::MakeFromEncoded(SkData::MakeFromStream(resStream.get(), resStream->getLength()))); +} + +sk_sp AttachImageLayer(const Json::Value& layer, AttachContext* ctx) { SkASSERT(layer.isObject()); - LOG("?? Image layer stub\n"); - return nullptr; + auto refId = ParseString(layer["refId"], ""); + if (refId.isEmpty()) { + LOG("!! Image layer missing refId\n"); + return nullptr; + } + + const auto* jimage = ctx->fAssets.find(refId); + if (!jimage) { + LOG("!! Image asset not found: '%s'\n", refId.c_str()); + return nullptr; + } + + return AttachImageAsset(**jimage, ctx); } sk_sp AttachNullLayer(const Json::Value& layer, AttachContext*) { @@ -699,7 +735,7 @@ sk_sp AttachComposition(const Json::Value& comp, AttachContext } // namespace -std::unique_ptr Animation::Make(SkStream* stream) { +std::unique_ptr Animation::Make(SkStream* stream, const ResourceProvider& res) { if (!stream->hasLength()) { // TODO: handle explicit buffering? LOG("!! cannot parse streaming content\n"); @@ -733,10 +769,37 @@ std::unique_ptr Animation::Make(SkStream* stream) { return nullptr; } - return std::unique_ptr(new Animation(std::move(version), size, fps, json)); + return std::unique_ptr(new Animation(res, std::move(version), size, fps, json)); +} + +std::unique_ptr Animation::MakeFromFile(const char path[], const ResourceProvider* res) { + class DirectoryResourceProvider final : public ResourceProvider { + public: + explicit DirectoryResourceProvider(SkString dir) : fDir(std::move(dir)) {} + + std::unique_ptr openStream(const char resource[]) const override { + const auto resPath = SkOSPath::Join(fDir.c_str(), resource); + return SkStream::MakeFromFile(resPath.c_str()); + } + + private: + const SkString fDir; + }; + + const auto jsonStream = SkStream::MakeFromFile(path); + if (!jsonStream) + return nullptr; + + std::unique_ptr defaultProvider; + if (!res) { + defaultProvider = skstd::make_unique(SkOSPath::Dirname(path)); + } + + return Make(jsonStream.get(), res ? *res : *defaultProvider); } -Animation::Animation(SkString version, const SkSize& size, SkScalar fps, const Json::Value& json) +Animation::Animation(const ResourceProvider& resources, + SkString version, const SkSize& size, SkScalar fps, const Json::Value& json) : fVersion(std::move(version)) , fSize(size) , fFrameRate(fps) @@ -752,7 +815,7 @@ Animation::Animation(SkString version, const SkSize& size, SkScalar fps, const J assets.set(ParseString(asset["id"], ""), &asset); } - AttachContext ctx = { assets, fAnimators }; + AttachContext ctx = { resources, assets, fAnimators }; fDom = AttachComposition(json, &ctx); LOG("** Attached %d animators\n", fAnimators.count()); diff --git a/experimental/skotty/Skotty.h b/experimental/skotty/Skotty.h index d02dc8d3ab..ebd103d60c 100644 --- a/experimental/skotty/Skotty.h +++ b/experimental/skotty/Skotty.h @@ -29,9 +29,18 @@ namespace skotty { class AnimatorBase; +class ResourceProvider : public SkNoncopyable { +public: + virtual ~ResourceProvider() = default; + + virtual std::unique_ptr openStream(const char resource[]) const = 0; +}; + class Animation : public SkNoncopyable { public: - static std::unique_ptr Make(SkStream*); + static std::unique_ptr Make(SkStream*, const ResourceProvider&); + static std::unique_ptr MakeFromFile(const char path[], + const ResourceProvider* = nullptr); ~Animation(); @@ -48,7 +57,9 @@ public: void setShowInval(bool show) { fShowInval = show; } private: - Animation(SkString ver, const SkSize& size, SkScalar fps, const Json::Value&); + Animation(const ResourceProvider&, + SkString ver, const SkSize& size, SkScalar fps, + const Json::Value&); SkString fVersion; SkSize fSize; diff --git a/experimental/sksg/SkSGImage.cpp b/experimental/sksg/SkSGImage.cpp new file mode 100644 index 0000000000..a0c3a759dc --- /dev/null +++ b/experimental/sksg/SkSGImage.cpp @@ -0,0 +1,29 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkSGImage.h" + +#include "SkCanvas.h" +#include "SkImage.h" + +namespace sksg { + +Image::Image(sk_sp image) : fImage(std::move(image)) {} + +void Image::onRender(SkCanvas* canvas) const { + SkPaint paint; + paint.setAntiAlias(fAntiAlias); + paint.setFilterQuality(fQuality); + + canvas->drawImage(fImage, 0, 0); +} + +SkRect Image::onRevalidate(InvalidationController*, const SkMatrix& ctm) { + return SkRect::Make(fImage->bounds()); +} + +} // namespace sksg diff --git a/experimental/sksg/SkSGImage.h b/experimental/sksg/SkSGImage.h new file mode 100644 index 0000000000..7d17a50aaa --- /dev/null +++ b/experimental/sksg/SkSGImage.h @@ -0,0 +1,49 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSGImage_DEFINED +#define SkSGImage_DEFINED + +#include "SkSGRenderNode.h" + +#include "SkFilterQuality.h" + +class SkImage; + +namespace sksg { + +/** + * Concrete rendering node, wrapping an SkImage. + * + */ +class Image final : public RenderNode { +public: + static sk_sp Make(sk_sp image) { + return image ? sk_sp(new Image(std::move(image))) : nullptr; + } + + SG_ATTRIBUTE(Quality , SkFilterQuality, fQuality ) + SG_ATTRIBUTE(AntiAlias, bool , fAntiAlias) + +protected: + explicit Image(sk_sp); + + void onRender(SkCanvas*) const override; + + SkRect onRevalidate(InvalidationController*, const SkMatrix&) override; + +private: + const sk_sp fImage; + SkFilterQuality fQuality = kLow_SkFilterQuality; + bool fAntiAlias = true; + + typedef RenderNode INHERITED; +}; + +} // namespace sksg + +#endif // SkSGImage_DEFINED -- cgit v1.2.3