[skottie] Parser cleanup
Consolidate parsing utils into their own CU. TBR= Change-Id: Idbf6db5220135ba91df6ebefce3a241c6ec4af15 Reviewed-on: https://skia-review.googlesource.com/99721 Reviewed-by: Florin Malita <fmalita@chromium.org> Commit-Queue: Florin Malita <fmalita@chromium.org>
This commit is contained in:
parent
ca96da7ad8
commit
cf8ed52895
1
BUILD.gn
1
BUILD.gn
@ -1327,6 +1327,7 @@ if (skia_enable_tools) {
|
||||
sources = [
|
||||
"experimental/skottie/Skottie.cpp",
|
||||
"experimental/skottie/SkottieAnimator.cpp",
|
||||
"experimental/skottie/SkottieParser.cpp",
|
||||
"experimental/skottie/SkottieProperties.cpp",
|
||||
]
|
||||
deps = [
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
#include "SkCanvas.h"
|
||||
#include "SkottieAnimator.h"
|
||||
#include "SkottiePriv.h"
|
||||
#include "SkottieParser.h"
|
||||
#include "SkottieProperties.h"
|
||||
#include "SkData.h"
|
||||
#include "SkImage.h"
|
||||
@ -46,6 +46,8 @@
|
||||
|
||||
namespace skottie {
|
||||
|
||||
#define LOG SkDebugf
|
||||
|
||||
namespace {
|
||||
|
||||
using AssetMap = SkTHashMap<SkString, const Json::Value*>;
|
||||
@ -75,9 +77,9 @@ bool BindProperty(const Json::Value& jprop, AttachContext* ctx,
|
||||
|
||||
// Older Json versions don't have an "a" animation marker.
|
||||
// For those, we attempt to parse both ways.
|
||||
if (jpropA.isNull() || !ParseBool(jpropA, "false")) {
|
||||
if (!ParseDefault(jpropA, false)) {
|
||||
T val;
|
||||
if (ValueTraits<T>::Parse(jpropK, &val)) {
|
||||
if (Parse<T>(jpropK, &val)) {
|
||||
// Static property.
|
||||
apply(val);
|
||||
return true;
|
||||
@ -154,8 +156,8 @@ sk_sp<sksg::RenderNode> AttachOpacity(const Json::Value& jtransform, AttachConte
|
||||
// nodes for the extremely common case of static opaciy == 100.
|
||||
const auto& opacity = jtransform["o"];
|
||||
if (opacity.isObject() &&
|
||||
!ParseBool(opacity["a"], true) &&
|
||||
ParseScalar(opacity["k"], -1) == 100) {
|
||||
!ParseDefault(opacity["a"], true) &&
|
||||
ParseDefault(opacity["k"], -1) == 100) {
|
||||
// Ignoring static full opacity.
|
||||
return childNode;
|
||||
}
|
||||
@ -248,7 +250,7 @@ sk_sp<sksg::GeometryNode> AttachPolystarGeometry(const Json::Value& jstar, Attac
|
||||
CompositePolyStar::Type::kPoly, // "sy": 2
|
||||
};
|
||||
|
||||
const auto type = ParseInt(jstar["sy"], 0) - 1;
|
||||
const auto type = ParseDefault(jstar["sy"], 0) - 1;
|
||||
if (type < 0 || type >= SkTo<int>(SK_ARRAY_COUNT(gTypes))) {
|
||||
LogFail(jstar, "Unknown polystar type");
|
||||
return nullptr;
|
||||
@ -308,14 +310,14 @@ sk_sp<sksg::Gradient> AttachGradient(const Json::Value& obj, AttachContext* ctx)
|
||||
if (!stops.isObject())
|
||||
return nullptr;
|
||||
|
||||
const auto stopCount = ParseInt(stops["p"], -1);
|
||||
const auto stopCount = ParseDefault(stops["p"], -1);
|
||||
if (stopCount < 0)
|
||||
return nullptr;
|
||||
|
||||
sk_sp<sksg::Gradient> gradient_node;
|
||||
sk_sp<CompositeGradient> composite;
|
||||
|
||||
if (ParseInt(obj["t"], 1) == 1) {
|
||||
if (ParseDefault(obj["t"], 1) == 1) {
|
||||
auto linear_node = sksg::LinearGradient::Make();
|
||||
composite = sk_make_sp<CompositeLinearGradient>(linear_node, stopCount);
|
||||
gradient_node = std::move(linear_node);
|
||||
@ -374,14 +376,14 @@ sk_sp<sksg::PaintNode> AttachStroke(const Json::Value& jstroke, AttachContext* c
|
||||
if (!width_attached)
|
||||
return nullptr;
|
||||
|
||||
stroke_node->setStrokeMiter(ParseScalar(jstroke["ml"], 4));
|
||||
stroke_node->setStrokeMiter(ParseDefault(jstroke["ml"], 4.0f));
|
||||
|
||||
static constexpr SkPaint::Join gJoins[] = {
|
||||
SkPaint::kMiter_Join,
|
||||
SkPaint::kRound_Join,
|
||||
SkPaint::kBevel_Join,
|
||||
};
|
||||
stroke_node->setStrokeJoin(gJoins[SkTPin<int>(ParseInt(jstroke["lj"], 1) - 1,
|
||||
stroke_node->setStrokeJoin(gJoins[SkTPin<int>(ParseDefault(jstroke["lj"], 1) - 1,
|
||||
0, SK_ARRAY_COUNT(gJoins) - 1)]);
|
||||
|
||||
static constexpr SkPaint::Cap gCaps[] = {
|
||||
@ -389,7 +391,7 @@ sk_sp<sksg::PaintNode> AttachStroke(const Json::Value& jstroke, AttachContext* c
|
||||
SkPaint::kRound_Cap,
|
||||
SkPaint::kSquare_Cap,
|
||||
};
|
||||
stroke_node->setStrokeCap(gCaps[SkTPin<int>(ParseInt(jstroke["lc"], 1) - 1,
|
||||
stroke_node->setStrokeCap(gCaps[SkTPin<int>(ParseDefault(jstroke["lc"], 1) - 1,
|
||||
0, SK_ARRAY_COUNT(gCaps) - 1)]);
|
||||
|
||||
return stroke_node;
|
||||
@ -431,7 +433,7 @@ std::vector<sk_sp<sksg::GeometryNode>> AttachMergeGeometryEffect(
|
||||
sksg::Merge::Mode::kXOR , // "mm": 5
|
||||
};
|
||||
|
||||
const auto mode = gModes[SkTPin<int>(ParseInt(jmerge["mm"], 1) - 1,
|
||||
const auto mode = gModes[SkTPin<int>(ParseDefault(jmerge["mm"], 1) - 1,
|
||||
0, SK_ARRAY_COUNT(gModes) - 1)];
|
||||
merged.push_back(sksg::Merge::Make(std::move(geos), mode));
|
||||
|
||||
@ -448,7 +450,7 @@ std::vector<sk_sp<sksg::GeometryNode>> AttachTrimGeometryEffect(
|
||||
kSeparate, // "m": 2
|
||||
} gModes[] = { Mode::kMerged, Mode::kSeparate };
|
||||
|
||||
const auto mode = gModes[SkTPin<int>(ParseInt(jtrim["m"], 1) - 1,
|
||||
const auto mode = gModes[SkTPin<int>(ParseDefault(jtrim["m"], 1) - 1,
|
||||
0, SK_ARRAY_COUNT(gModes) - 1)];
|
||||
|
||||
std::vector<sk_sp<sksg::GeometryNode>> inputs;
|
||||
@ -714,8 +716,8 @@ sk_sp<sksg::RenderNode> AttachShape(const Json::Value& jshape, AttachShapeContex
|
||||
sk_sp<sksg::RenderNode> AttachCompLayer(const Json::Value& layer, AttachContext* ctx) {
|
||||
SkASSERT(layer.isObject());
|
||||
|
||||
auto refId = ParseString(layer["refId"], "");
|
||||
if (refId.isEmpty()) {
|
||||
SkString refId;
|
||||
if (!Parse(layer["refId"], &refId) || refId.isEmpty()) {
|
||||
LOG("!! Comp layer missing refId\n");
|
||||
return nullptr;
|
||||
}
|
||||
@ -733,9 +735,9 @@ sk_sp<sksg::RenderNode> AttachCompLayer(const Json::Value& layer, AttachContext*
|
||||
sk_sp<sksg::RenderNode> AttachSolidLayer(const Json::Value& jlayer, AttachContext*) {
|
||||
SkASSERT(jlayer.isObject());
|
||||
|
||||
const auto size = SkSize::Make(ParseScalar(jlayer["sw"], -1),
|
||||
ParseScalar(jlayer["sh"], -1));
|
||||
const auto hex = ParseString(jlayer["sc"], "");
|
||||
const auto size = SkSize::Make(ParseDefault(jlayer["sw"], 0.0f),
|
||||
ParseDefault(jlayer["sh"], 0.0f));
|
||||
const auto hex = ParseDefault(jlayer["sc"], SkString());
|
||||
uint32_t c;
|
||||
if (size.isEmpty() ||
|
||||
!hex.startsWith("#") ||
|
||||
@ -753,8 +755,8 @@ sk_sp<sksg::RenderNode> AttachSolidLayer(const Json::Value& jlayer, AttachContex
|
||||
sk_sp<sksg::RenderNode> AttachImageAsset(const Json::Value& jimage, AttachContext* ctx) {
|
||||
SkASSERT(jimage.isObject());
|
||||
|
||||
const auto name = ParseString(jimage["p"], ""),
|
||||
path = ParseString(jimage["u"], "");
|
||||
const auto name = ParseDefault(jimage["p"], SkString()),
|
||||
path = ParseDefault(jimage["u"], SkString());
|
||||
if (name.isEmpty())
|
||||
return nullptr;
|
||||
|
||||
@ -774,8 +776,8 @@ sk_sp<sksg::RenderNode> AttachImageAsset(const Json::Value& jimage, AttachContex
|
||||
sk_sp<sksg::RenderNode> AttachImageLayer(const Json::Value& layer, AttachContext* ctx) {
|
||||
SkASSERT(layer.isObject());
|
||||
|
||||
auto refId = ParseString(layer["refId"], "");
|
||||
if (refId.isEmpty()) {
|
||||
SkString refId;
|
||||
if (!Parse(layer["refId"], &refId) || refId.isEmpty()) {
|
||||
LOG("!! Image layer missing refId\n");
|
||||
return nullptr;
|
||||
}
|
||||
@ -800,8 +802,6 @@ sk_sp<sksg::RenderNode> AttachNullLayer(const Json::Value& layer, AttachContext*
|
||||
sk_sp<sksg::RenderNode> AttachShapeLayer(const Json::Value& layer, AttachContext* ctx) {
|
||||
SkASSERT(layer.isObject());
|
||||
|
||||
LOG("** Attaching shape layer ind: %d\n", ParseInt(layer["ind"], 0));
|
||||
|
||||
std::vector<sk_sp<sksg::GeometryNode>> geometryStack;
|
||||
std::vector<GeometryEffectRec> geometryEffectStack;
|
||||
AttachShapeContext shapeCtx(ctx, &geometryStack, &geometryEffectStack, ctx->fAnimators.size());
|
||||
@ -851,7 +851,7 @@ struct AttachLayerContext {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ParseInt(l["ind"], -1) == index) {
|
||||
if (ParseDefault(l["ind"], -1) == index) {
|
||||
fLayerIndexCache.insert(std::make_pair(index, &l));
|
||||
return &l;
|
||||
}
|
||||
@ -868,7 +868,7 @@ struct AttachLayerContext {
|
||||
return cached->second;
|
||||
}
|
||||
|
||||
const auto* parentLayer = this->findLayer(ParseInt(jlayer["parent"], -1));
|
||||
const auto* parentLayer = this->findLayer(ParseDefault(jlayer["parent"], -1));
|
||||
|
||||
// TODO: cycle detection?
|
||||
auto parentMatrix = (parentLayer && parentLayer != &jlayer)
|
||||
@ -907,7 +907,7 @@ sk_sp<sksg::RenderNode> AttachMask(const Json::Value& jmask,
|
||||
if (!m.isObject())
|
||||
continue;
|
||||
|
||||
const auto inverted = ParseBool(m["inv"], false);
|
||||
const auto inverted = ParseDefault(m["inv"], false);
|
||||
// TODO
|
||||
if (inverted) {
|
||||
LogFail(m, "Unsupported inverse mask");
|
||||
@ -920,9 +920,12 @@ sk_sp<sksg::RenderNode> AttachMask(const Json::Value& jmask,
|
||||
continue;
|
||||
}
|
||||
|
||||
auto mode = ParseString(m["mode"], "");
|
||||
if (mode.size() != 1 || !strcmp(mode.c_str(), "n")) // "None" masks have no effect.
|
||||
SkString mode;
|
||||
if (!Parse(m["mode"], &mode) ||
|
||||
mode.size() != 1 ||
|
||||
!strcmp(mode.c_str(), "n")) { // "None" masks have no effect.
|
||||
continue;
|
||||
}
|
||||
|
||||
auto mask_paint = sksg::Color::Make(SK_ColorBLACK);
|
||||
mask_paint->setBlendMode(MaskBlendMode(mode.c_str()[0]));
|
||||
@ -952,7 +955,7 @@ sk_sp<sksg::RenderNode> AttachLayer(const Json::Value& jlayer,
|
||||
AttachTextLayer, // 'ty': 5
|
||||
};
|
||||
|
||||
int type = ParseInt(jlayer["ty"], -1);
|
||||
int type = ParseDefault(jlayer["ty"], -1);
|
||||
if (type < 0 || type >= SkTo<int>(SK_ARRAY_COUNT(gLayerAttachers))) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -989,15 +992,15 @@ sk_sp<sksg::RenderNode> AttachLayer(const Json::Value& jlayer,
|
||||
};
|
||||
|
||||
auto layerControl = sksg::OpacityEffect::Make(std::move(layer));
|
||||
const auto in = ParseScalar(jlayer["ip"], 0),
|
||||
out = ParseScalar(jlayer["op"], in);
|
||||
const auto in = ParseDefault(jlayer["ip"], 0.0f),
|
||||
out = ParseDefault(jlayer["op"], in);
|
||||
|
||||
if (in >= out || ! layerControl)
|
||||
return nullptr;
|
||||
|
||||
layerCtx->fCtx->fAnimators.push_back(skstd::make_unique<Activator>(layerControl, in, out));
|
||||
|
||||
if (ParseBool(jlayer["td"], false)) {
|
||||
if (ParseDefault(jlayer["td"], false)) {
|
||||
// This layer is a matte. We apply it as a mask to the next layer.
|
||||
layerCtx->fCurrentMatte = std::move(layerControl);
|
||||
return nullptr;
|
||||
@ -1039,7 +1042,7 @@ sk_sp<sksg::RenderNode> AttachComposition(const Json::Value& comp, AttachContext
|
||||
}
|
||||
|
||||
LOG("** Attached composition '%s': %d layers.\n",
|
||||
ParseString(comp["id"], "").c_str(), layers.count());
|
||||
ParseDefault(comp["id"], SkString()).c_str(), layers.count());
|
||||
|
||||
return comp_group;
|
||||
}
|
||||
@ -1070,9 +1073,10 @@ std::unique_ptr<Animation> Animation::Make(SkStream* stream, const ResourceProvi
|
||||
}
|
||||
}
|
||||
|
||||
const auto version = ParseString(json["v"], "");
|
||||
const auto size = SkSize::Make(ParseScalar(json["w"], -1), ParseScalar(json["h"], -1));
|
||||
const auto fps = ParseScalar(json["fr"], -1);
|
||||
const auto version = ParseDefault(json["v"], SkString());
|
||||
const auto size = SkSize::Make(ParseDefault(json["w"], 0.0f),
|
||||
ParseDefault(json["h"], 0.0f));
|
||||
const auto fps = ParseDefault(json["fr"], -1.0f);
|
||||
|
||||
if (size.isEmpty() || version.isEmpty() || fps < 0) {
|
||||
LOG("!! invalid animation params (version: %s, size: [%f %f], frame rate: %f)",
|
||||
@ -1114,8 +1118,8 @@ Animation::Animation(const ResourceProvider& resources,
|
||||
: fVersion(std::move(version))
|
||||
, fSize(size)
|
||||
, fFrameRate(fps)
|
||||
, fInPoint(ParseScalar(json["ip"], 0))
|
||||
, fOutPoint(SkTMax(ParseScalar(json["op"], SK_ScalarMax), fInPoint)) {
|
||||
, fInPoint(ParseDefault(json["ip"], 0.0f))
|
||||
, fOutPoint(SkTMax(ParseDefault(json["op"], SK_ScalarMax), fInPoint)) {
|
||||
|
||||
AssetMap assets;
|
||||
for (const auto& asset : json["assets"]) {
|
||||
@ -1123,7 +1127,7 @@ Animation::Animation(const ResourceProvider& resources,
|
||||
continue;
|
||||
}
|
||||
|
||||
assets.set(ParseString(asset["id"], ""), &asset);
|
||||
assets.set(ParseDefault(asset["id"], SkString()), &asset);
|
||||
}
|
||||
|
||||
sksg::Scene::AnimatorList animators;
|
||||
|
@ -16,31 +16,19 @@ SkScalar lerp_scalar(float v0, float v1, float t) {
|
||||
return v0 * (1 - t) + v1 * t;
|
||||
}
|
||||
|
||||
static inline SkPoint ParsePoint(const Json::Value& v, const SkPoint& defaultValue) {
|
||||
if (!v.isObject())
|
||||
return defaultValue;
|
||||
|
||||
const auto& vx = v["x"];
|
||||
const auto& vy = v["y"];
|
||||
|
||||
// Some BM versions seem to store x/y as single-element arrays.
|
||||
return SkPoint::Make(ParseScalar(vx.isArray() ? vx[0] : vx, defaultValue.x()),
|
||||
ParseScalar(vy.isArray() ? vy[0] : vy, defaultValue.y()));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool KeyframeIntervalBase::parse(const Json::Value& k, KeyframeIntervalBase* prev) {
|
||||
SkASSERT(k.isObject());
|
||||
|
||||
fT0 = fT1 = ParseScalar(k["t"], SK_ScalarMin);
|
||||
fT0 = fT1 = ParseDefault(k["t"], SK_ScalarMin);
|
||||
if (fT0 == SK_ScalarMin) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (prev) {
|
||||
if (prev->fT1 >= fT0) {
|
||||
LOG("!! Dropping out-of-order key frame (t: %f < t: %f)\n", fT0, prev->fT1);
|
||||
SkDebugf("!! Dropping out-of-order key frame (t: %f < t: %f)\n", fT0, prev->fT1);
|
||||
return false;
|
||||
}
|
||||
// Back-fill t1 in prev interval. Note: we do this even if we end up discarding
|
||||
@ -48,14 +36,14 @@ bool KeyframeIntervalBase::parse(const Json::Value& k, KeyframeIntervalBase* pre
|
||||
prev->fT1 = fT0;
|
||||
}
|
||||
|
||||
fHold = ParseBool(k["h"], false);
|
||||
fHold = ParseDefault(k["h"], false);
|
||||
|
||||
if (!fHold) {
|
||||
// default is linear lerp
|
||||
static constexpr SkPoint kDefaultC0 = { 0, 0 },
|
||||
kDefaultC1 = { 1, 1 };
|
||||
const auto c0 = ParsePoint(k["i"], kDefaultC0),
|
||||
c1 = ParsePoint(k["o"], kDefaultC1);
|
||||
const auto c0 = ParseDefault(k["i"], kDefaultC0),
|
||||
c1 = ParseDefault(k["o"], kDefaultC1);
|
||||
|
||||
if (c0 != kDefaultC0 || c1 != kDefaultC1) {
|
||||
fCubicMap = skstd::make_unique<SkCubicMap>();
|
||||
|
@ -9,8 +9,9 @@
|
||||
#define SkottieAnimator_DEFINED
|
||||
|
||||
#include "SkCubicMap.h"
|
||||
#include "SkJSONCPP.h"
|
||||
#include "SkMakeUnique.h"
|
||||
#include "SkottiePriv.h"
|
||||
#include "SkottieParser.h"
|
||||
#include "SkottieProperties.h"
|
||||
#include "SkSGScene.h"
|
||||
#include "SkTArray.h"
|
||||
@ -62,12 +63,12 @@ public:
|
||||
SkASSERT(k.isObject());
|
||||
|
||||
if (!this->INHERITED::parse(k, prev) ||
|
||||
!ValueTraits<T>::Parse(k["s"], &fV0)) {
|
||||
!Parse<T>(k["s"], &fV0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this->isHold() &&
|
||||
(!ValueTraits<T>::Parse(k["e"], &fV1) ||
|
||||
(!Parse<T>(k["e"], &fV1) ||
|
||||
ValueTraits<T>::Cardinality(fV0) != ValueTraits<T>::Cardinality(fV1))) {
|
||||
return false;
|
||||
}
|
||||
|
160
experimental/skottie/SkottieParser.cpp
Normal file
160
experimental/skottie/SkottieParser.cpp
Normal file
@ -0,0 +1,160 @@
|
||||
/*
|
||||
* 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 "SkottieParser.h"
|
||||
|
||||
#include "SkJSONCPP.h"
|
||||
#include "SkScalar.h"
|
||||
#include "SkPath.h"
|
||||
#include "SkPoint.h"
|
||||
#include "SkString.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace skottie {
|
||||
|
||||
template <>
|
||||
bool Parse<SkScalar>(const Json::Value& jv, SkScalar* v) {
|
||||
// Some versions wrap values as single-element arrays.
|
||||
if (jv.isArray() && jv.size() == 1) {
|
||||
return Parse(jv[0], v);
|
||||
}
|
||||
|
||||
if (jv.isNull() || !jv.isConvertibleTo(Json::realValue))
|
||||
return false;
|
||||
|
||||
*v = jv.asFloat();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool Parse<bool>(const Json::Value& jv, bool* v) {
|
||||
if (jv.isNull() || !jv.isConvertibleTo(Json::booleanValue))
|
||||
return false;
|
||||
|
||||
*v = jv.asBool();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool Parse<int>(const Json::Value& jv, int* v) {
|
||||
if (jv.isNull() || !jv.isConvertibleTo(Json::intValue))
|
||||
return false;
|
||||
|
||||
*v = jv.asInt();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool Parse<SkString>(const Json::Value& jv, SkString* v) {
|
||||
if (jv.isNull() || !jv.isConvertibleTo(Json::stringValue))
|
||||
return false;
|
||||
|
||||
v->set(jv.asCString());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool Parse<SkPoint>(const Json::Value& jv, SkPoint* v) {
|
||||
if (!jv.isObject())
|
||||
return false;
|
||||
|
||||
const auto& jvx = jv["x"],
|
||||
jvy = jv["y"];
|
||||
|
||||
// Some BM versions seem to store x/y as single-element arrays.
|
||||
return Parse(jvx.isArray() ? jvx[0] : jvx, &v->fX)
|
||||
&& Parse(jvy.isArray() ? jvy[0] : jvy, &v->fY);
|
||||
}
|
||||
|
||||
template <>
|
||||
bool Parse<std::vector<float>>(const Json::Value& jv, std::vector<float>* v) {
|
||||
if (!jv.isArray())
|
||||
return false;
|
||||
|
||||
v->resize(jv.size());
|
||||
|
||||
for (Json::ArrayIndex i = 0; i < jv.size(); ++i) {
|
||||
if (!Parse(jv[i], v->data() + i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
bool ParsePointVec(const Json::Value& jv, std::vector<SkPoint>* pts) {
|
||||
if (!jv.isArray())
|
||||
return false;
|
||||
|
||||
pts->clear();
|
||||
pts->reserve(jv.size());
|
||||
|
||||
std::vector<float> vec;
|
||||
for (Json::ArrayIndex i = 0; i < jv.size(); ++i) {
|
||||
if (!Parse(jv[i], &vec) || vec.size() != 2)
|
||||
return false;
|
||||
pts->push_back(SkPoint::Make(vec[0], vec[1]));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
template <>
|
||||
bool Parse<SkPath>(const Json::Value& jv, SkPath* v) {
|
||||
SkASSERT(v->isEmpty());
|
||||
|
||||
// Some versions wrap values as single-element arrays.
|
||||
if (jv.isArray() && jv.size() == 1) {
|
||||
return Parse(jv[0], v);
|
||||
}
|
||||
|
||||
std::vector<SkPoint> inPts, // Cubic Bezier "in" control points, relative to vertices.
|
||||
outPts, // Cubic Bezier "out" control points, relative to vertices.
|
||||
verts; // Cubic Bezier vertices.
|
||||
|
||||
if (!jv.isObject() ||
|
||||
!ParsePointVec(jv["i"], &inPts) ||
|
||||
!ParsePointVec(jv["o"], &outPts) ||
|
||||
!ParsePointVec(jv["v"], &verts) ||
|
||||
inPts.size() != outPts.size() ||
|
||||
inPts.size() != verts.size()) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!verts.empty()) {
|
||||
v->moveTo(verts.front());
|
||||
}
|
||||
|
||||
const auto& addCubic = [&](size_t from, size_t to) {
|
||||
v->cubicTo(verts[from] + outPts[from],
|
||||
verts[to] + inPts[to],
|
||||
verts[to]);
|
||||
};
|
||||
|
||||
for (size_t i = 1; i < verts.size(); ++i) {
|
||||
addCubic(i - 1, i);
|
||||
}
|
||||
|
||||
if (!verts.empty() && ParseDefault(jv["c"], false)) {
|
||||
addCubic(verts.size() - 1, 0);
|
||||
v->close();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // nasmespace skottie
|
28
experimental/skottie/SkottieParser.h
Normal file
28
experimental/skottie/SkottieParser.h
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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 SkottieParser_DEFINED
|
||||
#define SkottieParser_DEFINED
|
||||
|
||||
namespace Json { class Value; }
|
||||
|
||||
namespace skottie {
|
||||
|
||||
template <typename T>
|
||||
bool Parse(const Json::Value&, T*);
|
||||
|
||||
template <typename T>
|
||||
static inline T ParseDefault(const Json::Value& jv, const T& defaultValue) {
|
||||
T v;
|
||||
if (!Parse<T>(jv, &v))
|
||||
v = defaultValue;
|
||||
return v;
|
||||
}
|
||||
|
||||
} // nasmespace skottie
|
||||
|
||||
#endif // SkottieParser_DEFINED
|
@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef SkottiePriv_DEFINED
|
||||
#define SkottiePriv_DEFINED
|
||||
|
||||
#include "SkJSONCPP.h"
|
||||
#include "SkPoint.h"
|
||||
#include "SkScalar.h"
|
||||
#include "SkString.h"
|
||||
|
||||
namespace skottie {
|
||||
|
||||
#define LOG SkDebugf
|
||||
|
||||
static inline SkScalar ParseScalar(const Json::Value& v, SkScalar defaultValue) {
|
||||
return !v.isNull() && v.isConvertibleTo(Json::realValue)
|
||||
? v.asFloat() : defaultValue;
|
||||
}
|
||||
|
||||
static inline SkString ParseString(const Json::Value& v, const char defaultValue[]) {
|
||||
return SkString(!v.isNull() && v.isConvertibleTo(Json::stringValue)
|
||||
? v.asCString() : defaultValue);
|
||||
}
|
||||
|
||||
static inline int ParseInt(const Json::Value& v, int defaultValue) {
|
||||
return !v.isNull() && v.isConvertibleTo(Json::intValue)
|
||||
? v.asInt() : defaultValue;
|
||||
}
|
||||
|
||||
static inline bool ParseBool(const Json::Value& v, bool defaultValue) {
|
||||
return !v.isNull() && v.isConvertibleTo(Json::booleanValue)
|
||||
? v.asBool() : defaultValue;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif // SkottiePriv_DEFINED
|
@ -8,7 +8,7 @@
|
||||
#include "SkottieProperties.h"
|
||||
|
||||
#include "SkColor.h"
|
||||
#include "SkottiePriv.h"
|
||||
#include "SkJSONCPP.h"
|
||||
#include "SkPath.h"
|
||||
#include "SkSGColor.h"
|
||||
#include "SkSGGradient.h"
|
||||
@ -22,26 +22,6 @@ namespace skottie {
|
||||
|
||||
namespace {
|
||||
|
||||
using PointArray = SkSTArray<64, SkPoint, true>;
|
||||
|
||||
bool ParsePoints(const Json::Value& v, PointArray* pts) {
|
||||
if (!v.isArray()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (Json::ArrayIndex i = 0; i < v.size(); ++i) {
|
||||
const auto& pt = v[i];
|
||||
if (!pt.isArray() || pt.size() != 2 ||
|
||||
!pt[0].isConvertibleTo(Json::realValue) ||
|
||||
!pt[1].isConvertibleTo(Json::realValue)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
pts->push_back(SkPoint::Make(ParseScalar(pt[0], 0), ParseScalar(pt[1], 0)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
SkColor VecToColor(const float* v, size_t size) {
|
||||
// best effort to turn this into a color
|
||||
const auto r = size > 0 ? v[0] : 0,
|
||||
@ -57,20 +37,6 @@ SkColor VecToColor(const float* v, size_t size) {
|
||||
|
||||
} // namespace
|
||||
|
||||
template <>
|
||||
bool ValueTraits<ScalarValue>::Parse(const Json::Value& v, ScalarValue* scalar) {
|
||||
// Some files appear to wrap keyframes in arrays for no reason.
|
||||
if (v.isArray() && v.size() == 1) {
|
||||
return Parse(v[0], scalar);
|
||||
}
|
||||
|
||||
if (v.isNull() || !v.isConvertibleTo(Json::realValue))
|
||||
return false;
|
||||
|
||||
*scalar = v.asFloat();
|
||||
return true;
|
||||
}
|
||||
|
||||
template <>
|
||||
size_t ValueTraits<ScalarValue>::Cardinality(const ScalarValue&) {
|
||||
return 1;
|
||||
@ -82,24 +48,6 @@ SkScalar ValueTraits<ScalarValue>::As<SkScalar>(const ScalarValue& v) {
|
||||
return v;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool ValueTraits<VectorValue>::Parse(const Json::Value& v, VectorValue* vec) {
|
||||
SkASSERT(vec->empty());
|
||||
|
||||
if (!v.isArray())
|
||||
return false;
|
||||
|
||||
for (Json::ArrayIndex i = 0; i < v.size(); ++i) {
|
||||
ScalarValue scalar;
|
||||
if (!ValueTraits<ScalarValue>::Parse(v[i], &scalar))
|
||||
return false;
|
||||
|
||||
vec->push_back(std::move(scalar));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <>
|
||||
size_t ValueTraits<VectorValue>::Cardinality(const VectorValue& vec) {
|
||||
return vec.size();
|
||||
@ -127,51 +75,6 @@ SkSize ValueTraits<VectorValue>::As<SkSize>(const VectorValue& vec) {
|
||||
return SkSize::Make(pt.x(), pt.y());
|
||||
}
|
||||
|
||||
template<>
|
||||
bool ValueTraits<ShapeValue>::Parse(const Json::Value& v, ShapeValue* shape) {
|
||||
PointArray inPts, // Cubic Bezier "in" control points, relative to vertices.
|
||||
outPts, // Cubic Bezier "out" control points, relative to vertices.
|
||||
verts; // Cubic Bezier vertices.
|
||||
|
||||
// Some files appear to wrap keyframes in arrays for no reason.
|
||||
if (v.isArray() && v.size() == 1) {
|
||||
return Parse(v[0], shape);
|
||||
}
|
||||
|
||||
if (!v.isObject() ||
|
||||
!ParsePoints(v["i"], &inPts) ||
|
||||
!ParsePoints(v["o"], &outPts) ||
|
||||
!ParsePoints(v["v"], &verts) ||
|
||||
inPts.count() != outPts.count() ||
|
||||
inPts.count() != verts.count()) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
SkASSERT(shape->isEmpty());
|
||||
|
||||
if (!verts.empty()) {
|
||||
shape->moveTo(verts.front());
|
||||
}
|
||||
|
||||
const auto& addCubic = [&](int from, int to) {
|
||||
shape->cubicTo(verts[from] + outPts[from],
|
||||
verts[to] + inPts[to],
|
||||
verts[to]);
|
||||
};
|
||||
|
||||
for (int i = 1; i < verts.count(); ++i) {
|
||||
addCubic(i - 1, i);
|
||||
}
|
||||
|
||||
if (!verts.empty() && ParseBool(v["c"], false)) {
|
||||
addCubic(verts.count() - 1, 0);
|
||||
shape->close();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <>
|
||||
size_t ValueTraits<ShapeValue>::Cardinality(const ShapeValue& path) {
|
||||
return SkTo<size_t>(path.countVerbs());
|
||||
@ -252,7 +155,7 @@ void CompositeGradient::apply() {
|
||||
// |fColorStops| holds |fStopCount| x [ pos, r, g, g ] + ? x [ pos, alpha ]
|
||||
|
||||
if (fColorStops.size() < fStopCount * 4 || ((fColorStops.size() - fStopCount * 4) % 2)) {
|
||||
LOG("!! Invalid gradient stop array size: %zu", fColorStops.size());
|
||||
SkDebugf("!! Invalid gradient stop array size: %zu", fColorStops.size());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,6 @@
|
||||
#include "SkPath.h"
|
||||
#include "SkPoint.h"
|
||||
#include "SkSize.h"
|
||||
#include "SkottiePriv.h"
|
||||
#include "SkRefCnt.h"
|
||||
#include "SkTArray.h"
|
||||
#include "SkTypes.h"
|
||||
@ -31,11 +30,12 @@ class RRect;
|
||||
class RenderNode;;
|
||||
}
|
||||
|
||||
namespace Json { class Value; }
|
||||
|
||||
namespace skottie {
|
||||
|
||||
template <typename T>
|
||||
struct ValueTraits {
|
||||
static bool Parse(const Json::Value&, T*);
|
||||
static size_t Cardinality(const T&);
|
||||
|
||||
template <typename U>
|
||||
|
Loading…
Reference in New Issue
Block a user