@shopify/react-native-skia 2.3.6 → 2.3.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/apple/SkiaCVPixelBufferUtils.mm +4 -8
 - package/cpp/api/JsiSkCanvas.h +4 -2
 - package/cpp/api/JsiSkTextStyle.h +1 -1
 - package/cpp/api/recorder/Drawings.h +1 -30
 - package/cpp/api/recorder/RNRecorder.h +17 -2
 - package/cpp/jsi/RuntimeLifecycleMonitor.cpp +27 -12
 - package/cpp/jsi/ViewProperty.h +34 -1
 - package/package.json +1 -1
 - package/scripts/install-skia.mjs +74 -49
 
| 
         @@ -30,16 +30,12 @@ 
     | 
|
| 
       30 
30 
     | 
    
         
             
            #include <TargetConditionals.h>
         
     | 
| 
       31 
31 
     | 
    
         
             
            #if TARGET_RT_BIG_ENDIAN
         
     | 
| 
       32 
32 
     | 
    
         
             
            #define FourCC2Str(fourcc)                                                     \
         
     | 
| 
       33 
     | 
    
         
            -
              (const char[])  
     | 
| 
       34 
     | 
    
         
            -
             
     | 
| 
       35 
     | 
    
         
            -
                    *(((char *)&fourcc) + 3), 0                                            \
         
     | 
| 
       36 
     | 
    
         
            -
              }
         
     | 
| 
      
 33 
     | 
    
         
            +
              (const char[]){*((char *)&fourcc), *(((char *)&fourcc) + 1),                 \
         
     | 
| 
      
 34 
     | 
    
         
            +
                             *(((char *)&fourcc) + 2), *(((char *)&fourcc) + 3), 0}
         
     | 
| 
       37 
35 
     | 
    
         
             
            #else
         
     | 
| 
       38 
36 
     | 
    
         
             
            #define FourCC2Str(fourcc)                                                     \
         
     | 
| 
       39 
     | 
    
         
            -
              (const char[])  
     | 
| 
       40 
     | 
    
         
            -
             
     | 
| 
       41 
     | 
    
         
            -
                    *(((char *)&fourcc) + 1), *(((char *)&fourcc) + 0), 0                  \
         
     | 
| 
       42 
     | 
    
         
            -
              }
         
     | 
| 
      
 37 
     | 
    
         
            +
              (const char[]){*(((char *)&fourcc) + 3), *(((char *)&fourcc) + 2),           \
         
     | 
| 
      
 38 
     | 
    
         
            +
                             *(((char *)&fourcc) + 1), *(((char *)&fourcc) + 0), 0}
         
     | 
| 
       43 
39 
     | 
    
         
             
            #endif
         
     | 
| 
       44 
40 
     | 
    
         | 
| 
       45 
41 
     | 
    
         
             
            // pragma MARK: TextureHolder
         
     | 
    
        package/cpp/api/JsiSkCanvas.h
    CHANGED
    
    | 
         @@ -242,8 +242,10 @@ public: 
     | 
|
| 
       242 
242 
     | 
    
         
             
              }
         
     | 
| 
       243 
243 
     | 
    
         | 
| 
       244 
244 
     | 
    
         
             
              JSI_HOST_FUNCTION(getTotalMatrix) {
         
     | 
| 
       245 
     | 
    
         
            -
                auto matrix = 
     | 
| 
       246 
     | 
    
         
            -
             
     | 
| 
      
 245 
     | 
    
         
            +
                auto matrix =
         
     | 
| 
      
 246 
     | 
    
         
            +
                    std::make_shared<JsiSkMatrix>(getContext(), _canvas->getTotalMatrix());
         
     | 
| 
      
 247 
     | 
    
         
            +
                return JSI_CREATE_HOST_OBJECT_WITH_MEMORY_PRESSURE(runtime, matrix,
         
     | 
| 
      
 248 
     | 
    
         
            +
                                                                   getContext());
         
     | 
| 
       247 
249 
     | 
    
         
             
              }
         
     | 
| 
       248 
250 
     | 
    
         | 
| 
       249 
251 
     | 
    
         
             
              JSI_HOST_FUNCTION(drawPoints) {
         
     | 
    
        package/cpp/api/JsiSkTextStyle.h
    CHANGED
    
    | 
         @@ -137,7 +137,7 @@ public: 
     | 
|
| 
       137 
137 
     | 
    
         
             
                }
         
     | 
| 
       138 
