|
5 | 5 | /// Bindings for CanvasKit JavaScript API.
|
6 | 6 | part of engine;
|
7 | 7 |
|
| 8 | +final js.JsObject _jsWindow = js.JsObject.fromBrowserObject(html.window); |
| 9 | + |
| 10 | +/// This and [_jsObjectWrapper] below are used to convert `@JS`-backed |
| 11 | +/// objects to [js.JsObject]s. To do that we use `@JS` to pass the object |
| 12 | +/// to JavaScript (see [JsObjectWrapper]), then use this variable (which |
| 13 | +/// uses `dart:js`) to read the value back, causing it to be wrapped in |
| 14 | +/// [js.JsObject]. |
| 15 | +/// |
| 16 | +// TODO(yjbanov): this is a temporary hack until we fully migrate to @JS. |
| 17 | +final js.JsObject _jsObjectWrapperLegacy = js.JsObject(js.context['Object']); |
| 18 | + |
| 19 | +@JS('window.flutter_js_object_wrapper') |
| 20 | +external JsObjectWrapper get _jsObjectWrapper; |
| 21 | + |
8 | 22 | void initializeCanvasKitBindings(js.JsObject canvasKit) {
|
9 | 23 | // Because JsObject cannot be cast to a @JS type, we stash CanvasKit into
|
10 | 24 | // a global and use the [canvasKitJs] getter to access it.
|
11 |
| - js.JsObject.fromBrowserObject(html.window)['flutter_canvas_kit'] = canvasKit; |
| 25 | + _jsWindow['flutter_canvas_kit'] = canvasKit; |
| 26 | + _jsWindow['flutter_js_object_wrapper'] = _jsObjectWrapperLegacy; |
| 27 | +} |
| 28 | + |
| 29 | +@JS() |
| 30 | +class JsObjectWrapper { |
| 31 | + external set skPaint(SkPaint? paint); |
| 32 | + external set skMaskFilter(SkMaskFilter? filter); |
| 33 | + external set skColorFilter(SkColorFilter? filter); |
| 34 | + external set skImageFilter(SkImageFilter? filter); |
| 35 | +} |
| 36 | + |
| 37 | +/// Specific methods that wrap `@JS`-backed objects into a [js.JsObject] |
| 38 | +/// for use with legacy `dart:js` API. |
| 39 | +extension JsObjectWrappers on JsObjectWrapper { |
| 40 | + js.JsObject wrapSkPaint(SkPaint paint) { |
| 41 | + _jsObjectWrapper.skPaint = paint; |
| 42 | + js.JsObject wrapped = _jsObjectWrapperLegacy['skPaint']; |
| 43 | + _jsObjectWrapper.skPaint = null; |
| 44 | + return wrapped; |
| 45 | + } |
| 46 | + |
| 47 | + js.JsObject wrapSkMaskFilter(SkMaskFilter filter) { |
| 48 | + _jsObjectWrapper.skMaskFilter = filter; |
| 49 | + js.JsObject wrapped = _jsObjectWrapperLegacy['skMaskFilter']; |
| 50 | + _jsObjectWrapper.skMaskFilter = null; |
| 51 | + return wrapped; |
| 52 | + } |
| 53 | + |
| 54 | + js.JsObject wrapSkColorFilter(SkColorFilter filter) { |
| 55 | + _jsObjectWrapper.skColorFilter = filter; |
| 56 | + js.JsObject wrapped = _jsObjectWrapperLegacy['skColorFilter']; |
| 57 | + _jsObjectWrapper.skColorFilter = null; |
| 58 | + return wrapped; |
| 59 | + } |
| 60 | + |
| 61 | + js.JsObject wrapSkImageFilter(SkImageFilter filter) { |
| 62 | + _jsObjectWrapper.skImageFilter = filter; |
| 63 | + js.JsObject wrapped = _jsObjectWrapperLegacy['skImageFilter']; |
| 64 | + _jsObjectWrapper.skImageFilter = null; |
| 65 | + return wrapped; |
| 66 | + } |
12 | 67 | }
|
13 | 68 |
|
14 | 69 | @JS('window.flutter_canvas_kit')
|
@@ -317,12 +372,12 @@ class SkPaint {
|
317 | 372 | external void setStrokeJoin(SkStrokeJoin join);
|
318 | 373 | external void setAntiAlias(bool isAntiAlias);
|
319 | 374 | external void setColorInt(int color);
|
320 |
| - external void setShader(SkShader shader); |
321 |
| - external void setMaskFilter(SkMaskFilter maskFilter); |
| 375 | + external void setShader(SkShader? shader); |
| 376 | + external void setMaskFilter(SkMaskFilter? maskFilter); |
322 | 377 | external void setFilterQuality(SkFilterQuality filterQuality);
|
323 |
| - external void setColorFilter(SkColorFilter colorFilter); |
| 378 | + external void setColorFilter(SkColorFilter? colorFilter); |
324 | 379 | external void setStrokeMiter(double miterLimit);
|
325 |
| - external void setImageFilter(SkImageFilter imageFilter); |
| 380 | + external void setImageFilter(SkImageFilter? imageFilter); |
326 | 381 | }
|
327 | 382 |
|
328 | 383 | @JS()
|
@@ -373,3 +428,109 @@ Float32List toSkMatrixFromFloat32(Float32List matrix4) {
|
373 | 428 | }
|
374 | 429 | return skMatrix;
|
375 | 430 | }
|
| 431 | + |
| 432 | +/// Converts an [offset] into an `[x, y]` pair stored in a `Float32List`. |
| 433 | +/// |
| 434 | +/// The returned list can be passed to CanvasKit API that take points. |
| 435 | +Float32List toSkPoint(ui.Offset offset) { |
| 436 | + final Float32List point = Float32List(2); |
| 437 | + point[0] = offset.dx; |
| 438 | + point[1] = offset.dy; |
| 439 | + return point; |
| 440 | +} |
| 441 | + |
| 442 | +/// Color stops used when the framework specifies `null`. |
| 443 | +final Float32List _kDefaultSkColorStops = Float32List(2) |
| 444 | + ..[0] = 0 |
| 445 | + ..[1] = 1; |
| 446 | + |
| 447 | +/// Converts a list of color stops into a Skia-compatible JS array or color stops. |
| 448 | +/// |
| 449 | +/// In Flutter `null` means two color stops `[0, 1]` that in Skia must be specified explicitly. |
| 450 | +Float32List toSkColorStops(List<double>? colorStops) { |
| 451 | + if (colorStops == null) { |
| 452 | + return _kDefaultSkColorStops; |
| 453 | + } |
| 454 | + |
| 455 | + final int len = colorStops.length; |
| 456 | + final Float32List skColorStops = Float32List(len); |
| 457 | + for (int i = 0; i < len; i++) { |
| 458 | + skColorStops[i] = colorStops[i]; |
| 459 | + } |
| 460 | + return skColorStops; |
| 461 | +} |
| 462 | + |
| 463 | +@JS('Float32Array') |
| 464 | +external _NativeFloat32ArrayType get _nativeFloat32ArrayType; |
| 465 | + |
| 466 | +@JS() |
| 467 | +class _NativeFloat32ArrayType {} |
| 468 | + |
| 469 | +@JS('window.flutter_canvas_kit.Malloc') |
| 470 | +external SkFloat32List _mallocFloat32List( |
| 471 | + _NativeFloat32ArrayType float32ListType, |
| 472 | + int size, |
| 473 | +); |
| 474 | + |
| 475 | +/// Allocates a [Float32List] backed by WASM memory, managed by |
| 476 | +/// a [SkFloat32List]. |
| 477 | +SkFloat32List mallocFloat32List(int size) { |
| 478 | + return _mallocFloat32List(_nativeFloat32ArrayType, size); |
| 479 | +} |
| 480 | + |
| 481 | +/// Wraps a [Float32List] backed by WASM memory. |
| 482 | +/// |
| 483 | +/// This wrapper is necessary because the raw [Float32List] will get detached |
| 484 | +/// when WASM grows its memory. Call [toTypedArray] to get a new instance |
| 485 | +/// that's attached to the current WASM memory block. |
| 486 | +@JS() |
| 487 | +class SkFloat32List { |
| 488 | + /// Returns the [Float32List] object backed by WASM memory. |
| 489 | + /// |
| 490 | + /// Do not reuse the returned list across multiple WASM function/method |
| 491 | + /// invocations that may lead to WASM memory to grow. When WASM memory |
| 492 | + /// grows the [Float32List] object becomes "detached" and is no longer |
| 493 | + /// usable. Instead, call this method every time you need to read from |
| 494 | + /// or write to the list. |
| 495 | + external Float32List toTypedArray(); |
| 496 | +} |
| 497 | + |
| 498 | +/// Writes [color] information into the given [skColor] buffer. |
| 499 | +Float32List _populateSkColor(SkFloat32List skColor, ui.Color color) { |
| 500 | + final Float32List array = skColor.toTypedArray(); |
| 501 | + array[0] = color.red / 255.0; |
| 502 | + array[1] = color.green / 255.0; |
| 503 | + array[2] = color.blue / 255.0; |
| 504 | + array[3] = color.alpha / 255.0; |
| 505 | + return array; |
| 506 | +} |
| 507 | + |
| 508 | +/// Unpacks the [color] into CanvasKit-compatible representation stored |
| 509 | +/// in a shared memory location #1. |
| 510 | +/// |
| 511 | +/// Use this only for passing transient data to CanvasKit. Because the |
| 512 | +/// memory is shared the value will not persist. |
| 513 | +Float32List toSharedSkColor1(ui.Color color) { |
| 514 | + return _populateSkColor(_sharedSkColor1, color); |
| 515 | +} |
| 516 | +final SkFloat32List _sharedSkColor1 = mallocFloat32List(4); |
| 517 | + |
| 518 | +/// Unpacks the [color] into CanvasKit-compatible representation stored |
| 519 | +/// in a shared memory location #2. |
| 520 | +/// |
| 521 | +/// Use this only for passing transient data to CanvasKit. Because the |
| 522 | +/// memory is shared the value will not persist. |
| 523 | +Float32List toSharedSkColor2(ui.Color color) { |
| 524 | + return _populateSkColor(_sharedSkColor2, color); |
| 525 | +} |
| 526 | +final SkFloat32List _sharedSkColor2 = mallocFloat32List(4); |
| 527 | + |
| 528 | +/// Unpacks the [color] into CanvasKit-compatible representation stored |
| 529 | +/// in a shared memory location #3. |
| 530 | +/// |
| 531 | +/// Use this only for passing transient data to CanvasKit. Because the |
| 532 | +/// memory is shared the value will not persist. |
| 533 | +Float32List toSharedSkColor3(ui.Color color) { |
| 534 | + return _populateSkColor(_sharedSkColor3, color); |
| 535 | +} |
| 536 | +final SkFloat32List _sharedSkColor3 = mallocFloat32List(4); |
0 commit comments