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