138 
     | 
    
         
             
                if (object.hasProperty(runtime, "halfLeading")) {
         
     | 
| 
       139 
139 
     | 
    
         
             
                  auto propValue = object.getProperty(runtime, "halfLeading");
         
     | 
| 
       140 
     | 
    
         
            -
                  retVal.setHalfLeading(propValue. 
     | 
| 
      
 140 
     | 
    
         
            +
                  retVal.setHalfLeading(propValue.getBool());
         
     | 
| 
       141 
141 
     | 
    
         
             
                }
         
     | 
| 
       142 
142 
     | 
    
         
             
                if (object.hasProperty(runtime, "letterSpacing")) {
         
     | 
| 
       143 
143 
     | 
    
         
             
                  auto propValue = object.getProperty(runtime, "letterSpacing");
         
     | 
| 
         @@ -486,17 +486,6 @@ public: 
     | 
|
| 
       486 
486 
     | 
    
         
             
                convertProperty(runtime, object, "rect", props.rect, variables);
         
     | 
| 
       487 
487 
     | 
    
         
             
              }
         
     | 
| 
       488 
488 
     | 
    
         | 
| 
       489 
     | 
    
         
            -
              ~ImageCmd() {
         
     | 
| 
       490 
     | 
    
         
            -
                if (props.image.has_value()) {
         
     | 
| 
       491 
     | 
    
         
            -
                  auto image = props.image.value();
         
     | 
| 
       492 
     | 
    
         
            -
                  if (image) {
         
     | 
| 
       493 
     | 
    
         
            -
                    _context->runOnMainThread([image]() {
         
     | 
| 
       494 
     | 
    
         
            -
                      // Image will be deleted when this lambda is destroyed on main thread
         
     | 
| 
       495 
     | 
    
         
            -
                    });
         
     | 
| 
       496 
     | 
    
         
            -
                  }
         
     | 
| 
       497 
     | 
    
         
            -
                }
         
     | 
| 
       498 
     | 
    
         
            -
              }
         
     | 
| 
       499 
     | 
    
         
            -
             
     | 
| 
       500 
489 
     | 
    
         
             
              void draw(DrawingCtx *ctx) {
         
     | 
| 
       501 
490 
     | 
    
         
             
                auto [x, y, width, height, rect, fit, image, sampling] = props;
         
     | 
| 
       502 
491 
     | 
    
         
             
                if (image.has_value()) {
         
     | 
| 
         @@ -806,15 +795,6 @@ public: 
     | 
|
| 
       806 
795 
     | 
    
         
             
                convertProperty(runtime, object, "picture", props.picture, variables);
         
     | 
| 
       807 
796 
     | 
    
         
             
              }
         
     | 
| 
       808 
797 
     | 
    
         | 
| 
       809 
     | 
    
         
            -
              ~PictureCmd() {
         
     | 
| 
       810 
     | 
    
         
            -
                auto picture = props.picture;
         
     | 
| 
       811 
     | 
    
         
            -
                if (picture) {
         
     | 
| 
       812 
     | 
    
         
            -
                  _context->runOnMainThread([picture]() {
         
     | 
| 
       813 
     | 
    
         
            -
                    // Picture will be deleted when this lambda is destroyed on main thread
         
     | 
| 
       814 
     | 
    
         
            -
                  });
         
     | 
| 
       815 
     | 
    
         
            -
                }
         
     | 
| 
       816 
     | 
    
         
            -
              }
         
     | 
| 
       817 
     | 
    
         
            -
             
     | 
| 
       818 
798 
     | 
    
         
             
              void draw(DrawingCtx *ctx) { ctx->canvas->drawPicture(props.picture); }
         
     | 
| 
       819 
799 
     | 
    
         
             
            };
         
     | 
| 
       820 
800 
     | 
    
         | 
| 
         @@ -951,15 +931,6 @@ public: 
     | 
|
| 
       951 
931 
     | 
    
         
             
                convertProperty(runtime, object, "sampling", props.sampling, variables);
         
     | 
| 
       952 
932 
     | 
    
         
             
              }
         
     | 
| 
       953 
933 
     | 
    
         | 
| 
       954 
     | 
    
         
            -
              ~AtlasCmd() {
         
     | 
| 
       955 
     | 
    
         
            -
                auto image = props.image;
         
     | 
| 
       956 
     | 
    
         
            -
                if (image) {
         
     | 
| 
       957 
     | 
    
         
            -
                  _context->runOnMainThread([image]() {
         
     | 
| 
       958 
     | 
    
         
            -
                    // Image will be deleted when this lambda is destroyed on main thread
         
     | 
| 
       959 
     | 
    
         
            -
                  });
         
     | 
| 
       960 
     | 
    
         
            -
                }
         
     | 
| 
       961 
     | 
    
         
            -
              }
         
     | 
