[skrive] Start parsing the node hierarchy
TBR= Change-Id: I601ad831e69fd26ac8a0fe1f90ce2e9588a7f912 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/297056 Commit-Queue: Florin Malita <fmalita@chromium.org> Commit-Queue: Florin Malita <fmalita@google.com> Reviewed-by: Florin Malita <fmalita@chromium.org>
This commit is contained in:
parent
3711c6603e
commit
c217f61764
@ -8,9 +8,11 @@
|
||||
#ifndef SkRive_DEFINED
|
||||
#define SkRive_DEFINED
|
||||
|
||||
#include "include/core/SkBlendMode.h"
|
||||
#include "include/core/SkM44.h"
|
||||
#include "include/core/SkRefCnt.h"
|
||||
#include "include/core/SkString.h"
|
||||
#include "modules/sksg/include/SkSGGroup.h"
|
||||
#include "modules/sksg/include/SkSGRenderNode.h"
|
||||
|
||||
#include <memory>
|
||||
@ -20,6 +22,65 @@ class SkStreamAsset;
|
||||
|
||||
namespace skrive {
|
||||
|
||||
class Node : public sksg::Group {
|
||||
public:
|
||||
SG_ATTRIBUTE(Name , SkString , fName )
|
||||
SG_ATTRIBUTE(Translation , SkV2 , fTranslation )
|
||||
SG_ATTRIBUTE(Scale , SkV2 , fScale )
|
||||
SG_ATTRIBUTE(Rotation , float , fRotation )
|
||||
SG_ATTRIBUTE(Opacity , float , fOpacity )
|
||||
SG_ATTRIBUTE(CollapsedVisibility, bool , fCollapsedVisibility)
|
||||
|
||||
Node() : Node(Type::kNode) {}
|
||||
|
||||
protected:
|
||||
enum class Type : uint32_t {
|
||||
kNode, // base group node
|
||||
};
|
||||
|
||||
explicit Node(Type t) : fType(t) {}
|
||||
|
||||
SkRect onRevalidate(sksg::InvalidationController*, const SkMatrix&) override;
|
||||
|
||||
Type type() const { return fType; }
|
||||
|
||||
private:
|
||||
const Type fType;
|
||||
|
||||
SkString fName;
|
||||
SkV2 fTranslation = {0, 0},
|
||||
fScale = {1, 1};
|
||||
float fRotation = 0,
|
||||
fOpacity = 1;
|
||||
bool fCollapsedVisibility = false;
|
||||
|
||||
using INHERITED = sksg::Group;
|
||||
};
|
||||
|
||||
class Drawable : public Node {
|
||||
public:
|
||||
SG_ATTRIBUTE(DrawOrder, size_t , fDrawOrder)
|
||||
SG_ATTRIBUTE(BlendMode, SkBlendMode, fBlendMode)
|
||||
SG_ATTRIBUTE(IsHidden , bool , fIsHidden )
|
||||
|
||||
private:
|
||||
size_t fDrawOrder = 0;
|
||||
SkBlendMode fBlendMode = SkBlendMode::kSrcOver;
|
||||
bool fIsHidden = false;
|
||||
|
||||
using INHERITED = Node;
|
||||
};
|
||||
|
||||
class Shape final : public Drawable {
|
||||
public:
|
||||
SG_ATTRIBUTE(TransformAffectsStroke, bool, fTransformAffectsStroke)
|
||||
|
||||
private:
|
||||
bool fTransformAffectsStroke = true;
|
||||
|
||||
using INHERITED = Drawable;
|
||||
};
|
||||
|
||||
class Artboard final : public sksg::RenderNode {
|
||||
public:
|
||||
SG_ATTRIBUTE(Name , SkString , fName ) // TODO: non-invalidating attributes?
|
||||
|
@ -11,6 +11,9 @@ skia_skrive_public = [ "$_include/SkRive.h" ]
|
||||
|
||||
skia_skrive_sources = [
|
||||
"$_src/Artboard.cpp",
|
||||
"$_src/Drawable.cpp",
|
||||
"$_src/Node.cpp",
|
||||
"$_src/Shape.cpp",
|
||||
"$_src/SkRive.cpp",
|
||||
"$_src/reader/BinaryReader.cpp",
|
||||
"$_src/reader/JsonReader.cpp",
|
||||
|
@ -10,10 +10,60 @@
|
||||
#include "experimental/skrive/src/reader/StreamReader.h"
|
||||
#include "include/core/SkCanvas.h"
|
||||
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
namespace skrive {
|
||||
|
||||
namespace internal {
|
||||
|
||||
template <typename T>
|
||||
size_t parse_node(StreamReader*, T*);
|
||||
|
||||
template <typename T>
|
||||
std::tuple<sk_sp<Node>, size_t> make_from_stream(StreamReader* sr) {
|
||||
auto node = sk_make_sp<T>();
|
||||
const auto parent_index = parse_node<T>(sr, node.get());
|
||||
|
||||
return std::make_tuple(std::move(node), parent_index);
|
||||
}
|
||||
|
||||
std::tuple<sk_sp<Node>, size_t> parse_component(StreamReader* sr) {
|
||||
StreamReader::AutoBlock block(sr);
|
||||
switch (block.type()) {
|
||||
case StreamReader::BlockType::kActorNode : return make_from_stream<Node >(sr);
|
||||
case StreamReader::BlockType::kActorShape: return make_from_stream<Shape>(sr);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
SkDebugf("!! unsupported node type: %d\n", block.type());
|
||||
return {nullptr, 0};
|
||||
}
|
||||
|
||||
sk_sp<Node> parse_components(StreamReader* sr) {
|
||||
const auto count = sr->readLength16();
|
||||
|
||||
std::vector<sk_sp<Node>> nodes;
|
||||
nodes.reserve(count);
|
||||
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
auto [ node, parent_index ] = parse_component(sr);
|
||||
|
||||
if (node && parent_index < i && nodes[parent_index]) {
|
||||
nodes[parent_index]->addChild(node);
|
||||
}
|
||||
|
||||
nodes.push_back(std::move(node));
|
||||
}
|
||||
|
||||
SkDebugf(".. parsed %zu nodes\n", nodes.size());
|
||||
|
||||
return count > 0
|
||||
? std::move(nodes[0])
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
sk_sp<Artboard> parse_artboard(StreamReader* sr) {
|
||||
auto ab = sk_make_sp<Artboard>();
|
||||
|
||||
@ -25,6 +75,22 @@ sk_sp<Artboard> parse_artboard(StreamReader* sr) {
|
||||
ab->setClipContents(sr->readBool ("clipContents"));
|
||||
ab->setColor (sr->readColor ("color" ));
|
||||
|
||||
for (;;) {
|
||||
StreamReader::AutoBlock block(sr);
|
||||
if (block.type() == StreamReader::BlockType::kEoB) {
|
||||
break;
|
||||
}
|
||||
|
||||
switch (block.type()) {
|
||||
case StreamReader::BlockType::kComponents:
|
||||
parse_components(sr);
|
||||
break;
|
||||
default:
|
||||
SkDebugf("!! Unsupported block type: %d\n", block.type());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SkDebugf(".. parsed artboard \"%s\" [%f x %f]\n",
|
||||
ab->getName().c_str(), ab->getSize().x, ab->getSize().y);
|
||||
|
||||
|
32
experimental/skrive/src/Drawable.cpp
Normal file
32
experimental/skrive/src/Drawable.cpp
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2020 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "experimental/skrive/include/SkRive.h"
|
||||
|
||||
#include "experimental/skrive/src/reader/StreamReader.h"
|
||||
|
||||
namespace skrive::internal {
|
||||
template <typename T>
|
||||
size_t parse_node(StreamReader*, T*);
|
||||
|
||||
template <>
|
||||
size_t parse_node<Drawable>(StreamReader* sr, Drawable* node) {
|
||||
const auto parent_index = parse_node<Node>(sr, node);
|
||||
|
||||
node->setIsHidden(!sr->readBool("isVisible"));
|
||||
|
||||
const auto bm = sr->readUInt8("blendMode");
|
||||
if (bm <= static_cast<uint8_t>(SkBlendMode::kLastMode)) {
|
||||
node->setBlendMode(static_cast<SkBlendMode>(bm));
|
||||
}
|
||||
|
||||
node->setDrawOrder(sr->readUInt16("drawOrder"));
|
||||
|
||||
return parent_index;
|
||||
}
|
||||
|
||||
} // namespace skrive::internal
|
60
experimental/skrive/src/Node.cpp
Normal file
60
experimental/skrive/src/Node.cpp
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2020 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "experimental/skrive/include/SkRive.h"
|
||||
|
||||
#include "experimental/skrive/src/reader/StreamReader.h"
|
||||
|
||||
#include <tuple>
|
||||
|
||||
namespace skrive {
|
||||
namespace internal {
|
||||
|
||||
template <typename T>
|
||||
size_t parse_node(StreamReader*, T*);
|
||||
|
||||
template <>
|
||||
size_t parse_node<Node>(StreamReader* sr, Node* node) {
|
||||
node->setName(sr->readString("name"));
|
||||
const auto parent = sr->readUInt16("parent");
|
||||
|
||||
node->setTranslation(sr->readV2("translation"));
|
||||
node->setRotation(sr->readFloat("rotation"));
|
||||
node->setScale(sr->readV2("scale"));
|
||||
node->setOpacity(sr->readFloat("opacity"));
|
||||
node->setCollapsedVisibility(sr->readBool("isCollapsed"));
|
||||
|
||||
SkDebugf(".. '%s' -> %d\n", node->getName().c_str(), parent);
|
||||
|
||||
if (sr->openArray("clips")) {
|
||||
const auto count = sr->readLength8();
|
||||
|
||||
SkDebugf(".. %d clips\n", count);
|
||||
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
if (sr->openObject("clip")) {
|
||||
/*const auto clip_id =*/ sr->readUInt16("node");
|
||||
/*const auto intersect =*/ sr->readBool("intersect");
|
||||
|
||||
// TODO: actually use clips
|
||||
sr->closeObject();
|
||||
}
|
||||
}
|
||||
|
||||
sr->closeArray();
|
||||
}
|
||||
|
||||
return parent;
|
||||
}
|
||||
|
||||
} // namespace skrive
|
||||
|
||||
SkRect Node::onRevalidate(sksg::InvalidationController* ic, const SkMatrix& ctm) {
|
||||
return this->INHERITED::onRevalidate(ic, ctm);
|
||||
}
|
||||
|
||||
} // namespace internal
|
25
experimental/skrive/src/Shape.cpp
Normal file
25
experimental/skrive/src/Shape.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2020 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "experimental/skrive/include/SkRive.h"
|
||||
|
||||
#include "experimental/skrive/src/reader/StreamReader.h"
|
||||
|
||||
namespace skrive::internal {
|
||||
template <typename T>
|
||||
size_t parse_node(StreamReader*, T*);
|
||||
|
||||
template <>
|
||||
size_t parse_node<Shape>(StreamReader* sr, Shape* node) {
|
||||
const auto parent_index = parse_node<Drawable>(sr, node);
|
||||
|
||||
node->setTransformAffectsStroke(sr->readBool("transformAffectsStroke"));
|
||||
|
||||
return parent_index;
|
||||
}
|
||||
|
||||
} // namespace skrive::internal
|
@ -44,6 +44,14 @@ private:
|
||||
: 0.0f;
|
||||
}
|
||||
|
||||
uint8_t readUInt8(const char[]) override {
|
||||
uint8_t v;
|
||||
|
||||
return validateSize(sizeof(v)) && fStream->readU8(&v)
|
||||
? v
|
||||
: 0;
|
||||
}
|
||||
|
||||
uint16_t readUInt16(const char[]) override {
|
||||
uint16_t v;
|
||||
|
||||
@ -80,10 +88,20 @@ private:
|
||||
return fStream->read(dst, count * sizeof(float)) / sizeof(float);
|
||||
}
|
||||
|
||||
uint8_t readLength8() override {
|
||||
return this->readUInt8(nullptr);
|
||||
}
|
||||
|
||||
uint16_t readLength16() override {
|
||||
return this->readUInt16(nullptr);
|
||||
}
|
||||
|
||||
// nops
|
||||
bool openArray(const char[]) override { return true; }
|
||||
void closeArray() override {}
|
||||
bool openObject(const char[]) override { return true; }
|
||||
void closeObject() override {}
|
||||
|
||||
BlockType openBlock() override {
|
||||
uint8_t block_type;
|
||||
uint32_t block_size;
|
||||
|
@ -21,10 +21,20 @@ StreamReader::BlockType block_type(const char* type_name) {
|
||||
const char* name;
|
||||
StreamReader::BlockType block_type;
|
||||
} gTypeMap[] = {
|
||||
{"artboard" , StreamReader::BlockType::kActorArtboard },
|
||||
{"artboards", StreamReader::BlockType::kArtboards },
|
||||
{"node" , StreamReader::BlockType::kActorNode },
|
||||
{"nodes" , StreamReader::BlockType::kComponents },
|
||||
{"artboard" , StreamReader::BlockType::kActorArtboard },
|
||||
{"artboards" , StreamReader::BlockType::kArtboards },
|
||||
{"colorFill" , StreamReader::BlockType::kColorFill },
|
||||
{"colorStroke" , StreamReader::BlockType::kColorStroke },
|
||||
{"ellipse" , StreamReader::BlockType::kActorEllipse },
|
||||
{"gradientFill" , StreamReader::BlockType::kGradientFill },
|
||||
{"gradientStroke" , StreamReader::BlockType::kGradientStroke },
|
||||
{"node" , StreamReader::BlockType::kActorNode },
|
||||
{"nodes" , StreamReader::BlockType::kComponents },
|
||||
{"path" , StreamReader::BlockType::kActorPath },
|
||||
{"radialGradientFill" , StreamReader::BlockType::kRadialGradientFill },
|
||||
{"radialGradientStroke", StreamReader::BlockType::kRadialGradientStroke },
|
||||
{"rectangle" , StreamReader::BlockType::kActorRectangle },
|
||||
{"shape" , StreamReader::BlockType::kActorShape },
|
||||
};
|
||||
|
||||
const TypeMapEntry key = { type_name, StreamReader::BlockType::kUnknown };
|
||||
@ -53,12 +63,19 @@ public:
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
const T* readProp(const char label[]) const {
|
||||
const auto* current_container = fContextStack.back().fContainer;
|
||||
const T* readProp(const char label[]) {
|
||||
auto& ctx = fContextStack.back();
|
||||
|
||||
return current_container->is<skjson::ObjectValue>()
|
||||
? static_cast<const T*>(current_container->as<skjson::ObjectValue>()[label])
|
||||
: nullptr;
|
||||
if (ctx.fContainer->is<skjson::ObjectValue>()) {
|
||||
return static_cast<const T*>(ctx.fContainer->as<skjson::ObjectValue>()[label]);
|
||||
}
|
||||
|
||||
const skjson::ArrayValue* jarr = *ctx.fContainer;
|
||||
SkASSERT(jarr);
|
||||
|
||||
return ctx.fMemberIndex < jarr->size()
|
||||
? static_cast<const T*>((*jarr)[ctx.fMemberIndex++])
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
bool readBool(const char label[]) override {
|
||||
@ -73,6 +90,10 @@ private:
|
||||
return jnum ? static_cast<float>(**jnum) : 0.0f;
|
||||
}
|
||||
|
||||
uint8_t readUInt8(const char label[]) override {
|
||||
return static_cast<uint8_t>(this->readUInt32(label));
|
||||
}
|
||||
|
||||
uint16_t readUInt16(const char label[]) override {
|
||||
return static_cast<uint16_t>(this->readUInt32(label));
|
||||
}
|
||||
@ -106,6 +127,10 @@ private:
|
||||
return count;
|
||||
}
|
||||
|
||||
uint8_t readLength8() override {
|
||||
return SkToU8(this->currentLength());
|
||||
}
|
||||
|
||||
uint16_t readLength16() override {
|
||||
return SkToU16(this->currentLength());
|
||||
}
|
||||
@ -117,6 +142,36 @@ private:
|
||||
: ctx.fContainer->as<skjson:: ArrayValue>().size();
|
||||
}
|
||||
|
||||
bool openArray(const char label[]) override {
|
||||
const auto* jarr = this->readProp<skjson::ArrayValue>(label);
|
||||
if (!jarr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
fContextStack.push_back({jarr, 0});
|
||||
return true;
|
||||
}
|
||||
|
||||
void closeArray() override {
|
||||
SkASSERT(fContextStack.back().fContainer->is<skjson::ArrayValue>());
|
||||
fContextStack.pop_back();
|
||||
}
|
||||
|
||||
bool openObject(const char label[]) override {
|
||||
const auto* jobj = this->readProp<skjson::ObjectValue>(label);
|
||||
if (!jobj) {
|
||||
return false;
|
||||
}
|
||||
|
||||
fContextStack.push_back({jobj, 0});
|
||||
return true;
|
||||
}
|
||||
|
||||
void closeObject() override {
|
||||
SkASSERT(fContextStack.back().fContainer->is<skjson::ObjectValue>());
|
||||
fContextStack.pop_back();
|
||||
}
|
||||
|
||||
// "Blocks" map to either objects or arrays. For object containers, the block type is encoded
|
||||
// as the key; for array containers, the type is an explicit "type" property *inside* the block
|
||||
// entry - which must be an object in this case.
|
||||
@ -136,8 +191,11 @@ private:
|
||||
while (ctx.fMemberIndex < container.size()) {
|
||||
const auto& m = container[ctx.fMemberIndex];
|
||||
if (m.fValue.is<skjson::ObjectValue>() || m.fValue.is<skjson::ArrayValue>()) {
|
||||
fContextStack.push_back({&m.fValue, 0});
|
||||
return block_type(m.fKey.begin());
|
||||
const auto btype = block_type(m.fKey.begin());
|
||||
if (btype != BlockType::kUnknown) {
|
||||
fContextStack.push_back({&m.fValue, 0});
|
||||
return btype;
|
||||
}
|
||||
}
|
||||
|
||||
ctx.fMemberIndex++;
|
||||
|
@ -27,26 +27,45 @@ public:
|
||||
static std::unique_ptr<StreamReader> Make(const sk_sp<SkData>&);
|
||||
|
||||
enum class BlockType : uint8_t {
|
||||
kUnknown = 0,
|
||||
kComponents = 1,
|
||||
kActorNode = 2,
|
||||
kUnknown = 0,
|
||||
kComponents = 1,
|
||||
kActorNode = 2,
|
||||
|
||||
kActorArtboard = 114,
|
||||
kArtboards = 115,
|
||||
kActorShape = 100,
|
||||
kActorPath = 101,
|
||||
kColorFill = 102,
|
||||
kColorStroke = 103,
|
||||
kGradientFill = 104,
|
||||
kGradientStroke = 105,
|
||||
kRadialGradientFill = 106,
|
||||
kRadialGradientStroke = 107,
|
||||
kActorEllipse = 108,
|
||||
kActorRectangle = 109,
|
||||
kActorArtboard = 114,
|
||||
kArtboards = 115,
|
||||
|
||||
// End-of-block marker
|
||||
kEoB = 0xff,
|
||||
};
|
||||
|
||||
// Sequential block API
|
||||
virtual BlockType openBlock() = 0;
|
||||
virtual void closeBlock() = 0;
|
||||
|
||||
// Keyed API
|
||||
virtual bool openArray(const char label[]) = 0;
|
||||
virtual void closeArray() = 0;
|
||||
virtual bool openObject(const char label[]) = 0;
|
||||
virtual void closeObject() = 0;
|
||||
|
||||
virtual bool readBool (const char label[]) = 0;
|
||||
virtual float readFloat (const char label[]) = 0;
|
||||
virtual uint8_t readUInt8 (const char label[]) = 0;
|
||||
virtual uint16_t readUInt16(const char label[]) = 0;
|
||||
virtual uint32_t readUInt32(const char label[]) = 0;
|
||||
virtual SkString readString(const char label[]) = 0;
|
||||
|
||||
virtual uint8_t readLength8 () = 0;
|
||||
virtual uint16_t readLength16() = 0;
|
||||
|
||||
SkColor4f readColor(const char label[]);
|
||||
|
@ -35,6 +35,7 @@ public:
|
||||
void clear();
|
||||
|
||||
protected:
|
||||
Group();
|
||||
explicit Group(std::vector<sk_sp<RenderNode>>);
|
||||
~Group() override;
|
||||
|
||||
|
@ -13,6 +13,8 @@
|
||||
|
||||
namespace sksg {
|
||||
|
||||
Group::Group() = default;
|
||||
|
||||
Group::Group(std::vector<sk_sp<RenderNode>> children)
|
||||
: fChildren(std::move(children)) {
|
||||
for (const auto& child : fChildren) {
|
||||
|
Loading…
Reference in New Issue
Block a user