1 #pragma once
2 
3 #include <memory>
4 #include <utility>
5 
6 #include <jsi/jsi.h>
7 
8 #include "JsiSkHostObjects.h"
9 #include "JsiSkPathEffect.h"
10 
11 #pragma clang diagnostic push
12 #pragma clang diagnostic ignored "-Wdocumentation"
13 
14 #include "RNSkLog.h"
15 #include "SkPath.h"
16 #include "SkPathOps.h"
17 
18 #pragma clang diagnostic pop
19 
20 namespace RNSkia {
21 
22 namespace jsi = facebook::jsi;
23 
24 class JsiSkPathFactory : public JsiSkHostObject {
25 
26   static const int MOVE = 0;
27   static const int LINE = 1;
28   static const int QUAD = 2;
29   static const int CONIC = 3;
30   static const int CUBIC = 4;
31   static const int CLOSE = 5;
32 
33 public:
JSI_HOST_FUNCTION(Make)34   JSI_HOST_FUNCTION(Make) {
35     return jsi::Object::createFromHostObject(
36         runtime, std::make_shared<JsiSkPath>(getContext(), SkPath()));
37   }
38 
JSI_HOST_FUNCTION(MakeFromSVGString)39   JSI_HOST_FUNCTION(MakeFromSVGString) {
40     auto svgString = arguments[0].asString(runtime).utf8(runtime);
41     SkPath result;
42 
43     if (!SkParsePath::FromSVGString(svgString.c_str(), &result)) {
44       throw jsi::JSError(runtime, "Could not parse Svg path");
45       return jsi::Value(nullptr);
46     }
47 
48     return jsi::Object::createFromHostObject(
49         runtime, std::make_shared<JsiSkPath>(getContext(), std::move(result)));
50   }
51 
JSI_HOST_FUNCTION(MakeFromOp)52   JSI_HOST_FUNCTION(MakeFromOp) {
53     SkPath one = *JsiSkPath::fromValue(runtime, arguments[0]).get();
54     SkPath two = *JsiSkPath::fromValue(runtime, arguments[1]).get();
55     SkPathOp op = (SkPathOp)arguments[2].asNumber();
56     SkPath result;
57     bool success = Op(one, two, op, &result);
58     if (!success) {
59       return jsi::Value(nullptr);
60     }
61     return jsi::Object::createFromHostObject(
62         runtime, std::make_shared<JsiSkPath>(getContext(), std::move(result)));
63   }
64 
JSI_HOST_FUNCTION(MakeFromCmds)65   JSI_HOST_FUNCTION(MakeFromCmds) {
66     SkPath path;
67     auto cmds = arguments[0].asObject(runtime).asArray(runtime);
68     auto cmdCount = cmds.size(runtime);
69     for (int i = 0; i < cmdCount; i++) {
70       auto cmd =
71           cmds.getValueAtIndex(runtime, i).asObject(runtime).asArray(runtime);
72       if (cmd.size(runtime) < 1) {
73         RNSkLogger::logToConsole("Invalid command found (got an empty array)");
74         return jsi::Value::null();
75       }
76       auto verb = static_cast<int>(cmd.getValueAtIndex(runtime, 0).asNumber());
77       switch (verb) {
78       case MOVE: {
79         if (cmd.size(runtime) < 3) {
80           RNSkLogger::logToConsole("Invalid move command found");
81           return jsi::Value::null();
82         }
83         auto x = cmd.getValueAtIndex(runtime, 1).asNumber();
84         auto y = cmd.getValueAtIndex(runtime, 2).asNumber();
85         path.moveTo(x, y);
86         break;
87       }
88       case LINE: {
89         if (cmd.size(runtime) < 3) {
90           RNSkLogger::logToConsole("Invalid line command found");
91           return jsi::Value::null();
92         }
93         auto x = cmd.getValueAtIndex(runtime, 1).asNumber();
94         auto y = cmd.getValueAtIndex(runtime, 2).asNumber();
95         path.lineTo(x, y);
96         break;
97       }
98       case QUAD: {
99         if (cmd.size(runtime) < 5) {
100           RNSkLogger::logToConsole("Invalid line command found");
101           return jsi::Value::null();
102         }
103         auto x1 = cmd.getValueAtIndex(runtime, 1).asNumber();
104         auto y1 = cmd.getValueAtIndex(runtime, 2).asNumber();
105         auto x2 = cmd.getValueAtIndex(runtime, 3).asNumber();
106         auto y2 = cmd.getValueAtIndex(runtime, 4).asNumber();
107         path.quadTo(x1, y1, x2, y2);
108         break;
109       }
110       case CONIC: {
111         if (cmd.size(runtime) < 6) {
112           RNSkLogger::logToConsole("Invalid line command found");
113           return jsi::Value::null();
114         }
115         auto x1 = cmd.getValueAtIndex(runtime, 1).asNumber();
116         auto y1 = cmd.getValueAtIndex(runtime, 2).asNumber();
117         auto x2 = cmd.getValueAtIndex(runtime, 3).asNumber();
118         auto y2 = cmd.getValueAtIndex(runtime, 4).asNumber();
119         auto w = cmd.getValueAtIndex(runtime, 5).asNumber();
120         path.conicTo(x1, y1, x2, y2, w);
121         break;
122       }
123       case CUBIC: {
124         if (cmd.size(runtime) < 7) {
125           RNSkLogger::logToConsole("Invalid line command found");
126           return jsi::Value::null();
127         }
128         auto x1 = cmd.getValueAtIndex(runtime, 1).asNumber();
129         auto y1 = cmd.getValueAtIndex(runtime, 2).asNumber();
130         auto x2 = cmd.getValueAtIndex(runtime, 3).asNumber();
131         auto y2 = cmd.getValueAtIndex(runtime, 4).asNumber();
132         auto x3 = cmd.getValueAtIndex(runtime, 5).asNumber();
133         auto y3 = cmd.getValueAtIndex(runtime, 6).asNumber();
134         path.cubicTo(x1, y1, x2, y2, x3, y3);
135         break;
136       }
137       case CLOSE: {
138         path.close();
139         break;
140       }
141       default: {
142         RNSkLogger::logToConsole("Found an unknown command");
143         return jsi::Value::null();
144       }
145       }
146     }
147     return jsi::Object::createFromHostObject(
148         runtime, std::make_shared<JsiSkPath>(getContext(), std::move(path)));
149   }
150 
JSI_HOST_FUNCTION(MakeFromText)151   JSI_HOST_FUNCTION(MakeFromText) {
152     auto text = arguments[0].asString(runtime).utf8(runtime);
153     auto x = arguments[1].asNumber();
154     auto y = arguments[2].asNumber();
155     auto font = JsiSkFont::fromValue(runtime, arguments[3]);
156     SkPath path;
157     SkTextUtils::GetPath(text.c_str(), strlen(text.c_str()),
158                          SkTextEncoding::kUTF8, x, y, *font, &path);
159     return jsi::Object::createFromHostObject(
160         runtime, std::make_shared<JsiSkPath>(getContext(), std::move(path)));
161   }
162 
JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC (JsiSkPathFactory,Make),JSI_EXPORT_FUNC (JsiSkPathFactory,MakeFromSVGString),JSI_EXPORT_FUNC (JsiSkPathFactory,MakeFromOp),JSI_EXPORT_FUNC (JsiSkPathFactory,MakeFromCmds),JSI_EXPORT_FUNC (JsiSkPathFactory,MakeFromText))163   JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkPathFactory, Make),
164                        JSI_EXPORT_FUNC(JsiSkPathFactory, MakeFromSVGString),
165                        JSI_EXPORT_FUNC(JsiSkPathFactory, MakeFromOp),
166                        JSI_EXPORT_FUNC(JsiSkPathFactory, MakeFromCmds),
167                        JSI_EXPORT_FUNC(JsiSkPathFactory, MakeFromText))
168 
169   explicit JsiSkPathFactory(std::shared_ptr<RNSkPlatformContext> context)
170       : JsiSkHostObject(std::move(context)) {}
171 };
172 
173 } // namespace RNSkia
174