| 
       962 
     | 
    
         
            -
             
     | 
| 
       963 
934 
     | 
    
         
             
              void draw(DrawingCtx *ctx) {
         
     | 
| 
       964 
935 
     | 
    
         
             
                if (props.image) {
         
     | 
| 
       965 
936 
     | 
    
         
             
                  // Validate transforms and sprites have the same size
         
     | 
| 
         @@ -990,4 +961,4 @@ public: 
     | 
|
| 
       990 
961 
     | 
    
         
             
              }
         
     | 
| 
       991 
962 
     | 
    
         
             
            };
         
     | 
| 
       992 
963 
     | 
    
         | 
| 
       993 
     | 
    
         
            -
            } // namespace RNSkia
         
     | 
| 
      
 964 
     | 
    
         
            +
            } // namespace RNSkia
         
     | 
| 
         @@ -29,7 +29,22 @@ public: 
     | 
|
| 
       29 
29 
     | 
    
         
             
              Variables variables;
         
     | 
| 
       30 
30 
     | 
    
         | 
| 
       31 
31 
     | 
    
         
             
              Recorder() = default;
         
     | 
| 
       32 
     | 
    
         
            -
              ~Recorder()  
     | 
| 
      
 32 
     | 
    
         
            +
              ~Recorder() {
         
     | 
| 
      
 33 
     | 
    
         
            +
                if (!_context || commands.empty()) {
         
     | 
| 
      
 34 
     | 
    
         
            +
                  return;
         
     | 
| 
      
 35 
     | 
    
         
            +
                }
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                auto context = _context;
         
     | 
| 
      
 38 
     | 
    
         
            +
                using CommandList = std::vector<std::unique_ptr<Command>>;
         
     | 
| 
      
 39 
     | 
    
         
            +
                auto pendingCommands = std::make_shared<CommandList>(std::move(commands));
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                context->runOnMainThread(
         
     | 
| 
      
 42 
     | 
    
         
            +
                    [pendingCommands = std::move(pendingCommands)]() mutable {
         
     | 
| 
      
 43 
     | 
    
         
            +
                      // Destroy the recorded commands on the main thread to ensure GPU
         
     | 
| 
      
 44 
     | 
    
         
            +
                      // backed resources release safely.
         
     | 
| 
      
 45 
     | 
    
         
            +
                      pendingCommands->clear();
         
     | 
| 
      
 46 
     | 
    
         
            +
                    });
         
     | 
| 
      
 47 
     | 
    
         
            +
              }
         
     | 
| 
       33 
48 
     | 
    
         | 
| 
       34 
49 
     | 
    
         
             
              void savePaint(jsi::Runtime &runtime, const jsi::Object &props,
         
     | 
| 
       35 
50 
     | 
    
         
             
                             bool standalone) {
         
     | 
| 
         @@ -652,4 +667,4 @@ public: 
     | 
|
| 
       652 
667 
     | 
    
         
             
              }
         
     | 
| 
       653 
668 
     | 
    
         
             
            };
         
     | 
| 
       654 
669 
     | 
    
         | 
| 
       655 
     | 
    
         
            -
            } // namespace RNSkia
         
     | 
| 
      
 670 
     | 
    
         
            +
            } // namespace RNSkia
         
     | 
| 
         @@ -1,5 +1,6 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            #include "RuntimeLifecycleMonitor.h"
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
      
 3 
     | 
    
         
            +
            #include <mutex>
         
     | 
| 
       3 
4 
     | 
    
         
             
            #include <unordered_map>
         
     | 
| 
       4 
5 
     | 
    
         
             
            #include <unordered_set>
         
     | 
| 
       5 
6 
     | 
    
         
             
            #include <utility>
         
     | 
