@shopify/react-native-skia 2.5.1 → 2.5.2
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/android/CMakeLists.txt +4 -6
- package/android/build.gradle +5 -32
- package/android/cpp/rnskia-android/OpenGLContext.h +9 -2
- package/android/cpp/rnskia-android/RNSkAndroidPlatformContext.h +6 -3
- package/apple/MetalContext.h +10 -2
- package/apple/MetalWindowContext.h +1 -0
- package/apple/MetalWindowContext.mm +8 -1
- package/apple/RNSkApplePlatformContext.h +2 -1
- package/apple/RNSkApplePlatformContext.mm +6 -4
- package/apple/SkiaPictureView.mm +3 -0
- package/cpp/api/JsiSkImage.h +76 -0
- package/cpp/api/JsiSkSurfaceFactory.h +12 -1
- package/cpp/rnskia/RNDawnContext.h +24 -16
- package/cpp/rnskia/RNDawnUtils.h +12 -0
- package/cpp/rnskia/RNSkPlatformContext.h +3 -1
- package/lib/commonjs/skia/types/Surface/SurfaceFactory.d.ts +10 -1
- package/lib/commonjs/skia/types/Surface/SurfaceFactory.js +5 -0
- package/lib/commonjs/skia/types/Surface/SurfaceFactory.js.map +1 -1
- package/lib/module/skia/types/Surface/SurfaceFactory.d.ts +10 -1
- package/lib/module/skia/types/Surface/SurfaceFactory.js +4 -1
- package/lib/module/skia/types/Surface/SurfaceFactory.js.map +1 -1
- package/lib/typescript/lib/commonjs/skia/types/Surface/SurfaceFactory.d.ts +4 -0
- package/lib/typescript/lib/module/mock/index.d.ts +4 -0
- package/lib/typescript/lib/module/skia/types/Surface/SurfaceFactory.d.ts +4 -1
- package/lib/typescript/src/skia/types/Surface/SurfaceFactory.d.ts +10 -1
- package/package.json +5 -2
- package/react-native-skia.podspec +16 -83
- package/scripts/install-libs.js +131 -0
- package/src/skia/types/Surface/SurfaceFactory.ts +13 -1
package/android/CMakeLists.txt
CHANGED
|
@@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.4.1)
|
|
|
4
4
|
set (CMAKE_VERBOSE_MAKEFILE ON)
|
|
5
5
|
set (CMAKE_CXX_STANDARD 20)
|
|
6
6
|
|
|
7
|
-
# SKIA_LIBS_PATH is passed from Gradle (
|
|
7
|
+
# SKIA_LIBS_PATH is passed from Gradle (pointing to libs/android/, populated by npm postinstall)
|
|
8
8
|
# Append the ABI to get the full path
|
|
9
9
|
set (SKIA_LIBS_PATH "${SKIA_LIBS_PATH}/${ANDROID_ABI}")
|
|
10
10
|
|
|
@@ -17,14 +17,12 @@ if(NOT EXISTS "${SKIA_LIBS_PATH}/libskia.a")
|
|
|
17
17
|
message("│ │")
|
|
18
18
|
message("│ Could not find libskia.a at: ${SKIA_LIBS_PATH} │")
|
|
19
19
|
message("│ │")
|
|
20
|
-
message("│
|
|
21
|
-
message("│
|
|
22
|
-
message("│ │")
|
|
23
|
-
message("│ See: https://shopify.github.io/react-native-skia/docs/getting-started/installation │")
|
|
20
|
+
message("│ Run the following command to install them: │")
|
|
21
|
+
message("│ npx install-skia │")
|
|
24
22
|
message("│ │")
|
|
25
23
|
message("└─────────────────────────────────────────────────────────────────────────────┘")
|
|
26
24
|
message("")
|
|
27
|
-
message(FATAL_ERROR "Skia prebuilt binaries not found
|
|
25
|
+
message(FATAL_ERROR "Skia prebuilt binaries not found. Run `npx install-skia` to fix this.")
|
|
28
26
|
endif()
|
|
29
27
|
|
|
30
28
|
# Import libskia
|
package/android/build.gradle
CHANGED
|
@@ -56,41 +56,15 @@ static def findNodeModules(baseDir) {
|
|
|
56
56
|
throw new GradleException("React-Native-Skia: Failed to find node_modules/ path!")
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
// Resolve npm package path using Node.js resolution (handles monorepos, pnpm, etc.)
|
|
60
|
-
def resolveSkiaPackage(packageName) {
|
|
61
|
-
def cmdResult = providers.exec {
|
|
62
|
-
commandLine "node", "-e", "console.log(require.resolve('${packageName}/package.json'))"
|
|
63
|
-
ignoreExitValue = true
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (cmdResult.result.get().exitValue == 0) {
|
|
67
|
-
def packageJsonPath = cmdResult.standardOutput.asText.get().trim()
|
|
68
|
-
return new File(packageJsonPath).parent
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Fallback: walk up directories looking for node_modules
|
|
72
|
-
def basePath = projectDir.toPath().normalize()
|
|
73
|
-
while (basePath) {
|
|
74
|
-
def candidate = Paths.get(basePath.toString(), "node_modules", packageName)
|
|
75
|
-
if (candidate.toFile().exists() && new File(candidate.toString(), "package.json").exists()) {
|
|
76
|
-
return candidate.toString()
|
|
77
|
-
}
|
|
78
|
-
basePath = basePath.getParent()
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
throw new GradleException("React-Native-Skia: Could not find ${packageName}. Make sure you have run 'yarn install' or 'npm install'.")
|
|
82
|
-
}
|
|
83
|
-
|
|
84
59
|
def nodeModules = findNodeModules(projectDir)
|
|
85
60
|
|
|
86
|
-
//
|
|
87
|
-
|
|
88
|
-
def
|
|
89
|
-
def
|
|
90
|
-
def skiaLibsPath = "${skiaAndroidPackage}/libs"
|
|
61
|
+
// Skia prebuilt libs are copied into libs/android/ by the npm postinstall script
|
|
62
|
+
// Graphite is detected via marker file created by install-skia-graphite
|
|
63
|
+
def useGraphite = file("${projectDir}/../libs/.graphite").exists()
|
|
64
|
+
def skiaLibsPath = "${projectDir}/../libs/android"
|
|
91
65
|
|
|
92
66
|
logger.warn("react-native-skia: SK_GRAPHITE: ${useGraphite}")
|
|
93
|
-
logger.warn("react-native-skia: Skia
|
|
67
|
+
logger.warn("react-native-skia: Skia libs: ${skiaLibsPath}")
|
|
94
68
|
logger.warn("react-native-skia: node_modules/ found at: ${nodeModules}")
|
|
95
69
|
|
|
96
70
|
def sourceBuild = false
|
|
@@ -292,7 +266,6 @@ repositories {
|
|
|
292
266
|
}
|
|
293
267
|
}
|
|
294
268
|
google()
|
|
295
|
-
maven { url 'https://www.jitpack.io' }
|
|
296
269
|
}
|
|
297
270
|
|
|
298
271
|
dependencies {
|
|
@@ -58,7 +58,8 @@ public:
|
|
|
58
58
|
return instance;
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
sk_sp<SkSurface> MakeOffscreen(int width, int height
|
|
61
|
+
sk_sp<SkSurface> MakeOffscreen(int width, int height,
|
|
62
|
+
bool useP3ColorSpace = false) {
|
|
62
63
|
auto colorType = kRGBA_8888_SkColorType;
|
|
63
64
|
|
|
64
65
|
SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
|
|
@@ -89,10 +90,16 @@ public:
|
|
|
89
90
|
auto releaseCtx = new ReleaseContext{.directContext = _directContext.get(),
|
|
90
91
|
.texture = texture};
|
|
91
92
|
|
|
93
|
+
sk_sp<SkColorSpace> colorSpace =
|
|
94
|
+
useP3ColorSpace
|
|
95
|
+
? SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB,
|
|
96
|
+
SkNamedGamut::kDisplayP3)
|
|
97
|
+
: nullptr;
|
|
98
|
+
|
|
92
99
|
// Create a SkSurface from the GrBackendTexture
|
|
93
100
|
return SkSurfaces::WrapBackendTexture(
|
|
94
101
|
_directContext.get(), texture, kTopLeft_GrSurfaceOrigin, 0, colorType,
|
|
95
|
-
|
|
102
|
+
colorSpace, &props,
|
|
96
103
|
[](void *addr) {
|
|
97
104
|
auto releaseCtx = reinterpret_cast<ReleaseContext *>(addr);
|
|
98
105
|
releaseCtx->directContext->deleteBackendTexture(releaseCtx->texture);
|
|
@@ -50,11 +50,14 @@ public:
|
|
|
50
50
|
_jniPlatformContext->raiseError(err);
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
sk_sp<SkSurface> makeOffscreenSurface(int width, int height
|
|
53
|
+
sk_sp<SkSurface> makeOffscreenSurface(int width, int height,
|
|
54
|
+
bool useP3ColorSpace = false) override {
|
|
54
55
|
#if defined(SK_GRAPHITE)
|
|
55
|
-
return DawnContext::getInstance().MakeOffscreen(width, height
|
|
56
|
+
return DawnContext::getInstance().MakeOffscreen(width, height,
|
|
57
|
+
useP3ColorSpace);
|
|
56
58
|
#else
|
|
57
|
-
return OpenGLContext::getInstance().MakeOffscreen(width, height
|
|
59
|
+
return OpenGLContext::getInstance().MakeOffscreen(width, height,
|
|
60
|
+
useP3ColorSpace);
|
|
58
61
|
#endif
|
|
59
62
|
}
|
|
60
63
|
|
package/apple/MetalContext.h
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
#import <include/gpu/ganesh/mtl/GrMtlBackendSurface.h>
|
|
14
14
|
#import <include/gpu/ganesh/mtl/GrMtlDirectContext.h>
|
|
15
15
|
#import <include/gpu/ganesh/mtl/SkSurfaceMetal.h>
|
|
16
|
+
#include "include/core/SkColorSpace.h"
|
|
16
17
|
|
|
17
18
|
struct OffscreenRenderContext {
|
|
18
19
|
id<MTLTexture> texture;
|
|
@@ -44,7 +45,8 @@ public:
|
|
|
44
45
|
return instance;
|
|
45
46
|
}
|
|
46
47
|
|
|
47
|
-
sk_sp<SkSurface> MakeOffscreen(int width, int height
|
|
48
|
+
sk_sp<SkSurface> MakeOffscreen(int width, int height,
|
|
49
|
+
bool useP3ColorSpace = false) {
|
|
48
50
|
auto device = _device;
|
|
49
51
|
auto ctx = new OffscreenRenderContext(device, _directContext, _commandQueue,
|
|
50
52
|
width, height);
|
|
@@ -55,10 +57,16 @@ public:
|
|
|
55
57
|
GrBackendTexture backendTexture =
|
|
56
58
|
GrBackendTextures::MakeMtl(width, height, skgpu::Mipmapped::kNo, info);
|
|
57
59
|
|
|
60
|
+
sk_sp<SkColorSpace> colorSpace =
|
|
61
|
+
useP3ColorSpace
|
|
62
|
+
? SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB,
|
|
63
|
+
SkNamedGamut::kDisplayP3)
|
|
64
|
+
: nullptr;
|
|
65
|
+
|
|
58
66
|
// Create a SkSurface from the GrBackendTexture
|
|
59
67
|
auto surface = SkSurfaces::WrapBackendTexture(
|
|
60
68
|
_directContext.get(), backendTexture, kTopLeft_GrSurfaceOrigin, 0,
|
|
61
|
-
kBGRA_8888_SkColorType,
|
|
69
|
+
kBGRA_8888_SkColorType, colorSpace, nullptr,
|
|
62
70
|
[](void *addr) { delete (OffscreenRenderContext *)addr; }, ctx);
|
|
63
71
|
|
|
64
72
|
return surface;
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
#include "MetalContext.h"
|
|
4
4
|
#include "RNSkLog.h"
|
|
5
|
+
#include "include/core/SkColorSpace.h"
|
|
5
6
|
|
|
6
7
|
MetalWindowContext::MetalWindowContext(GrDirectContext *directContext,
|
|
7
8
|
id<MTLDevice> device,
|
|
@@ -46,6 +47,7 @@ MetalWindowContext::MetalWindowContext(GrDirectContext *directContext,
|
|
|
46
47
|
CGColorSpaceCreateWithName(kCGColorSpaceDisplayP3);
|
|
47
48
|
_layer.colorspace = colorSpace;
|
|
48
49
|
CGColorSpaceRelease(colorSpace);
|
|
50
|
+
_useP3ColorSpace = true;
|
|
49
51
|
}
|
|
50
52
|
}
|
|
51
53
|
|
|
@@ -69,9 +71,14 @@ sk_sp<SkSurface> MetalWindowContext::getSurface() {
|
|
|
69
71
|
GrBackendRenderTarget backendRT = GrBackendRenderTargets::MakeMtl(
|
|
70
72
|
_layer.drawableSize.width, _layer.drawableSize.height, fbInfo);
|
|
71
73
|
|
|
74
|
+
sk_sp<SkColorSpace> skColorSpace =
|
|
75
|
+
_useP3ColorSpace
|
|
76
|
+
? SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB,
|
|
77
|
+
SkNamedGamut::kDisplayP3)
|
|
78
|
+
: nullptr;
|
|
72
79
|
_skSurface = SkSurfaces::WrapBackendRenderTarget(
|
|
73
80
|
_directContext, backendRT, kTopLeft_GrSurfaceOrigin,
|
|
74
|
-
kBGRA_8888_SkColorType,
|
|
81
|
+
kBGRA_8888_SkColorType, skColorSpace, nullptr);
|
|
75
82
|
|
|
76
83
|
return _skSurface;
|
|
77
84
|
}
|
|
@@ -69,7 +69,8 @@ public:
|
|
|
69
69
|
const std::function<void(std::unique_ptr<SkStreamAsset>)> &op) override;
|
|
70
70
|
|
|
71
71
|
void raiseError(const std::exception &err) override;
|
|
72
|
-
sk_sp<SkSurface> makeOffscreenSurface(int width, int height
|
|
72
|
+
sk_sp<SkSurface> makeOffscreenSurface(int width, int height,
|
|
73
|
+
bool useP3ColorSpace = false) override;
|
|
73
74
|
|
|
74
75
|
sk_sp<SkFontMgr> createFontMgr() override;
|
|
75
76
|
|
|
@@ -251,12 +251,14 @@ void RNSkApplePlatformContext::raiseError(const std::exception &err) {
|
|
|
251
251
|
RCTFatal(RCTErrorWithMessage([NSString stringWithUTF8String:err.what()]));
|
|
252
252
|
}
|
|
253
253
|
|
|
254
|
-
sk_sp<SkSurface> RNSkApplePlatformContext::makeOffscreenSurface(
|
|
255
|
-
|
|
254
|
+
sk_sp<SkSurface> RNSkApplePlatformContext::makeOffscreenSurface(
|
|
255
|
+
int width, int height, bool useP3ColorSpace) {
|
|
256
256
|
#if defined(SK_GRAPHITE)
|
|
257
|
-
return DawnContext::getInstance().MakeOffscreen(width, height
|
|
257
|
+
return DawnContext::getInstance().MakeOffscreen(width, height,
|
|
258
|
+
useP3ColorSpace);
|
|
258
259
|
#else
|
|
259
|
-
return MetalContext::getInstance().MakeOffscreen(width, height
|
|
260
|
+
return MetalContext::getInstance().MakeOffscreen(width, height,
|
|
261
|
+
useP3ColorSpace);
|
|
260
262
|
#endif
|
|
261
263
|
}
|
|
262
264
|
|
package/apple/SkiaPictureView.mm
CHANGED
|
@@ -58,6 +58,9 @@ using namespace facebook::react;
|
|
|
58
58
|
if (newProps.colorSpace == "" || newProps.colorSpace == "srgb") {
|
|
59
59
|
bool useP3 = false;
|
|
60
60
|
[self setUseP3ColorSpace:useP3];
|
|
61
|
+
} else if (newProps.colorSpace == "p3") {
|
|
62
|
+
bool useP3 = true;
|
|
63
|
+
[self setUseP3ColorSpace:useP3];
|
|
61
64
|
}
|
|
62
65
|
}
|
|
63
66
|
|
package/cpp/api/JsiSkImage.h
CHANGED
|
@@ -35,6 +35,75 @@
|
|
|
35
35
|
|
|
36
36
|
#include <jsi/jsi.h>
|
|
37
37
|
|
|
38
|
+
#ifdef __APPLE__
|
|
39
|
+
#include <CoreFoundation/CoreFoundation.h>
|
|
40
|
+
#include <CoreGraphics/CoreGraphics.h>
|
|
41
|
+
#include <cstring>
|
|
42
|
+
|
|
43
|
+
// Replaces Skia's generated "Display P3 Gamut with sRGB Transfer" (Google/Skia
|
|
44
|
+
// copyright) ICC profile in a JPEG with Apple's canonical Display P3 ICC bytes
|
|
45
|
+
// from CGColorSpace.displayP3. This is needed because apps like Instagram only
|
|
46
|
+
// recognise the canonical Apple profile, not Skia's mathematically equivalent
|
|
47
|
+
// but non-standard one. Pixel values are untouched — zero quality loss.
|
|
48
|
+
static sk_sp<SkData> replaceJpegICCWithAppleP3(sk_sp<SkData> jpegData) {
|
|
49
|
+
if (!jpegData || jpegData->size() < 4) return jpegData;
|
|
50
|
+
|
|
51
|
+
const uint8_t *src = jpegData->bytes();
|
|
52
|
+
size_t srcLen = jpegData->size();
|
|
53
|
+
if (src[0] != 0xFF || src[1] != 0xD8) return jpegData; // not a JPEG
|
|
54
|
+
|
|
55
|
+
CGColorSpaceRef p3 = CGColorSpaceCreateWithName(kCGColorSpaceDisplayP3);
|
|
56
|
+
if (!p3) return jpegData;
|
|
57
|
+
CFDataRef cfICC = CGColorSpaceCopyICCData(p3);
|
|
58
|
+
CGColorSpaceRelease(p3);
|
|
59
|
+
if (!cfICC) return jpegData;
|
|
60
|
+
|
|
61
|
+
const uint8_t *iccBytes = CFDataGetBytePtr(cfICC);
|
|
62
|
+
size_t iccLen = (size_t)CFDataGetLength(cfICC);
|
|
63
|
+
|
|
64
|
+
// "ICC_PROFILE\0" APP2 marker signature (12 bytes)
|
|
65
|
+
static const uint8_t iccSig[] = {0x49, 0x43, 0x43, 0x5F, 0x50, 0x52,
|
|
66
|
+
0x4F, 0x46, 0x49, 0x4C, 0x45, 0x00};
|
|
67
|
+
|
|
68
|
+
SkDynamicMemoryWStream out;
|
|
69
|
+
|
|
70
|
+
out.write(src, 2); // SOI
|
|
71
|
+
|
|
72
|
+
// Structure: marker(2) + length(2) + "ICC_PROFILE\0"(12) + chunk[1,1](2) + profile
|
|
73
|
+
size_t iccContentLen = sizeof(iccSig) + 2 + iccLen;
|
|
74
|
+
size_t segLen = iccContentLen + 2; // length field includes itself
|
|
75
|
+
uint8_t app2hdr[4] = {0xFF, 0xE2, (uint8_t)(segLen >> 8),
|
|
76
|
+
(uint8_t)(segLen & 0xFF)};
|
|
77
|
+
uint8_t chunkInfo[2] = {0x01, 0x01}; // chunk 1 of 1
|
|
78
|
+
out.write(app2hdr, 4);
|
|
79
|
+
out.write(iccSig, sizeof(iccSig));
|
|
80
|
+
out.write(chunkInfo, 2);
|
|
81
|
+
out.write(iccBytes, iccLen);
|
|
82
|
+
|
|
83
|
+
// Copy all header segments except any existing ICC APP2
|
|
84
|
+
size_t i = 2;
|
|
85
|
+
while (i + 3 < srcLen) {
|
|
86
|
+
if (src[i] != 0xFF) break;
|
|
87
|
+
uint8_t marker = src[i + 1];
|
|
88
|
+
if (marker == 0xDA || marker == 0xD9) break; // SOS / EOI
|
|
89
|
+
size_t segLenVal = (size_t(src[i + 2]) << 8) | src[i + 3];
|
|
90
|
+
size_t end = i + 2 + segLenVal;
|
|
91
|
+
if (end > srcLen) break;
|
|
92
|
+
bool isICC = marker == 0xE2 && end > i + 4 + sizeof(iccSig) &&
|
|
93
|
+
memcmp(src + i + 4, iccSig, sizeof(iccSig)) == 0;
|
|
94
|
+
if (!isICC) {
|
|
95
|
+
out.write(src + i, end - i);
|
|
96
|
+
}
|
|
97
|
+
i = end;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
out.write(src + i, srcLen - i);
|
|
101
|
+
|
|
102
|
+
CFRelease(cfICC);
|
|
103
|
+
return out.detachAsData();
|
|
104
|
+
}
|
|
105
|
+
#endif // __APPLE__
|
|
106
|
+
|
|
38
107
|
namespace RNSkia {
|
|
39
108
|
|
|
40
109
|
namespace jsi = facebook::jsi;
|
|
@@ -138,6 +207,13 @@ public:
|
|
|
138
207
|
SkJpegEncoder::Options options;
|
|
139
208
|
options.fQuality = quality;
|
|
140
209
|
data = SkJpegEncoder::Encode(nullptr, image.get(), options);
|
|
210
|
+
#ifdef __APPLE__
|
|
211
|
+
// Replace Skia's generated ICC with Apple's canonical Display P3 profile
|
|
212
|
+
// so apps like Instagram recognise the wide-gamut colour space.
|
|
213
|
+
if (data && image->colorSpace() && !image->colorSpace()->isSRGB()) {
|
|
214
|
+
data = replaceJpegICCWithAppleP3(data);
|
|
215
|
+
}
|
|
216
|
+
#endif
|
|
141
217
|
} else if (format == SkEncodedImageFormat::kWEBP) {
|
|
142
218
|
SkWebpEncoder::Options options;
|
|
143
219
|
if (quality >= 100) {
|
|
@@ -39,8 +39,19 @@ public:
|
|
|
39
39
|
JSI_HOST_FUNCTION(MakeOffscreen) {
|
|
40
40
|
auto width = static_cast<int>(arguments[0].asNumber());
|
|
41
41
|
auto height = static_cast<int>(arguments[1].asNumber());
|
|
42
|
+
bool useP3ColorSpace = false;
|
|
43
|
+
if (count >= 3 && arguments[2].isObject()) {
|
|
44
|
+
auto opts = arguments[2].asObject(runtime);
|
|
45
|
+
if (opts.hasProperty(runtime, "colorSpace")) {
|
|
46
|
+
auto colorSpaceVal = opts.getProperty(runtime, "colorSpace");
|
|
47
|
+
if (colorSpaceVal.isString()) {
|
|
48
|
+
useP3ColorSpace =
|
|
49
|
+
colorSpaceVal.asString(runtime).utf8(runtime) == "display-p3";
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
42
53
|
auto context = getContext();
|
|
43
|
-
auto surface = context->makeOffscreenSurface(width, height);
|
|
54
|
+
auto surface = context->makeOffscreenSurface(width, height, useP3ColorSpace);
|
|
44
55
|
if (surface == nullptr) {
|
|
45
56
|
return jsi::Value::null();
|
|
46
57
|
}
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
#include "RNDawnWindowContext.h"
|
|
8
8
|
#include "RNImageProvider.h"
|
|
9
9
|
|
|
10
|
+
#include "include/core/SkColorSpace.h"
|
|
10
11
|
#include "include/core/SkData.h"
|
|
11
12
|
#include "include/gpu/graphite/BackendTexture.h"
|
|
12
13
|
#include "include/gpu/graphite/Context.h"
|
|
@@ -162,9 +163,16 @@ public:
|
|
|
162
163
|
}
|
|
163
164
|
|
|
164
165
|
// Create offscreen surface
|
|
165
|
-
sk_sp<SkSurface> MakeOffscreen(int width, int height
|
|
166
|
+
sk_sp<SkSurface> MakeOffscreen(int width, int height,
|
|
167
|
+
bool useP3ColorSpace = false) {
|
|
168
|
+
sk_sp<SkColorSpace> colorSpace =
|
|
169
|
+
useP3ColorSpace
|
|
170
|
+
? SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB,
|
|
171
|
+
SkNamedGamut::kDisplayP3)
|
|
172
|
+
: nullptr;
|
|
166
173
|
SkImageInfo info = SkImageInfo::Make(
|
|
167
|
-
width, height, DawnUtils::PreferedColorType, kPremul_SkAlphaType
|
|
174
|
+
width, height, DawnUtils::PreferedColorType, kPremul_SkAlphaType,
|
|
175
|
+
colorSpace);
|
|
168
176
|
sk_sp<SkSurface> surface = SkSurfaces::RenderTarget(getRecorder(), info);
|
|
169
177
|
|
|
170
178
|
if (!surface) {
|
|
@@ -303,6 +311,20 @@ public:
|
|
|
303
311
|
getRecorder(), backendContext.fDevice, surface, width, height);
|
|
304
312
|
}
|
|
305
313
|
|
|
314
|
+
skgpu::graphite::Recorder *getRecorder() {
|
|
315
|
+
static thread_local skgpu::graphite::RecorderOptions recorderOptions;
|
|
316
|
+
if (!recorderOptions.fImageProvider) {
|
|
317
|
+
auto imageProvider = ImageProvider::Make();
|
|
318
|
+
recorderOptions.fImageProvider = imageProvider;
|
|
319
|
+
}
|
|
320
|
+
static thread_local auto recorder =
|
|
321
|
+
fGraphiteContext->makeRecorder(recorderOptions);
|
|
322
|
+
if (!recorder) {
|
|
323
|
+
throw std::runtime_error("Failed to create graphite context");
|
|
324
|
+
}
|
|
325
|
+
return recorder.get();
|
|
326
|
+
}
|
|
327
|
+
|
|
306
328
|
private:
|
|
307
329
|
std::unique_ptr<dawn::native::Instance> instance;
|
|
308
330
|
std::unique_ptr<skgpu::graphite::Context> fGraphiteContext;
|
|
@@ -346,20 +368,6 @@ private:
|
|
|
346
368
|
backendContext.fTick(backendContext.fInstance);
|
|
347
369
|
}
|
|
348
370
|
}
|
|
349
|
-
|
|
350
|
-
skgpu::graphite::Recorder *getRecorder() {
|
|
351
|
-
static thread_local skgpu::graphite::RecorderOptions recorderOptions;
|
|
352
|
-
if (!recorderOptions.fImageProvider) {
|
|
353
|
-
auto imageProvider = ImageProvider::Make();
|
|
354
|
-
recorderOptions.fImageProvider = imageProvider;
|
|
355
|
-
}
|
|
356
|
-
static thread_local auto recorder =
|
|
357
|
-
fGraphiteContext->makeRecorder(recorderOptions);
|
|
358
|
-
if (!recorder) {
|
|
359
|
-
throw std::runtime_error("Failed to create graphite context");
|
|
360
|
-
}
|
|
361
|
-
return recorder.get();
|
|
362
|
-
}
|
|
363
371
|
};
|
|
364
372
|
|
|
365
373
|
} // namespace RNSkia
|
package/cpp/rnskia/RNDawnUtils.h
CHANGED
|
@@ -177,6 +177,18 @@ createDawnBackendContext(dawn::native::Instance *instance) {
|
|
|
177
177
|
if (adapter.HasFeature(wgpu::FeatureName::SharedTextureMemoryIOSurface)) {
|
|
178
178
|
features.push_back(wgpu::FeatureName::SharedTextureMemoryIOSurface);
|
|
179
179
|
}
|
|
180
|
+
if (adapter.HasFeature(wgpu::FeatureName::DawnMultiPlanarFormats)) {
|
|
181
|
+
features.push_back(wgpu::FeatureName::DawnMultiPlanarFormats);
|
|
182
|
+
}
|
|
183
|
+
if (adapter.HasFeature(wgpu::FeatureName::MultiPlanarFormatP010)) {
|
|
184
|
+
features.push_back(wgpu::FeatureName::MultiPlanarFormatP010);
|
|
185
|
+
}
|
|
186
|
+
if (adapter.HasFeature(wgpu::FeatureName::MultiPlanarFormatP210)) {
|
|
187
|
+
features.push_back(wgpu::FeatureName::MultiPlanarFormatP210);
|
|
188
|
+
}
|
|
189
|
+
if (adapter.HasFeature(wgpu::FeatureName::MultiPlanarFormatExtendedUsages)) {
|
|
190
|
+
features.push_back(wgpu::FeatureName::MultiPlanarFormatExtendedUsages);
|
|
191
|
+
}
|
|
180
192
|
#else
|
|
181
193
|
if (adapter.HasFeature(
|
|
182
194
|
wgpu::FeatureName::SharedTextureMemoryAHardwareBuffer)) {
|
|
@@ -90,9 +90,11 @@ public:
|
|
|
90
90
|
* Creates an offscreen surface
|
|
91
91
|
* @param width Width of the offscreen surface
|
|
92
92
|
* @param height Height of the offscreen surface
|
|
93
|
+
* @param useP3ColorSpace If true, surface will use Display P3 color space
|
|
93
94
|
* @return sk_sp<SkSurface>
|
|
94
95
|
*/
|
|
95
|
-
virtual sk_sp<SkSurface> makeOffscreenSurface(int width, int height
|
|
96
|
+
virtual sk_sp<SkSurface> makeOffscreenSurface(int width, int height,
|
|
97
|
+
bool useP3ColorSpace = false) = 0;
|
|
96
98
|
|
|
97
99
|
virtual std::shared_ptr<WindowContext>
|
|
98
100
|
makeContextFromNativeSurface(void *surface, int width, int height) = 0;
|
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
import type { SkSurface } from "./Surface";
|
|
2
|
+
export declare const ColorSpace: {
|
|
3
|
+
readonly SRGB: "srgb";
|
|
4
|
+
readonly DisplayP3: "display-p3";
|
|
5
|
+
};
|
|
6
|
+
export type ColorSpaceValue = (typeof ColorSpace)[keyof typeof ColorSpace];
|
|
7
|
+
export interface SurfaceOptions {
|
|
8
|
+
colorSpace: ColorSpaceValue;
|
|
9
|
+
}
|
|
2
10
|
export interface SurfaceFactory {
|
|
3
11
|
/**
|
|
4
12
|
* Returns a CPU backed surface with the given dimensions, an SRGB colorspace, Unpremul
|
|
@@ -12,6 +20,7 @@ export interface SurfaceFactory {
|
|
|
12
20
|
* Creates a GPU backed surface.
|
|
13
21
|
* @param width - number of pixels of the width of the drawable area.
|
|
14
22
|
* @param height - number of pixels of the height of the drawable area.
|
|
23
|
+
* @param opts - optional surface options (e.g. colorSpace: "display-p3" | "srgb").
|
|
15
24
|
*/
|
|
16
|
-
MakeOffscreen: (width: number, height: number) => SkSurface | null;
|
|
25
|
+
MakeOffscreen: (width: number, height: number, opts?: SurfaceOptions) => SkSurface | null;
|
|
17
26
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["SurfaceFactory.ts"],"sourcesContent":["import type { SkSurface } from \"./Surface\";\n\nexport interface SurfaceFactory {\n /**\n * Returns a CPU backed surface with the given dimensions, an SRGB colorspace, Unpremul\n * alphaType and 8888 color type. The pixels belonging to this surface will be in memory and\n * not visible.\n * @param width - number of pixels of the width of the drawable area.\n * @param height - number of pixels of the height of the drawable area.\n */\n Make: (width: number, height: number) => SkSurface | null;\n\n /**\n * Creates a GPU backed surface.\n * @param width - number of pixels of the width of the drawable area.\n * @param height - number of pixels of the height of the drawable area.\n */\n MakeOffscreen: (width: number, height: number) => SkSurface | null;\n}\n"],"mappings":"","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":["ColorSpace","exports","SRGB","DisplayP3"],"sources":["SurfaceFactory.ts"],"sourcesContent":["import type { SkSurface } from \"./Surface\";\n\nexport const ColorSpace = {\n SRGB: \"srgb\",\n DisplayP3: \"display-p3\",\n} as const;\n\nexport type ColorSpaceValue = (typeof ColorSpace)[keyof typeof ColorSpace];\n\nexport interface SurfaceOptions {\n colorSpace: ColorSpaceValue;\n}\n\nexport interface SurfaceFactory {\n /**\n * Returns a CPU backed surface with the given dimensions, an SRGB colorspace, Unpremul\n * alphaType and 8888 color type. The pixels belonging to this surface will be in memory and\n * not visible.\n * @param width - number of pixels of the width of the drawable area.\n * @param height - number of pixels of the height of the drawable area.\n */\n Make: (width: number, height: number) => SkSurface | null;\n\n /**\n * Creates a GPU backed surface.\n * @param width - number of pixels of the width of the drawable area.\n * @param height - number of pixels of the height of the drawable area.\n * @param opts - optional surface options (e.g. colorSpace: \"display-p3\" | \"srgb\").\n */\n MakeOffscreen: (width: number, height: number, opts?: SurfaceOptions) => SkSurface | null;\n}\n"],"mappings":";;;;;;AAEO,MAAMA,UAAU,GAAAC,OAAA,CAAAD,UAAA,GAAG;EACxBE,IAAI,EAAE,MAAM;EACZC,SAAS,EAAE;AACb,CAAU","ignoreList":[]}
|
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
import type { SkSurface } from "./Surface";
|
|
2
|
+
export declare const ColorSpace: {
|
|
3
|
+
readonly SRGB: "srgb";
|
|
4
|
+
readonly DisplayP3: "display-p3";
|
|
5
|
+
};
|
|
6
|
+
export type ColorSpaceValue = (typeof ColorSpace)[keyof typeof ColorSpace];
|
|
7
|
+
export interface SurfaceOptions {
|
|
8
|
+
colorSpace: ColorSpaceValue;
|
|
9
|
+
}
|
|
2
10
|
export interface SurfaceFactory {
|
|
3
11
|
/**
|
|
4
12
|
* Returns a CPU backed surface with the given dimensions, an SRGB colorspace, Unpremul
|
|
@@ -12,6 +20,7 @@ export interface SurfaceFactory {
|
|
|
12
20
|
* Creates a GPU backed surface.
|
|
13
21
|
* @param width - number of pixels of the width of the drawable area.
|
|
14
22
|
* @param height - number of pixels of the height of the drawable area.
|
|
23
|
+
* @param opts - optional surface options (e.g. colorSpace: "display-p3" | "srgb").
|
|
15
24
|
*/
|
|
16
|
-
MakeOffscreen: (width: number, height: number) => SkSurface | null;
|
|
25
|
+
MakeOffscreen: (width: number, height: number, opts?: SurfaceOptions) => SkSurface | null;
|
|
17
26
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["SurfaceFactory.ts"],"sourcesContent":["import type { SkSurface } from \"./Surface\";\n\nexport interface SurfaceFactory {\n /**\n * Returns a CPU backed surface with the given dimensions, an SRGB colorspace, Unpremul\n * alphaType and 8888 color type. The pixels belonging to this surface will be in memory and\n * not visible.\n * @param width - number of pixels of the width of the drawable area.\n * @param height - number of pixels of the height of the drawable area.\n */\n Make: (width: number, height: number) => SkSurface | null;\n\n /**\n * Creates a GPU backed surface.\n * @param width - number of pixels of the width of the drawable area.\n * @param height - number of pixels of the height of the drawable area.\n */\n MakeOffscreen: (width: number, height: number) => SkSurface | null;\n}\n"],"mappings":"","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":["ColorSpace","SRGB","DisplayP3"],"sources":["SurfaceFactory.ts"],"sourcesContent":["import type { SkSurface } from \"./Surface\";\n\nexport const ColorSpace = {\n SRGB: \"srgb\",\n DisplayP3: \"display-p3\",\n} as const;\n\nexport type ColorSpaceValue = (typeof ColorSpace)[keyof typeof ColorSpace];\n\nexport interface SurfaceOptions {\n colorSpace: ColorSpaceValue;\n}\n\nexport interface SurfaceFactory {\n /**\n * Returns a CPU backed surface with the given dimensions, an SRGB colorspace, Unpremul\n * alphaType and 8888 color type. The pixels belonging to this surface will be in memory and\n * not visible.\n * @param width - number of pixels of the width of the drawable area.\n * @param height - number of pixels of the height of the drawable area.\n */\n Make: (width: number, height: number) => SkSurface | null;\n\n /**\n * Creates a GPU backed surface.\n * @param width - number of pixels of the width of the drawable area.\n * @param height - number of pixels of the height of the drawable area.\n * @param opts - optional surface options (e.g. colorSpace: \"display-p3\" | \"srgb\").\n */\n MakeOffscreen: (width: number, height: number, opts?: SurfaceOptions) => SkSurface | null;\n}\n"],"mappings":"AAEA,OAAO,MAAMA,UAAU,GAAG;EACxBC,IAAI,EAAE,MAAM;EACZC,SAAS,EAAE;AACb,CAAU","ignoreList":[]}
|
|
@@ -193,6 +193,10 @@ export function Mock(CanvasKit: any): {
|
|
|
193
193
|
rrect: (r: any, rx: any, ry: any) => import("../../..").SkRRect;
|
|
194
194
|
processTransform2d: (transforms: any) => any;
|
|
195
195
|
isRNModule: (mod: any) => mod is number;
|
|
196
|
+
ColorSpace: {
|
|
197
|
+
SRGB: string;
|
|
198
|
+
DisplayP3: string;
|
|
199
|
+
};
|
|
196
200
|
VertexMode: {};
|
|
197
201
|
isShader: (obj: any) => boolean;
|
|
198
202
|
processUniforms: (source: any, uniforms: any, builder: any) => any[];
|
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
import type { SkSurface } from "./Surface";
|
|
2
|
+
export declare const ColorSpace: {
|
|
3
|
+
readonly SRGB: "srgb";
|
|
4
|
+
readonly DisplayP3: "display-p3";
|
|
5
|
+
};
|
|
6
|
+
export type ColorSpaceValue = (typeof ColorSpace)[keyof typeof ColorSpace];
|
|
7
|
+
export interface SurfaceOptions {
|
|
8
|
+
colorSpace: ColorSpaceValue;
|
|
9
|
+
}
|
|
2
10
|
export interface SurfaceFactory {
|
|
3
11
|
/**
|
|
4
12
|
* Returns a CPU backed surface with the given dimensions, an SRGB colorspace, Unpremul
|
|
@@ -12,6 +20,7 @@ export interface SurfaceFactory {
|
|
|
12
20
|
* Creates a GPU backed surface.
|
|
13
21
|
* @param width - number of pixels of the width of the drawable area.
|
|
14
22
|
* @param height - number of pixels of the height of the drawable area.
|
|
23
|
+
* @param opts - optional surface options (e.g. colorSpace: "display-p3" | "srgb").
|
|
15
24
|
*/
|
|
16
|
-
MakeOffscreen: (width: number, height: number) => SkSurface | null;
|
|
25
|
+
MakeOffscreen: (width: number, height: number, opts?: SurfaceOptions) => SkSurface | null;
|
|
17
26
|
}
|
package/package.json
CHANGED
|
@@ -5,10 +5,11 @@
|
|
|
5
5
|
"provenance": true
|
|
6
6
|
},
|
|
7
7
|
"bin": {
|
|
8
|
+
"install-skia": "scripts/install-libs.js",
|
|
8
9
|
"setup-skia-web": "scripts/setup-canvaskit.js"
|
|
9
10
|
},
|
|
10
11
|
"title": "React Native Skia",
|
|
11
|
-
"version": "2.5.
|
|
12
|
+
"version": "2.5.2",
|
|
12
13
|
"description": "High-performance React Native Graphics using Skia",
|
|
13
14
|
"main": "lib/module/index.js",
|
|
14
15
|
"react-native": "src/index.ts",
|
|
@@ -16,6 +17,7 @@
|
|
|
16
17
|
"types": "lib/typescript/index.d.ts",
|
|
17
18
|
"files": [
|
|
18
19
|
"scripts/setup-canvaskit.js",
|
|
20
|
+
"scripts/install-libs.js",
|
|
19
21
|
"src/**",
|
|
20
22
|
"lib/**",
|
|
21
23
|
"!**/__tests__/**",
|
|
@@ -35,6 +37,7 @@
|
|
|
35
37
|
"dist/**"
|
|
36
38
|
],
|
|
37
39
|
"scripts": {
|
|
40
|
+
"postinstall": "node scripts/install-libs.js",
|
|
38
41
|
"lint": "eslint . --ext .ts,.tsx --max-warnings 0 --cache --fix",
|
|
39
42
|
"tsc": "tsc --noEmit",
|
|
40
43
|
"test": "jest",
|
|
@@ -117,7 +120,7 @@
|
|
|
117
120
|
"rimraf": "3.0.2",
|
|
118
121
|
"semantic-release": "^24.1.0",
|
|
119
122
|
"semantic-release-yarn": "^3.0.2",
|
|
120
|
-
"tar": "^7.5.
|
|
123
|
+
"tar": "^7.5.11",
|
|
121
124
|
"ts-jest": "29.4.3",
|
|
122
125
|
"tsx": "^4.21.0",
|
|
123
126
|
"typescript": "^5.2.2",
|
|
@@ -4,14 +4,9 @@ require "json"
|
|
|
4
4
|
|
|
5
5
|
package = JSON.parse(File.read(File.join(__dir__, "package.json")))
|
|
6
6
|
|
|
7
|
-
# Check if Graphite is enabled
|
|
8
|
-
use_graphite =
|
|
9
|
-
|
|
10
|
-
use_graphite = ENV['SK_GRAPHITE'] == '1' || ENV['SK_GRAPHITE'].downcase == 'true'
|
|
11
|
-
puts "-- SK_GRAPHITE: using environment variable (#{use_graphite ? 'ON' : 'OFF'})"
|
|
12
|
-
else
|
|
13
|
-
puts "-- SK_GRAPHITE: OFF (set SK_GRAPHITE=1 to enable)"
|
|
14
|
-
end
|
|
7
|
+
# Check if Graphite is enabled via marker file (created by install-skia-graphite)
|
|
8
|
+
use_graphite = File.exist?(File.join(__dir__, 'libs', '.graphite'))
|
|
9
|
+
puts "-- SK_GRAPHITE: #{use_graphite ? 'ON' : 'OFF'} (detected via libs/.graphite marker file)"
|
|
15
10
|
|
|
16
11
|
# Set preprocessor definitions based on GRAPHITE flag
|
|
17
12
|
preprocessor_defs = use_graphite ?
|
|
@@ -23,86 +18,28 @@ framework_names = ['libskia', 'libsvg', 'libskshaper', 'libskparagraph',
|
|
|
23
18
|
'libskunicode_core', 'libskunicode_libgrapheme',
|
|
24
19
|
'libskottie', 'libsksg']
|
|
25
20
|
|
|
21
|
+
# Verify that prebuilt binaries have been installed by the postinstall script
|
|
22
|
+
unless Dir.exist?(File.join(__dir__, 'libs', 'ios')) && Dir.exist?(File.join(__dir__, 'libs', 'macos'))
|
|
23
|
+
Pod::UI.warn "#{'-' * 72}"
|
|
24
|
+
Pod::UI.warn "react-native-skia: Skia prebuilt binaries not found in libs/!"
|
|
25
|
+
Pod::UI.warn ""
|
|
26
|
+
Pod::UI.warn "Run the following command to install them:"
|
|
27
|
+
Pod::UI.warn " npx install-skia"
|
|
28
|
+
Pod::UI.warn "#{'-' * 72}"
|
|
29
|
+
raise "react-native-skia: Skia prebuilt binaries not found. Run `npx install-skia` to fix this."
|
|
30
|
+
end
|
|
31
|
+
|
|
26
32
|
# Build platform-specific framework paths (relative to pod's libs directory)
|
|
33
|
+
# xcframeworks are copied into libs/ by the npm postinstall script (scripts/install-libs.js)
|
|
27
34
|
ios_frameworks = framework_names.map { |f| "libs/ios/#{f}.xcframework" }
|
|
28
35
|
osx_frameworks = framework_names.map { |f| "libs/macos/#{f}.xcframework" }
|
|
29
|
-
# tvOS frameworks -
|
|
36
|
+
# tvOS frameworks - check if libs/tvos/ exists (populated by postinstall before pod install runs)
|
|
30
37
|
tvos_frameworks = if use_graphite || !Dir.exist?(File.join(__dir__, 'libs', 'tvos'))
|
|
31
38
|
[]
|
|
32
39
|
else
|
|
33
40
|
framework_names.map { |f| "libs/tvos/#{f}.xcframework" }
|
|
34
41
|
end
|
|
35
42
|
|
|
36
|
-
# Prepare command resolves paths at RUNTIME (not evaluation time) to ensure deterministic checksums
|
|
37
|
-
# This script:
|
|
38
|
-
# 1. Checks if xcframeworks are already installed (e.g., from Graphite script)
|
|
39
|
-
# 2. If not, resolves npm package paths and copies xcframeworks
|
|
40
|
-
# The script content is deterministic - no machine-specific paths embedded in the podspec
|
|
41
|
-
prepare_command_script = <<-'SCRIPT'
|
|
42
|
-
node -e "
|
|
43
|
-
const path = require('path');
|
|
44
|
-
const fs = require('fs');
|
|
45
|
-
const { execSync } = require('child_process');
|
|
46
|
-
|
|
47
|
-
const iosLibs = 'libs/ios';
|
|
48
|
-
const macosLibs = 'libs/macos';
|
|
49
|
-
|
|
50
|
-
// Check if xcframeworks are already installed
|
|
51
|
-
const hasIos = fs.existsSync(iosLibs) && fs.readdirSync(iosLibs).some(f => f.endsWith('.xcframework'));
|
|
52
|
-
const hasMacos = fs.existsSync(macosLibs) && fs.readdirSync(macosLibs).some(f => f.endsWith('.xcframework'));
|
|
53
|
-
|
|
54
|
-
if (hasIos && hasMacos) {
|
|
55
|
-
console.log('-- Using pre-installed xcframeworks from libs/');
|
|
56
|
-
process.exit(0);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Determine package prefix based on SK_GRAPHITE env var
|
|
60
|
-
const useGraphite = process.env.SK_GRAPHITE === '1' || (process.env.SK_GRAPHITE || '').toLowerCase() === 'true';
|
|
61
|
-
const prefix = useGraphite ? 'react-native-skia-graphite' : 'react-native-skia';
|
|
62
|
-
|
|
63
|
-
// Resolve package paths
|
|
64
|
-
let iosPackage, macosPackage, tvosPackage;
|
|
65
|
-
try {
|
|
66
|
-
iosPackage = path.dirname(require.resolve(prefix + '-apple-ios/package.json'));
|
|
67
|
-
macosPackage = path.dirname(require.resolve(prefix + '-apple-macos/package.json'));
|
|
68
|
-
} catch (e) {
|
|
69
|
-
console.error('ERROR: Could not find ' + prefix + '-apple-ios or ' + prefix + '-apple-macos');
|
|
70
|
-
console.error('Make sure you have run yarn install or npm install');
|
|
71
|
-
process.exit(1);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// Verify xcframeworks exist in the packages
|
|
75
|
-
const iosXcf = path.join(iosPackage, 'libs');
|
|
76
|
-
if (!fs.existsSync(iosXcf) || !fs.readdirSync(iosXcf).some(f => f.endsWith('.xcframework'))) {
|
|
77
|
-
console.error('ERROR: Skia prebuilt binaries not found in ' + prefix + '-apple-ios!');
|
|
78
|
-
process.exit(1);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
console.log('-- Skia iOS package: ' + iosPackage);
|
|
82
|
-
console.log('-- Skia macOS package: ' + macosPackage);
|
|
83
|
-
|
|
84
|
-
// Clean and copy
|
|
85
|
-
execSync('rm -rf libs/ios libs/macos libs/tvos', { stdio: 'inherit' });
|
|
86
|
-
execSync('mkdir -p libs/ios libs/macos', { stdio: 'inherit' });
|
|
87
|
-
execSync('cp -R \"' + iosPackage + '/libs/\"*.xcframework libs/ios/', { stdio: 'inherit' });
|
|
88
|
-
execSync('cp -R \"' + macosPackage + '/libs/\"*.xcframework libs/macos/', { stdio: 'inherit' });
|
|
89
|
-
|
|
90
|
-
// Handle tvOS (non-Graphite only)
|
|
91
|
-
if (!useGraphite) {
|
|
92
|
-
try {
|
|
93
|
-
tvosPackage = path.dirname(require.resolve(prefix + '-apple-tvos/package.json'));
|
|
94
|
-
console.log('-- Skia tvOS package: ' + tvosPackage);
|
|
95
|
-
execSync('mkdir -p libs/tvos', { stdio: 'inherit' });
|
|
96
|
-
execSync('cp -R \"' + tvosPackage + '/libs/\"*.xcframework libs/tvos/', { stdio: 'inherit' });
|
|
97
|
-
} catch (e) {
|
|
98
|
-
console.log('-- tvOS package not found, skipping');
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
console.log('-- Copied xcframeworks from npm packages');
|
|
103
|
-
"
|
|
104
|
-
SCRIPT
|
|
105
|
-
|
|
106
43
|
Pod::Spec.new do |s|
|
|
107
44
|
s.name = "react-native-skia"
|
|
108
45
|
s.version = package["version"]
|
|
@@ -120,10 +57,6 @@ Pod::Spec.new do |s|
|
|
|
120
57
|
s.platforms = { :ios => "14.0", :tvos => "13.0", :osx => "11" }
|
|
121
58
|
s.source = { :git => "https://github.com/shopify/react-native-skia/react-native-skia.git", :tag => "#{s.version}" }
|
|
122
59
|
|
|
123
|
-
# Copy xcframeworks from npm packages into pod directory structure
|
|
124
|
-
# The script is deterministic - path resolution happens at runtime, not evaluation time
|
|
125
|
-
s.prepare_command = prepare_command_script
|
|
126
|
-
|
|
127
60
|
s.requires_arc = true
|
|
128
61
|
s.pod_target_xcconfig = {
|
|
129
62
|
'GCC_PREPROCESSOR_DEFINITIONS' => preprocessor_defs,
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
const path = require("path");
|
|
5
|
+
const fs = require("fs");
|
|
6
|
+
const { execSync } = require("child_process");
|
|
7
|
+
|
|
8
|
+
const useGraphite =
|
|
9
|
+
process.env.SK_GRAPHITE === "1" ||
|
|
10
|
+
(process.env.SK_GRAPHITE || "").toLowerCase() === "true";
|
|
11
|
+
const prefix = useGraphite ? "react-native-skia-graphite" : "react-native-skia";
|
|
12
|
+
const libsDir = path.join(__dirname, "..", "libs");
|
|
13
|
+
|
|
14
|
+
// --- Apple platforms ---
|
|
15
|
+
|
|
16
|
+
let iosPackage, macosPackage;
|
|
17
|
+
try {
|
|
18
|
+
iosPackage = path.dirname(
|
|
19
|
+
require.resolve(prefix + "-apple-ios/package.json")
|
|
20
|
+
);
|
|
21
|
+
macosPackage = path.dirname(
|
|
22
|
+
require.resolve(prefix + "-apple-macos/package.json")
|
|
23
|
+
);
|
|
24
|
+
} catch (e) {
|
|
25
|
+
console.error(
|
|
26
|
+
"ERROR: Could not find " +
|
|
27
|
+
prefix +
|
|
28
|
+
"-apple-ios or " +
|
|
29
|
+
prefix +
|
|
30
|
+
"-apple-macos"
|
|
31
|
+
);
|
|
32
|
+
console.error("Make sure you have run yarn install or npm install");
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Verify xcframeworks exist in the iOS package
|
|
37
|
+
const iosXcf = path.join(iosPackage, "libs");
|
|
38
|
+
if (
|
|
39
|
+
!fs.existsSync(iosXcf) ||
|
|
40
|
+
!fs.readdirSync(iosXcf).some((f) => f.endsWith(".xcframework"))
|
|
41
|
+
) {
|
|
42
|
+
console.error(
|
|
43
|
+
"ERROR: Skia prebuilt binaries not found in " + prefix + "-apple-ios!"
|
|
44
|
+
);
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
console.log("-- Skia iOS package: " + iosPackage);
|
|
49
|
+
console.log("-- Skia macOS package: " + macosPackage);
|
|
50
|
+
|
|
51
|
+
// Clean and copy Apple frameworks
|
|
52
|
+
execSync(
|
|
53
|
+
"rm -rf " +
|
|
54
|
+
path.join(libsDir, "ios") +
|
|
55
|
+
" " +
|
|
56
|
+
path.join(libsDir, "macos") +
|
|
57
|
+
" " +
|
|
58
|
+
path.join(libsDir, "tvos")
|
|
59
|
+
);
|
|
60
|
+
fs.mkdirSync(path.join(libsDir, "ios"), { recursive: true });
|
|
61
|
+
fs.mkdirSync(path.join(libsDir, "macos"), { recursive: true });
|
|
62
|
+
execSync(
|
|
63
|
+
'cp -R "' +
|
|
64
|
+
iosPackage +
|
|
65
|
+
'/libs/"*.xcframework "' +
|
|
66
|
+
path.join(libsDir, "ios") +
|
|
67
|
+
'/"'
|
|
68
|
+
);
|
|
69
|
+
execSync(
|
|
70
|
+
'cp -R "' +
|
|
71
|
+
macosPackage +
|
|
72
|
+
'/libs/"*.xcframework "' +
|
|
73
|
+
path.join(libsDir, "macos") +
|
|
74
|
+
'/"'
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
// Handle tvOS (non-Graphite only)
|
|
78
|
+
if (!useGraphite) {
|
|
79
|
+
try {
|
|
80
|
+
const tvosPackage = path.dirname(
|
|
81
|
+
require.resolve(prefix + "-apple-tvos/package.json")
|
|
82
|
+
);
|
|
83
|
+
console.log("-- Skia tvOS package: " + tvosPackage);
|
|
84
|
+
fs.mkdirSync(path.join(libsDir, "tvos"), { recursive: true });
|
|
85
|
+
execSync(
|
|
86
|
+
'cp -R "' +
|
|
87
|
+
tvosPackage +
|
|
88
|
+
'/libs/"*.xcframework "' +
|
|
89
|
+
path.join(libsDir, "tvos") +
|
|
90
|
+
'/"'
|
|
91
|
+
);
|
|
92
|
+
} catch (e) {
|
|
93
|
+
console.log("-- tvOS package not found, skipping");
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
console.log("-- Copied Apple xcframeworks to libs/");
|
|
98
|
+
|
|
99
|
+
// --- Android ---
|
|
100
|
+
|
|
101
|
+
const androidPackageName = useGraphite
|
|
102
|
+
? "react-native-skia-graphite-android"
|
|
103
|
+
: "react-native-skia-android";
|
|
104
|
+
|
|
105
|
+
let androidPackage;
|
|
106
|
+
try {
|
|
107
|
+
androidPackage = path.dirname(
|
|
108
|
+
require.resolve(androidPackageName + "/package.json")
|
|
109
|
+
);
|
|
110
|
+
} catch (e) {
|
|
111
|
+
console.error("ERROR: Could not find " + androidPackageName);
|
|
112
|
+
console.error("Make sure you have run yarn install or npm install");
|
|
113
|
+
process.exit(1);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const androidSrcLibs = path.join(androidPackage, "libs");
|
|
117
|
+
if (!fs.existsSync(androidSrcLibs)) {
|
|
118
|
+
console.error(
|
|
119
|
+
"ERROR: Skia prebuilt binaries not found in " + androidPackageName + "!"
|
|
120
|
+
);
|
|
121
|
+
process.exit(1);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
console.log("-- Skia Android package: " + androidPackage);
|
|
125
|
+
|
|
126
|
+
// Copy Android libs (per-ABI static libraries)
|
|
127
|
+
const androidDest = path.join(libsDir, "android");
|
|
128
|
+
execSync("rm -rf " + androidDest);
|
|
129
|
+
execSync('cp -R "' + androidSrcLibs + '" "' + androidDest + '"');
|
|
130
|
+
|
|
131
|
+
console.log("-- Copied Android libs to libs/android/");
|
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
import type { SkSurface } from "./Surface";
|
|
2
2
|
|
|
3
|
+
export const ColorSpace = {
|
|
4
|
+
SRGB: "srgb",
|
|
5
|
+
DisplayP3: "display-p3",
|
|
6
|
+
} as const;
|
|
7
|
+
|
|
8
|
+
export type ColorSpaceValue = (typeof ColorSpace)[keyof typeof ColorSpace];
|
|
9
|
+
|
|
10
|
+
export interface SurfaceOptions {
|
|
11
|
+
colorSpace: ColorSpaceValue;
|
|
12
|
+
}
|
|
13
|
+
|
|
3
14
|
export interface SurfaceFactory {
|
|
4
15
|
/**
|
|
5
16
|
* Returns a CPU backed surface with the given dimensions, an SRGB colorspace, Unpremul
|
|
@@ -14,6 +25,7 @@ export interface SurfaceFactory {
|
|
|
14
25
|
* Creates a GPU backed surface.
|
|
15
26
|
* @param width - number of pixels of the width of the drawable area.
|
|
16
27
|
* @param height - number of pixels of the height of the drawable area.
|
|
28
|
+
* @param opts - optional surface options (e.g. colorSpace: "display-p3" | "srgb").
|
|
17
29
|
*/
|
|
18
|
-
MakeOffscreen: (width: number, height: number) => SkSurface | null;
|
|
30
|
+
MakeOffscreen: (width: number, height: number, opts?: SurfaceOptions) => SkSurface | null;
|
|
19
31
|
}
|