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 <SkPath.h>
15 #include <SkPathOps.h>
16 #include <RNSkLog.h>
17 
18 #pragma clang diagnostic pop
19 
20 namespace RNSkia {
21 
22 using namespace facebook;
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 = cmds.getValueAtIndex(runtime, i).asObject(runtime).asArray(runtime);
71       if (cmd.size(runtime) < 1) {
72         RNSkLogger::logToConsole("Invalid command found (got an empty array)");
73         return jsi::Value::null();
74       }
75       auto verb = static_cast<int>(cmd.getValueAtIndex(runtime, 0).asNumber());
76       switch (verb) {
77         case MOVE: {
78           if (cmd.size(runtime) < 3) {
79             RNSkLogger::logToConsole( "Invalid move command found");
80             return jsi::Value::null();
81           }
82           auto x = cmd.getValueAtIndex(runtime, 1).asNumber();
83           auto y = cmd.getValueAtIndex(runtime, 2).asNumber();
84           path.moveTo(x, y);
85           break;
86         }
87         case LINE: {
88           if (cmd.size(runtime) < 3) {
89             RNSkLogger::logToConsole("Invalid line command found");
90             return jsi::Value::null();
91           }
92           auto x = cmd.getValueAtIndex(runtime, 1).asNumber();
93           auto y = cmd.getValueAtIndex(runtime, 2).asNumber();
94           path.lineTo(x, y);
95           break;
96         }
97         case QUAD: {
98           if (cmd.size(runtime) < 5) {
99             RNSkLogger::logToConsole("Invalid line command found");
100             return jsi::Value::null();
101           }
102           auto x1 = cmd.getValueAtIndex(runtime, 1).asNumber();
103           auto y1 = cmd.getValueAtIndex(runtime, 2).asNumber();
104           auto x2 = cmd.getValueAtIndex(runtime, 3).asNumber();
105           auto y2 = cmd.getValueAtIndex(runtime, 4).asNumber();
106           path.quadTo(x1, y1, x2, y2);
107           break;
108         }
109         case CONIC: {
110           if (cmd.size(runtime) < 6) {
111             RNSkLogger::logToConsole("Invalid line command found");
112             return jsi::Value::null();
113           }
114           auto x1 = cmd.getValueAtIndex(runtime, 1).asNumber();
115           auto y1 = cmd.getValueAtIndex(runtime, 2).asNumber();
116           auto x2 = cmd.getValueAtIndex(runtime, 3).asNumber();
117           auto y2 = cmd.getValueAtIndex(runtime, 4).asNumber();
118           auto w = cmd.getValueAtIndex(runtime, 5).asNumber();
119           path.conicTo(x1, y1, x2, y2, w);
120           break;
121         }
122         case CUBIC: {
123           if (cmd.size(runtime) < 7) {
124             RNSkLogger::logToConsole("Invalid line command found");
125             return jsi::Value::null();
126           }
127           auto x1 = cmd.getValueAtIndex(runtime, 1).asNumber();
128           auto y1 = cmd.getValueAtIndex(runtime, 2).asNumber();
129           auto x2 = cmd.getValueAtIndex(runtime, 3).asNumber();
130           auto y2 = cmd.getValueAtIndex(runtime, 4).asNumber();
131           auto x3 = cmd.getValueAtIndex(runtime, 5).asNumber();
132           auto y3 = cmd.getValueAtIndex(runtime, 6).asNumber();
133           path.cubicTo(x1, y1, x2, y2, x3, y3);
134           break;
135         }
136         case CLOSE: {
137           path.close();
138           break;
139         }
140         default: {
141           RNSkLogger::logToConsole("Found an unknown command");
142           return jsi::Value::null();
143         }
144       }
145     }
146     return jsi::Object::createFromHostObject(
147             runtime, std::make_shared<JsiSkPath>(getContext(), std::move(path)));
148   }
149 
JSI_HOST_FUNCTION(MakeFromText)150   JSI_HOST_FUNCTION(MakeFromText) {
151     auto text = arguments[0].asString(runtime).utf8(runtime);
152     auto x = arguments[1].asNumber();
153     auto y = arguments[2].asNumber();
154     auto font = JsiSkFont::fromValue(runtime, arguments[3]);
155     SkPath path;
156     SkTextUtils::GetPath(text.c_str(), strlen(text.c_str()),
157                          SkTextEncoding::kUTF8, x, y, *font, &path);
158     return jsi::Object::createFromHostObject(
159             runtime, std::make_shared<JsiSkPath>(getContext(), std::move(path)));;
160   }
161 
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))162   JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkPathFactory, Make),
163                        JSI_EXPORT_FUNC(JsiSkPathFactory, MakeFromSVGString),
164                        JSI_EXPORT_FUNC(JsiSkPathFactory, MakeFromOp),
165                        JSI_EXPORT_FUNC(JsiSkPathFactory, MakeFromCmds),
166                        JSI_EXPORT_FUNC(JsiSkPathFactory, MakeFromText))
167 
168     JsiSkPathFactory(std::shared_ptr<RNSkPlatformContext> context)
169       : JsiSkHostObject(std::move(context)) {}
170 };
171 
172 } // namespace RNSkia
173