canvu-react 0.4.34 → 0.4.35
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/dist/native.cjs +136 -1
- package/dist/native.cjs.map +1 -1
- package/dist/native.js +137 -2
- package/dist/native.js.map +1 -1
- package/package.json +1 -1
package/dist/native.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import getStroke from 'perfect-freehand';
|
|
2
|
-
import { Group, Canvas, Rect, Circle, Path, RoundedRect, Oval, DashPathEffect, Line, vec, matchFont, Text,
|
|
2
|
+
import { Group, Canvas, Rect, Circle, Path, RoundedRect, Oval, DashPathEffect, Line, vec, matchFont, Text, Image } from '@shopify/react-native-skia';
|
|
3
3
|
import { memo, forwardRef, useState, useRef, useCallback, useEffect, useMemo, useImperativeHandle } from 'react';
|
|
4
4
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
5
5
|
import { StyleSheet, PanResponder, View, Pressable, Text as Text$1, ScrollView } from 'react-native';
|
|
@@ -1398,6 +1398,141 @@ function smoothFreehandPointsToPathD(points) {
|
|
|
1398
1398
|
d += ` Q ${pLast.x} ${pLast.y} ${pEnd.x} ${pEnd.y}`;
|
|
1399
1399
|
return d;
|
|
1400
1400
|
}
|
|
1401
|
+
var DEFAULT_NATIVE_IMAGE_CACHE_MAX_ENTRIES = 96;
|
|
1402
|
+
function disposeCachedImage(image) {
|
|
1403
|
+
try {
|
|
1404
|
+
image.dispose?.();
|
|
1405
|
+
} catch {
|
|
1406
|
+
}
|
|
1407
|
+
}
|
|
1408
|
+
function createNativeImageCache({
|
|
1409
|
+
loadImage,
|
|
1410
|
+
maxEntries = DEFAULT_NATIVE_IMAGE_CACHE_MAX_ENTRIES
|
|
1411
|
+
}) {
|
|
1412
|
+
const safeMaxEntries = Math.max(1, Math.round(maxEntries));
|
|
1413
|
+
const entries = /* @__PURE__ */ new Map();
|
|
1414
|
+
let clock = 0;
|
|
1415
|
+
const touchEntry = (entry) => {
|
|
1416
|
+
clock += 1;
|
|
1417
|
+
entry.lastUsed = clock;
|
|
1418
|
+
};
|
|
1419
|
+
const createEntry = () => {
|
|
1420
|
+
clock += 1;
|
|
1421
|
+
return {
|
|
1422
|
+
lastUsed: clock,
|
|
1423
|
+
retainCount: 0
|
|
1424
|
+
};
|
|
1425
|
+
};
|
|
1426
|
+
const prune = () => {
|
|
1427
|
+
const cachedEntries = [...entries.entries()].filter(
|
|
1428
|
+
(entry) => entry[1].image != null && entry[1].retainCount === 0
|
|
1429
|
+
);
|
|
1430
|
+
if (cachedEntries.length <= safeMaxEntries) return;
|
|
1431
|
+
const evictedEntries = cachedEntries.sort(
|
|
1432
|
+
(leftEntry, rightEntry) => leftEntry[1].lastUsed - rightEntry[1].lastUsed
|
|
1433
|
+
).slice(0, cachedEntries.length - safeMaxEntries);
|
|
1434
|
+
for (const [href, entry] of evictedEntries) {
|
|
1435
|
+
entries.delete(href);
|
|
1436
|
+
disposeCachedImage(entry.image);
|
|
1437
|
+
}
|
|
1438
|
+
};
|
|
1439
|
+
const getCached = (href) => {
|
|
1440
|
+
const entry = entries.get(href);
|
|
1441
|
+
if (!entry?.image) return null;
|
|
1442
|
+
touchEntry(entry);
|
|
1443
|
+
return entry.image;
|
|
1444
|
+
};
|
|
1445
|
+
const load = async (href) => {
|
|
1446
|
+
const cachedImage = getCached(href);
|
|
1447
|
+
if (cachedImage) return cachedImage;
|
|
1448
|
+
const existingEntry = entries.get(href);
|
|
1449
|
+
if (existingEntry?.promise) return await existingEntry.promise;
|
|
1450
|
+
const entry = existingEntry ?? createEntry();
|
|
1451
|
+
const promise = loadImage(href).then((image) => {
|
|
1452
|
+
if (!image) {
|
|
1453
|
+
if (entry.retainCount === 0) entries.delete(href);
|
|
1454
|
+
return null;
|
|
1455
|
+
}
|
|
1456
|
+
entry.image = image;
|
|
1457
|
+
entry.promise = void 0;
|
|
1458
|
+
touchEntry(entry);
|
|
1459
|
+
prune();
|
|
1460
|
+
return image;
|
|
1461
|
+
}).catch((error) => {
|
|
1462
|
+
entries.delete(href);
|
|
1463
|
+
throw error;
|
|
1464
|
+
});
|
|
1465
|
+
entry.promise = promise;
|
|
1466
|
+
entries.set(href, entry);
|
|
1467
|
+
return await promise;
|
|
1468
|
+
};
|
|
1469
|
+
const retain = (href) => {
|
|
1470
|
+
const entry = entries.get(href) ?? createEntry();
|
|
1471
|
+
entry.retainCount += 1;
|
|
1472
|
+
touchEntry(entry);
|
|
1473
|
+
entries.set(href, entry);
|
|
1474
|
+
let released = false;
|
|
1475
|
+
return () => {
|
|
1476
|
+
if (released) return;
|
|
1477
|
+
released = true;
|
|
1478
|
+
entry.retainCount = Math.max(0, entry.retainCount - 1);
|
|
1479
|
+
if (!entry.image && !entry.promise && entry.retainCount === 0) {
|
|
1480
|
+
entries.delete(href);
|
|
1481
|
+
return;
|
|
1482
|
+
}
|
|
1483
|
+
prune();
|
|
1484
|
+
};
|
|
1485
|
+
};
|
|
1486
|
+
const clear = () => {
|
|
1487
|
+
for (const entry of entries.values()) {
|
|
1488
|
+
if (entry.image) disposeCachedImage(entry.image);
|
|
1489
|
+
}
|
|
1490
|
+
entries.clear();
|
|
1491
|
+
};
|
|
1492
|
+
const size = () => [...entries.values()].filter((entry) => entry.image != null).length;
|
|
1493
|
+
return { getCached, load, retain, clear, size };
|
|
1494
|
+
}
|
|
1495
|
+
async function loadSkiaImageFromHref(href) {
|
|
1496
|
+
const { Skia } = await import('@shopify/react-native-skia');
|
|
1497
|
+
const data = await Skia.Data.fromURI(href);
|
|
1498
|
+
return Skia.Image.MakeImageFromEncoded(data);
|
|
1499
|
+
}
|
|
1500
|
+
var nativeSkiaImageCache = createNativeImageCache({
|
|
1501
|
+
loadImage: loadSkiaImageFromHref
|
|
1502
|
+
});
|
|
1503
|
+
function useCachedSkiaImage(href) {
|
|
1504
|
+
const [loadedImage, setLoadedImage] = useState(
|
|
1505
|
+
() => href ? { href, image: nativeSkiaImageCache.getCached(href) } : null
|
|
1506
|
+
);
|
|
1507
|
+
useEffect(() => {
|
|
1508
|
+
if (!href) {
|
|
1509
|
+
setLoadedImage(null);
|
|
1510
|
+
return;
|
|
1511
|
+
}
|
|
1512
|
+
const releaseImage = nativeSkiaImageCache.retain(href);
|
|
1513
|
+
const cachedImage = nativeSkiaImageCache.getCached(href);
|
|
1514
|
+
if (cachedImage) {
|
|
1515
|
+
setLoadedImage({ href, image: cachedImage });
|
|
1516
|
+
return releaseImage;
|
|
1517
|
+
}
|
|
1518
|
+
let active = true;
|
|
1519
|
+
setLoadedImage({ href, image: null });
|
|
1520
|
+
void nativeSkiaImageCache.load(href).then(
|
|
1521
|
+
(loadedImage2) => {
|
|
1522
|
+
if (active) setLoadedImage({ href, image: loadedImage2 });
|
|
1523
|
+
},
|
|
1524
|
+
() => {
|
|
1525
|
+
if (active) setLoadedImage({ href, image: null });
|
|
1526
|
+
}
|
|
1527
|
+
);
|
|
1528
|
+
return () => {
|
|
1529
|
+
active = false;
|
|
1530
|
+
releaseImage();
|
|
1531
|
+
};
|
|
1532
|
+
}, [href]);
|
|
1533
|
+
if (!href || loadedImage?.href !== href) return null;
|
|
1534
|
+
return loadedImage.image;
|
|
1535
|
+
}
|
|
1401
1536
|
|
|
1402
1537
|
// src/native/skia-transform.ts
|
|
1403
1538
|
function parseNum(s) {
|
|
@@ -1662,7 +1797,7 @@ function SvgNodeItem({ node }) {
|
|
|
1662
1797
|
function SvgImageNodeItem({
|
|
1663
1798
|
node
|
|
1664
1799
|
}) {
|
|
1665
|
-
const image =
|
|
1800
|
+
const image = useCachedSkiaImage(node.href);
|
|
1666
1801
|
if (!image) return null;
|
|
1667
1802
|
return /* @__PURE__ */ jsx(
|
|
1668
1803
|
Image,
|