1 #pragma once
2 
3 #include <memory>
4 #include <utility>
5 
6 #include <jsi/jsi.h>
7 
8 #include "JsiPromises.h"
9 #include "JsiSkData.h"
10 #include "SkBase64.h"
11 
12 namespace RNSkia {
13 
14 namespace jsi = facebook::jsi;
15 
16 class JsiSkDataFactory : public JsiSkHostObject {
17 public:
JSI_HOST_FUNCTION(fromURI)18   JSI_HOST_FUNCTION(fromURI) {
19     auto jsiLocalUri = arguments[0].asString(runtime);
20     auto localUri = jsiLocalUri.utf8(runtime);
21     auto context = getContext();
22     return RNJsi::JsiPromises::createPromiseAsJSIValue(
23         runtime,
24         [context = std::move(context), localUri = std::move(localUri)](
25             jsi::Runtime &runtime,
26             std::shared_ptr<RNJsi::JsiPromises::Promise> promise) -> void {
27           // Create a stream operation - this will be run in a
28           // separate thread
29           context->performStreamOperation(
30               localUri,
31               [&runtime, context = std::move(context),
32                promise = std::move(promise)](
33                   std::unique_ptr<SkStreamAsset> stream) -> void {
34                 // Schedule drawCallback on the Javascript thread
35                 auto result =
36                     SkData::MakeFromStream(stream.get(), stream->getLength());
37                 context->runOnJavascriptThread([&runtime,
38                                                 context = std::move(context),
39                                                 promise = std::move(promise),
40                                                 result = std::move(result)]() {
41                   promise->resolve(jsi::Object::createFromHostObject(
42                       runtime, std::make_shared<JsiSkData>(std::move(context),
43                                                            std::move(result))));
44                 });
45               });
46         });
47   };
48 
JSI_HOST_FUNCTION(fromBytes)49   JSI_HOST_FUNCTION(fromBytes) {
50     auto array = arguments[0].asObject(runtime);
51     jsi::ArrayBuffer buffer =
52         array.getProperty(runtime, jsi::PropNameID::forAscii(runtime, "buffer"))
53             .asObject(runtime)
54             .getArrayBuffer(runtime);
55 
56     auto data =
57         SkData::MakeWithCopy(buffer.data(runtime), buffer.size(runtime));
58     return jsi::Object::createFromHostObject(
59         runtime, std::make_shared<JsiSkData>(getContext(), std::move(data)));
60   }
61 
JSI_HOST_FUNCTION(fromBase64)62   JSI_HOST_FUNCTION(fromBase64) {
63     auto base64 = arguments[0].asString(runtime);
64     auto base64Str = base64.utf8(runtime);
65     auto size = base64Str.size();
66 
67     // Calculate length
68     size_t len;
69     auto err =
70         SkBase64::Decode(&base64.utf8(runtime).c_str()[0], size, nullptr, &len);
71     if (err != SkBase64::Error::kNoError) {
72       throw jsi::JSError(runtime, "Error decoding base64 string");
73       return jsi::Value::undefined();
74     }
75 
76     // Create data object and decode
77     auto data = SkData::MakeUninitialized(len);
78     err = SkBase64::Decode(&base64.utf8(runtime).c_str()[0], size,
79                            data->writable_data(), &len);
80     if (err != SkBase64::Error::kNoError) {
81       throw jsi::JSError(runtime, "Error decoding base64 string");
82       return jsi::Value::undefined();
83     }
84 
85     return jsi::Object::createFromHostObject(
86         runtime, std::make_shared<JsiSkData>(getContext(), std::move(data)));
87   }
88 
JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC (JsiSkDataFactory,fromURI),JSI_EXPORT_FUNC (JsiSkDataFactory,fromBytes),JSI_EXPORT_FUNC (JsiSkDataFactory,fromBase64))89   JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkDataFactory, fromURI),
90                        JSI_EXPORT_FUNC(JsiSkDataFactory, fromBytes),
91                        JSI_EXPORT_FUNC(JsiSkDataFactory, fromBase64))
92 
93   explicit JsiSkDataFactory(std::shared_ptr<RNSkPlatformContext> context)
94       : JsiSkHostObject(std::move(context)) {}
95 };
96 
97 } // namespace RNSkia
98