Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 5e7c3b7

Browse files
committed
[web] Make Canvaskit's malloc more useful
1 parent d945c15 commit 5e7c3b7

File tree

4 files changed

+89
-22
lines changed

4 files changed

+89
-22
lines changed

lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart

+55-17
Original file line numberDiff line numberDiff line change
@@ -1267,34 +1267,46 @@ Float32List toSkColorStops(List<double>? colorStops) {
12671267
return skColorStops;
12681268
}
12691269

1270-
@JS('Float32Array')
1271-
external _NativeFloat32ArrayType get _nativeFloat32ArrayType;
1272-
12731270
@JS()
12741271
@staticInterop
1275-
class _NativeFloat32ArrayType {}
1272+
abstract class _ArrayType {}
1273+
1274+
@JS('Float32Array')
1275+
external _ArrayType get _nativeFloat32ArrayType;
1276+
1277+
@JS('Uint32Array')
1278+
external _ArrayType get _nativeUint32ArrayType;
12761279

12771280
@JS('window.flutterCanvasKit.Malloc')
1278-
external SkFloat32List _mallocFloat32List(
1279-
_NativeFloat32ArrayType float32ListType,
1280-
int size,
1281-
);
1281+
external Object _mallocList(_ArrayType arrayType, int size);
12821282

12831283
/// Allocates a [Float32List] backed by WASM memory, managed by
12841284
/// a [SkFloat32List].
12851285
///
1286-
/// To free the allocated array use [freeFloat32List].
1286+
/// To free the allocated array use [freeList].
12871287
SkFloat32List mallocFloat32List(int size) {
1288-
return _mallocFloat32List(_nativeFloat32ArrayType, size);
1288+
return _mallocList(_nativeFloat32ArrayType, size) as SkFloat32List;
1289+
}
1290+
1291+
/// Allocates a [Uint32List] backed by WASM memory, managed by
1292+
/// a [SkUint32List].
1293+
///
1294+
/// To free the allocated array use [freeList].
1295+
SkUint32List mallocUint32List(int size) {
1296+
return _mallocList(_nativeUint32ArrayType, size) as SkUint32List;
12891297
}
12901298

1291-
/// Frees the WASM memory occupied by a [SkFloat32List].
1299+
/// Frees the WASM memory occupied by a [SkFloat32List] or [SkUint32List].
12921300
///
12931301
/// The [list] is no longer usable after calling this function.
12941302
///
12951303
/// Use this function to free lists owned by the engine.
12961304
@JS('window.flutterCanvasKit.Free')
1297-
external void freeFloat32List(SkFloat32List list);
1305+
external void freeList(_MallocObj list);
1306+
1307+
@JS()
1308+
@staticInterop
1309+
abstract class _MallocObj {}
12981310

12991311
/// Wraps a [Float32List] backed by WASM memory.
13001312
///
@@ -1303,19 +1315,45 @@ external void freeFloat32List(SkFloat32List list);
13031315
/// that's attached to the current WASM memory block.
13041316
@JS()
13051317
@staticInterop
1306-
class SkFloat32List {}
1318+
class SkFloat32List extends _MallocObj {}
13071319

13081320
extension SkFloat32ListExtension on SkFloat32List {
1321+
/// The number of objects this pointer refers to.
1322+
external int length;
1323+
13091324
/// Returns the [Float32List] object backed by WASM memory.
13101325
///
1311-
/// Do not reuse the returned list across multiple WASM function/method
1326+
/// Do not reuse the returned array across multiple WASM function/method
13121327
/// invocations that may lead to WASM memory to grow. When WASM memory
1313-
/// grows the [Float32List] object becomes "detached" and is no longer
1314-
/// usable. Instead, call this method every time you need to read from
1328+
/// grows, the returned [Float32List] object becomes "detached" and is no
1329+
/// longer usable. Instead, call this method every time you need to read from
13151330
/// or write to the list.
13161331
external Float32List toTypedArray();
13171332
}
13181333

