[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:
Florin Malita 2020-06-18 14:56:14 -04:00 committed by Skia Commit-Bot
parent 3711c6603e
commit c217f61764
11 changed files with 361 additions and 16 deletions

View File

@ -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?

View File

@ -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",

View File

@ -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);

View 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

View 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

View 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

View File

@ -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;

View File

@ -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++;

View File

@ -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[]);

View File

@ -35,6 +35,7 @@ public:
void clear();
protected:
Group();
explicit Group(std::vector<sk_sp<RenderNode>>);
~Group() override;

View File

@ -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) {