| 
         @@ -9,25 +10,43 @@ namespace RNJsi { 
     | 
|
| 
       9 
10 
     | 
    
         
             
            static std::unordered_map<jsi::Runtime *,
         
     | 
| 
       10 
11 
     | 
    
         
             
                                      std::unordered_set<RuntimeLifecycleListener *>>
         
     | 
| 
       11 
12 
     | 
    
         
             
                listeners;
         
     | 
| 
      
 13 
     | 
    
         
            +
            static std::mutex listenersMutex;
         
     | 
| 
       12 
14 
     | 
    
         | 
| 
       13 
15 
     | 
    
         
             
            struct RuntimeLifecycleMonitorObject : public jsi::HostObject {
         
     | 
| 
       14 
16 
     | 
    
         
             
              jsi::Runtime *_rt;
         
     | 
| 
       15 
17 
     | 
    
         
             
              explicit RuntimeLifecycleMonitorObject(jsi::Runtime *rt) : _rt(rt) {}
         
     | 
| 
       16 
18 
     | 
    
         
             
              ~RuntimeLifecycleMonitorObject() {
         
     | 
| 
       17 
     | 
    
         
            -
                 
     | 
| 
       18 
     | 
    
         
            -
                 
     | 
| 
       19 
     | 
    
         
            -
                   
     | 
| 
       20 
     | 
    
         
            -
             
     | 
| 
      
 19 
     | 
    
         
            +
                std::unordered_set<RuntimeLifecycleListener *> listenersCopy;
         
     | 
| 
      
 20 
     | 
    
         
            +
                {
         
     | 
| 
      
 21 
     | 
    
         
            +
                  std::lock_guard<std::mutex> lock(listenersMutex);
         
     | 
| 
      
 22 
     | 
    
         
            +
                  auto listenersSet = listeners.find(_rt);
         
     | 
| 
      
 23 
     | 
    
         
            +
                  if (listenersSet != listeners.end()) {
         
     | 
| 
      
 24 
     | 
    
         
            +
                    listenersCopy = listenersSet->second;
         
     | 
| 
      
 25 
     | 
    
         
            +
                    listeners.erase(listenersSet);
         
     | 
| 
       21 
26 
     | 
    
         
             
                  }
         
     | 
| 
       22 
     | 
    
         
            -
             
     | 
| 
      
 27 
     | 
    
         
            +
                }
         
     | 
| 
      
 28 
     | 
    
         
            +
                for (auto listener : listenersCopy) {
         
     | 
| 
      
 29 
     | 
    
         
            +
                  listener->onRuntimeDestroyed(_rt);
         
     | 
| 
       23 
30 
     | 
    
         
             
                }
         
     | 
| 
       24 
31 
     | 
    
         
             
              }
         
     | 
| 
       25 
32 
     | 
    
         
             
            };
         
     | 
| 
       26 
33 
     | 
    
         | 
| 
       27 
34 
     | 
    
         
             
            void RuntimeLifecycleMonitor::addListener(jsi::Runtime &rt,
         
     | 
| 
       28 
35 
     | 
    
         
             
                                                      RuntimeLifecycleListener *listener) {
         
     | 
| 
       29 
     | 
    
         
            -
               
     | 
| 
       30 
     | 
    
         
            -
               
     | 
| 
      
 36 
     | 
    
         
            +
              bool shouldInstallMonitor = false;
         
     | 
| 
      
 37 
     | 
    
         
            +
              {
         
     | 
| 
      
 38 
     | 
    
         
            +
                std::lock_guard<std::mutex> lock(listenersMutex);
         
     | 
| 
      
 39 
     | 
    
         
            +
                auto listenersSet = listeners.find(&rt);
         
     | 
| 
      
 40 
     | 
    
         
            +
                if (listenersSet == listeners.end()) {
         
     | 
| 
      
 41 
     | 
    
         
            +
                  std::unordered_set<RuntimeLifecycleListener *> newSet;
         
     | 
| 
      
 42 
     | 
    
         
            +
                  newSet.insert(listener);
         
     | 
| 
      
 43 
     | 
    
         
            +
                  listeners.emplace(&rt, std::move(newSet));
         
     | 
| 
      
 44 
     | 
    
         
            +
                  shouldInstallMonitor = true;
         
     | 
| 
      
 45 
     | 
    
         
            +
                } else {
         
     | 
| 
      
 46 
     | 
    
         
            +
                  listenersSet->second.insert(listener);
         
     | 
| 
      
 47 
     | 
    
         
            +
                }
         
     | 
| 
      
 48 
     | 
    
         
            +
              }
         
     | 
| 
      
 49 
     | 
    
         
            +
              if (shouldInstallMonitor) {
         
     | 
| 
       31 
50 
     | 
    
         
             
                // We install a global host object in the provided runtime, this way we can
         
     | 
| 
       32 
51 
     | 
    
         
             
                // use that host object destructor to get notified when the runtime is being
         
     | 
| 
       33 
52 
     | 
    
         
             
                // terminated. We use a unique name for the object as it gets saved with the
         
     | 
| 
         @@ -36,16 +55,12 @@ void RuntimeLifecycleMonitor::addListener(jsi::Runtime &rt, 
     | 
|
| 
       36 
55 
     | 
    
         
             
                    rt, "__rnskia_rt_lifecycle_monitor",
         
     | 
| 
       37 
56 
     | 
    
         
             
                    jsi::Object::createFromHostObject(
         
     | 
| 
       38 
57 
     | 
    
         
             
                        rt, std::make_shared<RuntimeLifecycleMonitorObject>(&rt)));
         
     | 
| 
       39 
     | 
    
         
            -
                std::unordered_set<RuntimeLifecycleListener *> newSet;
         
     | 
| 
       40 
     | 
    
         
            -
                newSet.insert(listener);
         
     | 
| 
       41 
     | 
    
         
            -
                listeners.emplace(&rt, std::move(newSet));
         
     | 
| 
       42 
     | 
    
         
            -
              } else {
         
     | 
| 
       43 
     | 
    
         
            -
                listenersSet->second.insert(listener);
         
     | 
| 
       44 
58 
     | 
    
         
             
              }
         
     | 
| 
       45 
59 
     | 
    
         
             
            }
         
     | 
| 
       46 
60 
     | 
    
         | 
| 
       47 
61 
     | 
    
         
             
            void RuntimeLifecycleMonitor::removeListener(
         
     | 
| 
       48 
62 
     | 
    
         
             
                jsi::Runtime &rt, RuntimeLifecycleListener *listener) {
         
     | 
| 
      
 63 
     | 
    
         
            +
              std::lock_guard<std::mutex> lock(listenersMutex);
         
     | 
| 
       49 
64 
     | 
    
         
             
              auto listenersSet = listeners.find(&rt);
         
     | 
| 
       50 
65 
     | 
    
         
             
              if (listenersSet == listeners.end()) {
         
     | 
| 
       51 
66 
     | 
    
         
             
                // nothing to do here
         
     | 
    
        package/cpp/jsi/ViewProperty.h
    CHANGED
    
    | 
         @@ -1,5 +1,6 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            #pragma once
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
      
 3 
     | 
    
         
            +
            #include <atomic>
         
     | 
| 
       3 
4 
     | 
    
         
             
            #include <functional>
         
     | 
| 
       4 
5 
     | 
    
         
             
            #include <jsi/jsi.h>
         
     | 
| 
       5 
6 
     | 
    
         
             
            #include <memory>
         
     | 
| 
         @@ -7,10 +8,35 @@ 
     | 
|
| 
       7 
8 
     | 
    
         
             
            #include <variant>
         
     | 
| 
       8 
9 
     | 
    
         | 
| 
       9 
10 
     | 
    
         
             
            #include "JsiSkPicture.h"
         
     | 
| 
      
 11 
     | 
    
         
            +
            #include "RuntimeLifecycleMonitor.h"
         
     | 
| 
       10 
12 
     | 
    
         | 
| 
       11 
13 
     | 
    
         
             
            namespace RNJsi {
         
     | 
| 
       12 
14 
     | 
    
         
             
            namespace jsi = facebook::jsi;
         
     | 
| 
       13 
15 
     | 
    
         | 
| 
      
 16 
     | 
    
         
            +
            class RuntimeAwareRuntimeGuard : public RuntimeLifecycleListener {
         
     | 
| 
      
 17 
     | 
    
         
            +
            public:
         
     | 
| 
      
 18 
     | 
    
         
            +
              explicit RuntimeAwareRuntimeGuard(jsi::Runtime &runtime)
         
     | 
| 
      
 19 
     | 
    
         
            +
                  : _runtime(&runtime) {
         
     | 
| 
      
 20 
     | 
    
         
            +
                RuntimeLifecycleMonitor::addListener(runtime, this);
         
     | 
| 
      
 21 
     | 
    
         
            +
              }
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
              ~RuntimeAwareRuntimeGuard() override {
         
     | 
| 
      
 24 
     | 
    
         
            +
                auto runtime = _runtime.load();
         
     | 
| 
      
 25 
     | 
    
         
            +
                if (runtime != nullptr) {
         
     | 
| 
      
 26 
     | 
    
         
            +
                  RuntimeLifecycleMonitor::removeListener(*runtime, this);
         
     | 
| 
      
 27 
     | 
    
         
            +
                }
         
     | 
| 
      
 28 
     | 
    
         
            +
              }
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
              void onRuntimeDestroyed(jsi::Runtime *) override {
         
     | 
| 
      
 31 
     | 
    
         
            +
                _runtime.store(nullptr);
         
     | 
| 
      
 32 
     | 
    
         
            +
              }
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
              jsi::Runtime *getRuntime() const { return _runtime.load(); }
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
            private:
         
     | 
| 
      
 37 
     | 
    
         
            +
              std::atomic<jsi::Runtime *> _runtime;
         
     | 
| 
      
 38 
     | 
    
         
            +
            };
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
       14 
40 
     | 
    
         
             
            class ViewProperty {
         
     | 
| 
       15 
41 
     | 
    
         
             
            public:
         
     | 
| 
       16 
42 
     | 
    
         
             
              ViewProperty(jsi::Runtime &runtime, const jsi::Value &value) {
         
     | 
| 
         @@ -31,8 +57,15 @@ public: 
     | 
|
| 
       31 
57 
     | 
    
         
             
              ViewProperty(jsi::Runtime &runtime, const jsi::Value &value,
         
     | 
| 
       32 
58 
     | 
    
         
             
                           PlatformContext platformContext, size_t nativeId) {
         
     | 
| 
       33 
59 
     | 
    
         
             
                // Set the onSize callback with all the necessary context
         
     | 
| 
      
 60 
     | 
    
         
            +
                auto runtimeGuard = std::make_shared<RuntimeAwareRuntimeGuard>(runtime);
         
     | 
| 
       34 
61 
     | 
    
         
             
                _value = std::function<void(int, int)>(
         
     | 
| 
       35 
     | 
    
         
            -
                    [ 
     | 
| 
      
 62 
     | 
    
         
            +
                    [runtimeGuard, platformContext, nativeId](int width, int height) {
         
     | 
| 
      
 63 
     | 
    
         
            +
                      auto runtimePtr = runtimeGuard->getRuntime();
         
     | 
| 
      
 64 
     | 
    
         
            +
                      if (runtimePtr == nullptr) {
         
     | 
| 
      
 65 
     | 
    
         
            +
                        return;
         
     | 
| 
      
 66 
     | 
    
         
            +
                      }
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
                      jsi::Runtime &runtime = *runtimePtr;
         
     | 
| 
       36 
69 
     | 
    
         
             
                      jsi::Object size(runtime);
         
     | 
| 
       37 
70 
     | 
    
         
             
                      auto pd = platformContext->getPixelDensity();
         
     | 
| 
       38 
71 
     | 
    
         
             
                      size.setProperty(runtime, "width", jsi::Value(width / pd));
         
     | 
    
        package/package.json
    CHANGED
    
    
    
        package/scripts/install-skia.mjs
    CHANGED
    
    | 
         @@ -77,64 +77,89 @@ const runCommand = (command, args) => { 
     | 
|
| 
       77 
77 
     | 
    
         
             
              });
         
     | 
| 
       78 
78 
     | 
    
         
             
            };
         
     | 
| 
       79 
79 
     | 
    
         | 
| 
       80 
     | 
    
         
            -
            const  
     | 
| 
      
 80 
     | 
    
         
            +
            const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
            const downloadToFile = (url, destPath, maxRetries = 5) => {
         
     | 
| 
       81 
83 
     | 
    
         
             
              fs.mkdirSync(path.dirname(destPath), { recursive: true });
         
     | 
| 
       82 
     | 
    
         
            -
             
     | 
| 
       83 
     | 
    
         
            -
             
     | 
| 
       84 
     | 
    
         
            -
             
     | 
| 
       85 
     | 
    
         
            -
             
     | 
| 
       86 
     | 
    
         
            -
             
     | 
| 
       87 
     | 
    
         
            -
             
     | 
| 
       88 
     | 
    
         
            -
                         
     | 
| 
       89 
     | 
    
         
            -
             
     | 
| 
       90 
     | 
    
         
            -
             
     | 
| 
       91 
     | 
    
         
            -
                         
     | 
| 
       92 
     | 
    
         
            -
                          res. 
     | 
| 
       93 
     | 
    
         
            -
                           
     | 
| 
       94 
     | 
    
         
            -
             
     | 
| 
       95 
     | 
    
         
            -
             
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
              const attemptDownload = (retryCount = 0) => {
         
     | 
| 
      
 86 
     | 
    
         
            +
                return new Promise((resolve, reject) => {
         
     | 
| 
      
 87 
     | 
    
         
            +
                  const request = (currentUrl) => {
         
     | 
| 
      
 88 
     | 
    
         
            +
                    https
         
     | 
| 
      
 89 
     | 
    
         
            +
                      .get(currentUrl, { headers: { "User-Agent": "node" } }, (res) => {
         
     | 
| 
      
 90 
     | 
    
         
            +
                        if (
         
     | 
| 
      
 91 
     | 
    
         
            +
                          res.statusCode &&
         
     | 
| 
      
 92 
     | 
    
         
            +
                          [301, 302, 303, 307, 308].includes(res.statusCode)
         
     | 
| 
      
 93 
     | 
    
         
            +
                        ) {
         
     | 
| 
      
 94 
     | 
    
         
            +
                          const { location } = res.headers;
         
     | 
| 
      
 95 
     | 
    
         
            +
                          if (location) {
         
     | 
| 
      
 96 
     | 
    
         
            +
                            res.resume();
         
     | 
| 
      
 97 
     | 
    
         
            +
                            request(location);
         
     | 
| 
      
 98 
     | 
    
         
            +
                          } else {
         
     | 
| 
      
 99 
     | 
    
         
            +
                            reject(new Error(`Redirect without location for ${currentUrl}`));
         
     | 
| 
      
 100 
     | 
    
         
            +
                          }
         
     | 
| 
      
 101 
     | 
    
         
            +
                          return;
         
     | 
| 
       96 
102 
     | 
    
         
             
                        }
         
     | 
| 
       97 
     | 
    
         
            -
                        return;
         
     | 
| 
       98 
     | 
    
         
            -
                      }
         
     | 
| 
       99 
103 
     | 
    
         | 
| 
       100 
     | 
    
         
            -
             
     | 
| 
       101 
     | 
    
         
            -
             
     | 
| 
       102 
     | 
    
         
            -
                          new Error(
         
     | 
| 
      
 104 
     | 
    
         
            +
                        if (res.statusCode !== 200) {
         
     | 
| 
      
 105 
     | 
    
         
            +
                          const error = new Error(
         
     | 
| 
       103 
106 
     | 
    
         
             
                            `Failed to download: ${res.statusCode} ${res.statusMessage}`
         
     | 
| 
       104 
     | 
    
         
            -
                          )
         
     | 
| 
       105 
     | 
    
         
            -
             
     | 
| 
       106 
     | 
    
         
            -
             
     | 
| 
       107 
     | 
    
         
            -
             
     | 
| 
       108 
     | 
    
         
            -
             
     | 
| 
       109 
     | 
    
         
            -
             
     | 
| 
       110 
     | 
    
         
            -
                      const fileStream = fs.createWriteStream(destPath);
         
     | 
| 
       111 
     | 
    
         
            -
                      res.pipe(fileStream);
         
     | 
| 
      
 107 
     | 
    
         
            +
                          );
         
     | 
| 
      
 108 
     | 
    
         
            +
                          error.statusCode = res.statusCode;
         
     | 
| 
      
 109 
     | 
    
         
            +
                          reject(error);
         
     | 
| 
      
 110 
     | 
    
         
            +
                          res.resume();
         
     | 
| 
      
 111 
     | 
    
         
            +
                          return;
         
     | 
| 
      
 112 
     | 
    
         
            +
                        }
         
     | 
| 
       112 
113 
     | 
    
         | 
| 
       113 
     | 
    
         
            -
             
     | 
| 
       114 
     | 
    
         
            -
                         
     | 
| 
       115 
     | 
    
         
            -
             
     | 
| 
       116 
     | 
    
         
            -
             
     | 
| 
       117 
     | 
    
         
            -
             
     | 
| 
       118 
     | 
    
         
            -
                             
     | 
| 
       119 
     | 
    
         
            -
             
     | 
| 
       120 
     | 
    
         
            -
             
     | 
| 
       121 
     | 
    
         
            -
             
     | 
| 
      
 114 
     | 
    
         
            +
                        const fileStream = fs.createWriteStream(destPath);
         
     | 
| 
      
 115 
     | 
    
         
            +
                        res.pipe(fileStream);
         
     | 
| 
      
 116 
     | 
    
         
            +
             
     | 
| 
      
 117 
     | 
    
         
            +
                        fileStream.on("finish", () => {
         
     | 
| 
      
 118 
     | 
    
         
            +
                          fileStream.close((err) => {
         
     | 
| 
      
 119 
     | 
    
         
            +
                            if (err) {
         
     | 
| 
      
 120 
     | 
    
         
            +
                              // If closing the stream errors, perform the same cleanup and reject.
         
     | 
| 
      
 121 
     | 
    
         
            +
                              fileStream.destroy();
         
     | 
| 
      
 122 
     | 
    
         
            +
                              fs.unlink(destPath, () => reject(err));
         
     | 
| 
      
 123 
     | 
    
         
            +
                            } else {
         
     | 
| 
      
 124 
     | 
    
         
            +
                              resolve();
         
     | 
| 
      
 125 
     | 
    
         
            +
                            }
         
     | 
| 
      
 126 
     | 
    
         
            +
                          });
         
     | 
| 
       122 
127 
     | 
    
         
             
                        });
         
     | 
| 
       123 
     | 
    
         
            -
                      });
         
     | 
| 
       124 
128 
     | 
    
         | 
| 
       125 
     | 
    
         
            -
             
     | 
| 
       126 
     | 
    
         
            -
             
     | 
| 
       127 
     | 
    
         
            -
             
     | 
| 
       128 
     | 
    
         
            -
             
     | 
| 
      
 129 
     | 
    
         
            +
                        const cleanup = (error) => {
         
     | 
| 
      
 130 
     | 
    
         
            +
                          fileStream.destroy();
         
     | 
| 
      
 131 
     | 
    
         
            +
                          fs.unlink(destPath, () => reject(error));
         
     | 
| 
      
 132 
     | 
    
         
            +
                        };
         
     | 
| 
      
 133 
     | 
    
         
            +
             
     | 
| 
      
 134 
     | 
    
         
            +
                        res.on("error", cleanup);
         
     | 
| 
      
 135 
     | 
    
         
            +
                        fileStream.on("error", cleanup);
         
     | 
| 
      
 136 
     | 
    
         
            +
                      })
         
     | 
| 
      
 137 
     | 
    
         
            +
                      .on("error", reject);
         
     | 
| 
      
 138 
     | 
    
         
            +
                  };
         
     | 
| 
       129 
139 
     | 
    
         | 
| 
       130 
     | 
    
         
            -
             
     | 
| 
       131 
     | 
    
         
            -
             
     | 
| 
       132 
     | 
    
         
            -
             
     | 
| 
       133 
     | 
    
         
            -
                    .on("error", reject);
         
     | 
| 
       134 
     | 
    
         
            -
                };
         
     | 
| 
      
 140 
     | 
    
         
            +
                  request(url);
         
     | 
| 
      
 141 
     | 
    
         
            +
                });
         
     | 
| 
      
 142 
     | 
    
         
            +
              };
         
     | 
| 
       135 
143 
     | 
    
         | 
| 
       136 
     | 
    
         
            -
             
     | 
| 
       137 
     | 
    
         
            -
             
     | 
| 
      
 144 
     | 
    
         
            +
              const downloadWithRetry = async (retryCount = 0) => {
         
     | 
| 
      
 145 
     | 
    
         
            +
                try {
         
     | 
| 
      
 146 
     | 
    
         
            +
                  await attemptDownload(retryCount);
         
     | 
| 
      
 147 
     | 
    
         
            +
                } catch (error) {
         
     | 
| 
      
 148 
     | 
    
         
            +
                  const isRateLimit = error.statusCode === 403 || error.message.includes('rate limit');
         
     | 
| 
      
 149 
     | 
    
         
            +
                  const shouldRetry = retryCount < maxRetries && (isRateLimit || error.code === 'ECONNRESET' || error.code === 'ETIMEDOUT');
         
     | 
| 
      
 150 
     | 
    
         
            +
             
     | 
| 
      
 151 
     | 
    
         
            +
                  if (shouldRetry) {
         
     | 
| 
      
 152 
     | 
    
         
            +
                    const delay = Math.pow(2, retryCount) * 1000; // 1s, 2s, 4s, 8s, 16s
         
     | 
| 
      
 153 
     | 
    
         
            +
                    console.log(`   ⚠️  Download failed (${error.message}), retrying in ${delay/1000}s... (attempt ${retryCount + 1}/${maxRetries})`);
         
     | 
| 
      
 154 
     | 
    
         
            +
                    await sleep(delay);
         
     | 
| 
      
 155 
     | 
    
         
            +
                    return downloadWithRetry(retryCount + 1);
         
     | 
| 
      
 156 
     | 
    
         
            +
                  } else {
         
     | 
| 
      
 157 
     | 
    
         
            +
                    throw error;
         
     | 
| 
      
 158 
     | 
    
         
            +
                  }
         
     | 
| 
      
 159 
     | 
    
         
            +
                }
         
     | 
| 
      
 160 
     | 
    
         
            +
              };
         
     | 
| 
      
 161 
     | 
    
         
            +
             
     | 
| 
      
 162 
     | 
    
         
            +
              return downloadWithRetry();
         
     | 
| 
       138 
163 
     | 
    
         
             
            };
         
     | 
| 
       139 
164 
     | 
    
         | 
| 
       140 
165 
     | 
    
         
             
            const extractTarGz = async (archivePath, destDir) => {
         
     |