1334+
/// Wraps a [Uint32List] backed by WASM memory.
1335+
///
1336+
/// This wrapper is necessary because the raw [Uint32List] will get detached
1337+
/// when WASM grows its memory. Call [toTypedArray] to get a new instance
1338+
/// that's attached to the current WASM memory block.
1339+
@JS()
1340+
@staticInterop
1341+
class SkUint32List extends _MallocObj {}
1342+
1343+
extension SkUint32ListExtension on SkUint32List {
1344+
/// The number of objects this pointer refers to.
1345+
external int length;
1346+
1347+
/// Returns the [Uint32List] object backed by WASM memory.
1348+
///
1349+
/// Do not reuse the returned array across multiple WASM function/method
1350+
/// invocations that may lead to WASM memory to grow. When WASM memory
1351+
/// grows, the returned [Uint32List] object becomes "detached" and is no
1352+
/// longer usable. Instead, call this method every time you need to read from
1353+
/// or write to the list.
1354+
external Uint32List toTypedArray();
1355+
}
1356+
13191357
/// Writes [color] information into the given [skColor] buffer.
13201358
Float32List _populateSkColor(SkFloat32List skColor, ui.Color color) {
13211359
final Float32List array = skColor.toTypedArray();
@@ -1584,7 +1622,7 @@ Float32List toOuterSkRect(ui.RRect rrect) {
15841622
/// Uses `CanvasKit.Malloc` to allocate storage for the points in the WASM
15851623
/// memory to avoid unnecessary copying. Unless CanvasKit takes ownership of
15861624
/// the list the returned list must be explicitly freed using
1587-
/// [freeMallocedFloat32List].
1625+
/// [freeList].
15881626
SkFloat32List toMallocedSkPoints(List<ui.Offset> points) {
15891627
final int len = points.length;
15901628
final SkFloat32List skPoints = mallocFloat32List(len * 2);

lib/web_ui/lib/src/engine/canvaskit/canvaskit_canvas.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@ class CanvasKitCanvas implements ui.Canvas {
326326
pointMode,
327327
skPoints.toTypedArray(),
328328
);
329-
freeFloat32List(skPoints);
329+
freeList(skPoints);
330330
}
331331

332332
@override

lib/web_ui/lib/src/engine/canvaskit/path.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ class CkPath extends ManagedSkiaObject<SkPath> implements ui.Path {
8989
assert(points != null);
9090
final SkFloat32List encodedPoints = toMallocedSkPoints(points);
9191
skiaObject.addPoly(encodedPoints.toTypedArray(), close);
92-
freeFloat32List(encodedPoints);
92+
freeList(encodedPoints);
9393
}
9494

9595
@override

lib/web_ui/test/canvaskit/canvaskit_api_test.dart

+32-3
Original file line numberDiff line numberDiff line change
@@ -533,11 +533,40 @@ void _imageFilterTests() {
533533
}
534534

535535
void _mallocTests() {
536-
test('SkFloat32List', () {
536+
test('$SkFloat32List', () {
537+
final List<SkFloat32List> lists = <SkFloat32List>[];
538+
537539
for (int size = 0; size < 1000; size++) {
538540
final SkFloat32List skList = mallocFloat32List(4);
539541
expect(skList, isNotNull);
540-
expect(skList.toTypedArray().length, 4);
542+
expect(skList.toTypedArray(), hasLength(4));
543+
lists.add(skList);
544+
}
545+
546+
for (final SkFloat32List skList in lists) {
547+
// toTypedArray() still works.
548+
expect(() => skList.toTypedArray(), returnsNormally);
549+
freeList(skList);
550+
// toTypedArray() throws after free.
551+
expect(() => skList.toTypedArray(), throwsA(isA<Error>()));
552+
}
553+
});
554+
test('$SkUint32List', () {
555+
final List<SkUint32List> lists = <SkUint32List>[];
556+
557+
for (int size = 0; size < 1000; size++) {
558+
final SkUint32List skList = mallocUint32List(4);
559+
expect(skList, isNotNull);
560+
expect(skList.toTypedArray(), hasLength(4));
561+
lists.add(skList);
562+
}
563+
564+
for (final SkUint32List skList in lists) {
565+
// toTypedArray() still works.
566+
expect(() => skList.toTypedArray(), returnsNormally);
567+
freeList(skList);
568+
// toTypedArray() throws after free.
569+
expect(() => skList.toTypedArray(), throwsA(isA<Error>()));
541570
}
542571
});
543572
}
@@ -812,7 +841,7 @@ void _pathTests() {
812841
ui.Offset(10, 10),
813842
]);
814843
path.addPoly(encodedPoints.toTypedArray(), true);
815-
freeFloat32List(encodedPoints);
844+
freeList(encodedPoints);
816845
});
817846

818847
test('addRRect', () {

0 commit comments

Comments
 (0)