@shopify/react-native-skia 2.3.5 → 2.3.7
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 +12 -20
- package/android/cpp/rnskia-android/RNSkAndroidPlatformContext.h +0 -1
- package/apple/SkiaCVPixelBufferUtils.mm +4 -8
- package/cpp/api/JsiSkCanvas.h +8 -0
- 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/rnskia/RNDawnContext.h +9 -3
- package/lib/commonjs/skia/types/Canvas.d.ts +6 -1
- package/lib/commonjs/skia/types/Canvas.js.map +1 -1
- package/lib/commonjs/skia/web/JsiSkCanvas.d.ts +1 -0
- package/lib/commonjs/skia/web/JsiSkCanvas.js +3 -0
- package/lib/commonjs/skia/web/JsiSkCanvas.js.map +1 -1
- package/lib/module/skia/types/Canvas.d.ts +6 -1
- package/lib/module/skia/types/Canvas.js.map +1 -1
- package/lib/module/skia/web/JsiSkCanvas.d.ts +1 -0
- package/lib/module/skia/web/JsiSkCanvas.js +3 -0
- package/lib/module/skia/web/JsiSkCanvas.js.map +1 -1
- package/lib/typescript/lib/commonjs/skia/web/JsiSkCanvas.d.ts +2 -0
- package/lib/typescript/lib/module/skia/web/JsiSkCanvas.d.ts +2 -0
- package/lib/typescript/src/skia/types/Canvas.d.ts +6 -1
- package/lib/typescript/src/skia/web/JsiSkCanvas.d.ts +1 -0
- package/package.json +22 -3
- package/scripts/install-skia.mjs +323 -79
- package/src/skia/types/Canvas.ts +7 -1
- package/src/skia/web/JsiSkCanvas.ts +7 -0
package/scripts/install-skia.mjs
CHANGED
|
@@ -2,6 +2,7 @@ import fs from "fs";
|
|
|
2
2
|
import https from "https";
|
|
3
3
|
import path from "path";
|
|
4
4
|
import os from "os";
|
|
5
|
+
import crypto from "crypto";
|
|
5
6
|
import { spawn } from "child_process";
|
|
6
7
|
import { fileURLToPath } from "url";
|
|
7
8
|
|
|
@@ -9,10 +10,34 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
|
9
10
|
|
|
10
11
|
const repo = "shopify/react-native-skia";
|
|
11
12
|
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
return
|
|
13
|
+
const packageJsonPath = path.join(__dirname, "..", "package.json");
|
|
14
|
+
|
|
15
|
+
const getPackageJson = () => {
|
|
16
|
+
return JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const getSkiaConfig = (graphite = false) => {
|
|
20
|
+
const packageJson = getPackageJson();
|
|
21
|
+
return graphite ? packageJson["skia-graphite"] : packageJson.skia;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const getSkiaVersion = (graphite = false) => {
|
|
25
|
+
const packageJson = getPackageJson();
|
|
26
|
+
const skiaConfig = getSkiaConfig(graphite);
|
|
27
|
+
return skiaConfig?.version || packageJson.skiaVersion;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const updateSkiaChecksums = (checksums, graphite = false) => {
|
|
31
|
+
const packageJson = getPackageJson();
|
|
32
|
+
const field = graphite ? "skia-graphite" : "skia";
|
|
33
|
+
|
|
34
|
+
if (!packageJson[field]) {
|
|
35
|
+
packageJson[field] = { version: packageJson[field]?.version || "m142", checksums: {} };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
packageJson[field].checksums = checksums;
|
|
39
|
+
|
|
40
|
+
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + "\n", "utf8");
|
|
16
41
|
};
|
|
17
42
|
|
|
18
43
|
const GRAPHITE = !!process.env.SK_GRAPHITE;
|
|
@@ -25,13 +50,13 @@ const names = [
|
|
|
25
50
|
`${prefix}-apple-xcframeworks`,
|
|
26
51
|
];
|
|
27
52
|
if (GRAPHITE) {
|
|
28
|
-
names.push(
|
|
53
|
+
names.push(`${prefix}-headers`);
|
|
29
54
|
}
|
|
30
55
|
|
|
31
|
-
const skiaVersion = getSkiaVersion();
|
|
32
|
-
const releaseTag = `skia-${skiaVersion}`;
|
|
56
|
+
const skiaVersion = getSkiaVersion(GRAPHITE);
|
|
57
|
+
const releaseTag = GRAPHITE ? `skia-graphite-${skiaVersion}` : `skia-${skiaVersion}`;
|
|
33
58
|
console.log(
|
|
34
|
-
`📦 Downloading Skia prebuilt binaries for
|
|
59
|
+
`📦 Downloading Skia prebuilt binaries for ${releaseTag}`
|
|
35
60
|
);
|
|
36
61
|
|
|
37
62
|
const runCommand = (command, args) => {
|
|
@@ -52,64 +77,89 @@ const runCommand = (command, args) => {
|
|
|
52
77
|
});
|
|
53
78
|
};
|
|
54
79
|
|
|
55
|
-
const
|
|
80
|
+
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
|
|
81
|
+
|
|
82
|
+
const downloadToFile = (url, destPath, maxRetries = 5) => {
|
|
56
83
|
fs.mkdirSync(path.dirname(destPath), { recursive: true });
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
res.
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
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;
|
|
71
102
|
}
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
103
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
new Error(
|
|
104
|
+
if (res.statusCode !== 200) {
|
|
105
|
+
const error = new Error(
|
|
78
106
|
`Failed to download: ${res.statusCode} ${res.statusMessage}`
|
|
79
|
-
)
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
const fileStream = fs.createWriteStream(destPath);
|
|
86
|
-
res.pipe(fileStream);
|
|
107
|
+
);
|
|
108
|
+
error.statusCode = res.statusCode;
|
|
109
|
+
reject(error);
|
|
110
|
+
res.resume();
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
87
113
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
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
|
+
});
|
|
97
127
|
});
|
|
98
|
-
});
|
|
99
128
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
129
|
+
const cleanup = (error) => {
|
|
130
|
+
fileStream.destroy();
|
|
131
|
+
fs.unlink(destPath, () => reject(error));
|
|
132
|
+
};
|
|
104
133
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
134
|
+
res.on("error", cleanup);
|
|
135
|
+
fileStream.on("error", cleanup);
|
|
136
|
+
})
|
|
137
|
+
.on("error", reject);
|
|
138
|
+
};
|
|
110
139
|
|
|
111
|
-
|
|
112
|
-
|
|
140
|
+
request(url);
|
|
141
|
+
});
|
|
142
|
+
};
|
|
143
|
+
|
|
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();
|
|
113
163
|
};
|
|
114
164
|
|
|
115
165
|
const extractTarGz = async (archivePath, destDir) => {
|
|
@@ -178,6 +228,92 @@ const artifactsDir = path.resolve(
|
|
|
178
228
|
|
|
179
229
|
const libsDir = path.resolve(__dirname, "../libs");
|
|
180
230
|
|
|
231
|
+
// Function to calculate the checksum of a directory
|
|
232
|
+
const calculateDirectoryChecksum = (directory) => {
|
|
233
|
+
if (!fs.existsSync(directory)) {
|
|
234
|
+
return null;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const hash = crypto.createHash("sha256");
|
|
238
|
+
const files = [];
|
|
239
|
+
|
|
240
|
+
const collectFiles = (dir) => {
|
|
241
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
242
|
+
for (const entry of entries) {
|
|
243
|
+
const fullPath = path.join(dir, entry.name);
|
|
244
|
+
if (entry.isDirectory()) {
|
|
245
|
+
collectFiles(fullPath);
|
|
246
|
+
} else if (entry.isFile()) {
|
|
247
|
+
files.push(fullPath);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
collectFiles(directory);
|
|
253
|
+
files.sort();
|
|
254
|
+
|
|
255
|
+
for (const file of files) {
|
|
256
|
+
const relativePath = path.relative(directory, file);
|
|
257
|
+
hash.update(relativePath);
|
|
258
|
+
hash.update(fs.readFileSync(file));
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return hash.digest("hex");
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
// Function to calculate all library checksums
|
|
265
|
+
const calculateLibraryChecksums = () => {
|
|
266
|
+
const checksums = {};
|
|
267
|
+
|
|
268
|
+
// Android architectures
|
|
269
|
+
const androidArchs = ["armeabi-v7a", "arm64-v8a", "x86", "x86_64"];
|
|
270
|
+
for (const arch of androidArchs) {
|
|
271
|
+
const archDir = path.join(libsDir, "android", arch);
|
|
272
|
+
const checksum = calculateDirectoryChecksum(archDir);
|
|
273
|
+
if (checksum) {
|
|
274
|
+
const checksumKey = `android-${arch}`;
|
|
275
|
+
checksums[checksumKey] = checksum;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Apple frameworks
|
|
280
|
+
const appleDir = path.join(libsDir, "apple");
|
|
281
|
+
const appleChecksum = calculateDirectoryChecksum(appleDir);
|
|
282
|
+
if (appleChecksum) {
|
|
283
|
+
checksums["apple-xcframeworks"] = appleChecksum;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
return checksums;
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
// Function to verify if checksums match
|
|
290
|
+
const verifyChecksums = () => {
|
|
291
|
+
const skiaConfig = getSkiaConfig(GRAPHITE);
|
|
292
|
+
const expectedChecksums = skiaConfig?.checksums || {};
|
|
293
|
+
|
|
294
|
+
// If no checksums in package.json, we need to download
|
|
295
|
+
if (Object.keys(expectedChecksums).length === 0) {
|
|
296
|
+
console.log("⚠️ No checksums found in package.json");
|
|
297
|
+
return false;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
const actualChecksums = calculateLibraryChecksums();
|
|
301
|
+
|
|
302
|
+
// Check if all expected checksums match
|
|
303
|
+
for (const [key, expectedChecksum] of Object.entries(expectedChecksums)) {
|
|
304
|
+
const actualChecksum = actualChecksums[key];
|
|
305
|
+
if (actualChecksum !== expectedChecksum) {
|
|
306
|
+
console.log(`⚠️ Checksum mismatch for ${key}`);
|
|
307
|
+
console.log(` Expected: ${expectedChecksum}`);
|
|
308
|
+
console.log(` Actual: ${actualChecksum || "missing"}`);
|
|
309
|
+
return false;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
console.log("✅ All checksums match");
|
|
314
|
+
return true;
|
|
315
|
+
};
|
|
316
|
+
|
|
181
317
|
// Function to check if prebuilt binaries are already installed
|
|
182
318
|
const areBinariesInstalled = () => {
|
|
183
319
|
if (!fs.existsSync(libsDir)) {
|
|
@@ -223,17 +359,14 @@ const clearDirectory = (directory) => {
|
|
|
223
359
|
};
|
|
224
360
|
|
|
225
361
|
const main = async () => {
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
if (!forceReinstall && areBinariesInstalled()) {
|
|
230
|
-
console.log("✅ Prebuilt binaries already installed, skipping download");
|
|
231
|
-
console.log(" Use --force to reinstall");
|
|
362
|
+
// Check if binaries are installed and checksums match
|
|
363
|
+
if (areBinariesInstalled() && verifyChecksums()) {
|
|
364
|
+
console.log("✅ Prebuilt binaries already installed with matching checksums, skipping download");
|
|
232
365
|
return;
|
|
233
366
|
}
|
|
234
367
|
|
|
235
|
-
if (
|
|
236
|
-
console.log("
|
|
368
|
+
if (areBinariesInstalled()) {
|
|
369
|
+
console.log("⚠️ Binaries installed but checksums don't match, re-downloading...");
|
|
237
370
|
}
|
|
238
371
|
|
|
239
372
|
console.log("🧹 Clearing existing artifacts...");
|
|
@@ -270,22 +403,50 @@ const main = async () => {
|
|
|
270
403
|
fs.mkdirSync(androidDir, { recursive: true });
|
|
271
404
|
|
|
272
405
|
// Copy android artifacts
|
|
273
|
-
const androidArchs = [
|
|
274
|
-
{
|
|
275
|
-
{
|
|
276
|
-
{
|
|
277
|
-
{
|
|
406
|
+
const androidArchs = GRAPHITE ? [
|
|
407
|
+
{ artifact: `${prefix}-android-arm`, srcSubdir: "arm", dest: "armeabi-v7a" },
|
|
408
|
+
{ artifact: `${prefix}-android-arm-64`, srcSubdir: "arm64", dest: "arm64-v8a" },
|
|
409
|
+
{ artifact: `${prefix}-android-arm-x86`, srcSubdir: "x86", dest: "x86" },
|
|
410
|
+
{ artifact: `${prefix}-android-arm-x64`, srcSubdir: "x64", dest: "x86_64" },
|
|
411
|
+
] : [
|
|
412
|
+
{ artifact: `${prefix}-android-arm`, srcSubdir: "armeabi-v7a", dest: "armeabi-v7a" },
|
|
413
|
+
{ artifact: `${prefix}-android-arm-64`, srcSubdir: "arm64-v8a", dest: "arm64-v8a" },
|
|
414
|
+
{ artifact: `${prefix}-android-arm-x86`, srcSubdir: "x86", dest: "x86" },
|
|
415
|
+
{ artifact: `${prefix}-android-arm-x64`, srcSubdir: "x86_64", dest: "x86_64" },
|
|
278
416
|
];
|
|
279
417
|
|
|
280
|
-
androidArchs.forEach(({
|
|
281
|
-
// The tar file extracts to artifactName/
|
|
282
|
-
const srcDir = path.join(artifactsDir,
|
|
418
|
+
androidArchs.forEach(({ artifact, srcSubdir, dest }) => {
|
|
419
|
+
// The tar file extracts to artifactName/srcSubdir
|
|
420
|
+
const srcDir = path.join(artifactsDir, artifact, srcSubdir);
|
|
283
421
|
const destDir = path.join(androidDir, dest);
|
|
422
|
+
console.log(` Checking ${srcDir} -> ${destDir}`);
|
|
284
423
|
if (fs.existsSync(srcDir)) {
|
|
424
|
+
console.log(` ✓ Copying ${artifact}/${srcSubdir}`);
|
|
285
425
|
fs.mkdirSync(destDir, { recursive: true });
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
426
|
+
|
|
427
|
+
const copyDir = (srcPath, destPath) => {
|
|
428
|
+
fs.mkdirSync(destPath, { recursive: true });
|
|
429
|
+
fs.readdirSync(srcPath).forEach((file) => {
|
|
430
|
+
const srcFile = path.join(srcPath, file);
|
|
431
|
+
const destFile = path.join(destPath, file);
|
|
432
|
+
const stat = fs.lstatSync(srcFile);
|
|
433
|
+
|
|
434
|
+
// Skip sockets and other special files
|
|
435
|
+
if (stat.isSocket() || stat.isFIFO() || stat.isCharacterDevice() || stat.isBlockDevice()) {
|
|
436
|
+
return;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
if (stat.isDirectory()) {
|
|
440
|
+
copyDir(srcFile, destFile);
|
|
441
|
+
} else {
|
|
442
|
+
fs.copyFileSync(srcFile, destFile);
|
|
443
|
+
}
|
|
444
|
+
});
|
|
445
|
+
};
|
|
446
|
+
|
|
447
|
+
copyDir(srcDir, destDir);
|
|
448
|
+
} else {
|
|
449
|
+
console.log(` ✗ Source directory not found: ${srcDir}`);
|
|
289
450
|
}
|
|
290
451
|
});
|
|
291
452
|
|
|
@@ -294,7 +455,7 @@ const main = async () => {
|
|
|
294
455
|
// The tar file extracts to skia-apple-xcframeworks/apple
|
|
295
456
|
const appleSrcDir = path.join(
|
|
296
457
|
artifactsDir,
|
|
297
|
-
|
|
458
|
+
`${prefix}-apple-xcframeworks`,
|
|
298
459
|
"apple"
|
|
299
460
|
);
|
|
300
461
|
if (fs.existsSync(appleSrcDir)) {
|
|
@@ -326,7 +487,90 @@ const main = async () => {
|
|
|
326
487
|
});
|
|
327
488
|
}
|
|
328
489
|
|
|
329
|
-
|
|
490
|
+
// Copy Graphite headers if using Graphite
|
|
491
|
+
if (GRAPHITE) {
|
|
492
|
+
console.log("📦 Copying Graphite headers...");
|
|
493
|
+
const cppDir = path.resolve(__dirname, "../cpp");
|
|
494
|
+
const headersSrcDir = path.join(artifactsDir, `${prefix}-headers`);
|
|
495
|
+
|
|
496
|
+
console.log(` Looking for headers in: ${headersSrcDir}`);
|
|
497
|
+
console.log(` Headers dir exists: ${fs.existsSync(headersSrcDir)}`);
|
|
498
|
+
|
|
499
|
+
if (fs.existsSync(headersSrcDir)) {
|
|
500
|
+
console.log(` Contents: ${fs.readdirSync(headersSrcDir).join(", ")}`);
|
|
501
|
+
|
|
502
|
+
// The asset contains packages/skia/cpp structure, so we need to navigate into it
|
|
503
|
+
const packagesDir = path.join(headersSrcDir, "packages", "skia", "cpp");
|
|
504
|
+
console.log(` Looking for packages dir: ${packagesDir}`);
|
|
505
|
+
console.log(` Packages dir exists: ${fs.existsSync(packagesDir)}`);
|
|
506
|
+
|
|
507
|
+
if (fs.existsSync(packagesDir)) {
|
|
508
|
+
console.log(` Packages contents: ${fs.readdirSync(packagesDir).join(", ")}`);
|
|
509
|
+
|
|
510
|
+
// Copy dawn/include
|
|
511
|
+
const dawnIncludeSrc = path.join(packagesDir, "dawn", "include");
|
|
512
|
+
const dawnIncludeDest = path.join(cppDir, "dawn", "include");
|
|
513
|
+
console.log(` Dawn source: ${dawnIncludeSrc}`);
|
|
514
|
+
console.log(` Dawn source exists: ${fs.existsSync(dawnIncludeSrc)}`);
|
|
515
|
+
|
|
516
|
+
if (fs.existsSync(dawnIncludeSrc)) {
|
|
517
|
+
const copyDir = (src, dest) => {
|
|
518
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
519
|
+
fs.readdirSync(src).forEach((file) => {
|
|
520
|
+
const srcFile = path.join(src, file);
|
|
521
|
+
const destFile = path.join(dest, file);
|
|
522
|
+
if (fs.lstatSync(srcFile).isDirectory()) {
|
|
523
|
+
copyDir(srcFile, destFile);
|
|
524
|
+
} else {
|
|
525
|
+
fs.copyFileSync(srcFile, destFile);
|
|
526
|
+
}
|
|
527
|
+
});
|
|
528
|
+
};
|
|
529
|
+
copyDir(dawnIncludeSrc, dawnIncludeDest);
|
|
530
|
+
console.log(" ✓ Dawn headers copied");
|
|
531
|
+
} else {
|
|
532
|
+
console.log(" ✗ Dawn headers not found");
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
// Copy graphite headers
|
|
536
|
+
const graphiteSrc = path.join(packagesDir, "skia", "src", "gpu", "graphite");
|
|
537
|
+
const graphiteDest = path.join(cppDir, "skia", "src", "gpu", "graphite");
|
|
538
|
+
console.log(` Graphite source: ${graphiteSrc}`);
|
|
539
|
+
console.log(` Graphite source exists: ${fs.existsSync(graphiteSrc)}`);
|
|
540
|
+
|
|
541
|
+
if (fs.existsSync(graphiteSrc)) {
|
|
542
|
+
const copyDir = (src, dest) => {
|
|
543
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
544
|
+
fs.readdirSync(src).forEach((file) => {
|
|
545
|
+
const srcFile = path.join(src, file);
|
|
546
|
+
const destFile = path.join(dest, file);
|
|
547
|
+
if (fs.lstatSync(srcFile).isDirectory()) {
|
|
548
|
+
copyDir(srcFile, destFile);
|
|
549
|
+
} else {
|
|
550
|
+
fs.copyFileSync(srcFile, destFile);
|
|
551
|
+
}
|
|
552
|
+
});
|
|
553
|
+
};
|
|
554
|
+
copyDir(graphiteSrc, graphiteDest);
|
|
555
|
+
console.log(" ✓ Graphite headers copied");
|
|
556
|
+
} else {
|
|
557
|
+
console.log(" ✗ Graphite headers not found");
|
|
558
|
+
}
|
|
559
|
+
} else {
|
|
560
|
+
console.log(" ✗ Packages directory not found in headers asset");
|
|
561
|
+
}
|
|
562
|
+
} else {
|
|
563
|
+
console.log(" ✗ Headers directory not found");
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
console.log("✅ Completed installation of Skia prebuilt binaries.");
|
|
568
|
+
|
|
569
|
+
// Calculate and update checksums in package.json
|
|
570
|
+
console.log("🔐 Calculating and updating checksums...");
|
|
571
|
+
const newChecksums = calculateLibraryChecksums();
|
|
572
|
+
updateSkiaChecksums(newChecksums, GRAPHITE);
|
|
573
|
+
console.log("✅ Checksums updated in package.json");
|
|
330
574
|
|
|
331
575
|
// Clean up artifacts directory
|
|
332
576
|
console.log("🗑️ Cleaning up artifacts directory...");
|
|
@@ -338,4 +582,4 @@ const main = async () => {
|
|
|
338
582
|
main().catch((error) => {
|
|
339
583
|
console.error("❌ Error:", error);
|
|
340
584
|
process.exit(1);
|
|
341
|
-
});
|
|
585
|
+
});
|
package/src/skia/types/Canvas.ts
CHANGED
|
@@ -14,7 +14,7 @@ import type { SkColor } from "./Color";
|
|
|
14
14
|
import type { InputRRect } from "./RRect";
|
|
15
15
|
import type { BlendMode } from "./Paint/BlendMode";
|
|
16
16
|
import type { SkPoint, PointMode } from "./Point";
|
|
17
|
-
import type { InputMatrix } from "./Matrix";
|
|
17
|
+
import type { InputMatrix, SkMatrix } from "./Matrix";
|
|
18
18
|
import type { SkImageFilter } from "./ImageFilter";
|
|
19
19
|
import type { SkVertices } from "./Vertices";
|
|
20
20
|
import type { SkTextBlob } from "./TextBlob";
|
|
@@ -241,6 +241,12 @@ export interface SkCanvas {
|
|
|
241
241
|
*/
|
|
242
242
|
restoreToCount(saveCount: number): void;
|
|
243
243
|
|
|
244
|
+
/**
|
|
245
|
+
* Legacy version of getLocalToDevice(), which strips away any Z information, and
|
|
246
|
+
* just returns a 3x3 version.
|
|
247
|
+
*/
|
|
248
|
+
getTotalMatrix(): SkMatrix;
|
|
249
|
+
|
|
244
250
|
/**
|
|
245
251
|
* Draws the given points using the current clip, current matrix, and the provided paint.
|
|
246
252
|
*
|
|
@@ -218,6 +218,13 @@ export class JsiSkCanvas
|
|
|
218
218
|
this.ref.restoreToCount(saveCount);
|
|
219
219
|
}
|
|
220
220
|
|
|
221
|
+
getTotalMatrix(): SkMatrix {
|
|
222
|
+
return new JsiSkMatrix(
|
|
223
|
+
this.CanvasKit,
|
|
224
|
+
Float32Array.of(...this.ref.getTotalMatrix())
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
|
|
221
228
|
drawPoints(mode: PointMode, points: SkPoint[], paint: SkPaint) {
|
|
222
229
|
this.ref.drawPoints(
|
|
223
230
|
getEnum(this.CanvasKit, "PointMode", mode),
|