diff --git a/engine/src/flutter/ci/licenses_golden/licenses_flutter b/engine/src/flutter/ci/licenses_golden/licenses_flutter index 0158c116e1..2af8a23fab 100644 --- a/engine/src/flutter/ci/licenses_golden/licenses_flutter +++ b/engine/src/flutter/ci/licenses_golden/licenses_flutter @@ -2043,6 +2043,7 @@ ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_sh ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_skdata.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_skstring.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_surface.dart + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_vertices.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/skwasm_module.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/text/raw_line_metrics.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/text/raw_paragraph.dart + ../../../flutter/LICENSE @@ -2122,6 +2123,7 @@ ORIGIN: ../../../flutter/lib/web_ui/skwasm/text/paragraph_builder.cpp + ../../.. ORIGIN: ../../../flutter/lib/web_ui/skwasm/text/paragraph_style.cpp + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/skwasm/text/strut_style.cpp + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/skwasm/text/text_style.cpp + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/lib/web_ui/skwasm/vertices.cpp + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/skwasm/wrappers.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/runtime/dart_isolate.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/runtime/dart_isolate.h + ../../../flutter/LICENSE @@ -4696,6 +4698,7 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_shad FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_skdata.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_skstring.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_surface.dart +FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_vertices.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/skwasm_module.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/text/raw_line_metrics.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/text/raw_paragraph.dart @@ -4775,6 +4778,7 @@ FILE: ../../../flutter/lib/web_ui/skwasm/text/paragraph_builder.cpp FILE: ../../../flutter/lib/web_ui/skwasm/text/paragraph_style.cpp FILE: ../../../flutter/lib/web_ui/skwasm/text/strut_style.cpp FILE: ../../../flutter/lib/web_ui/skwasm/text/text_style.cpp +FILE: ../../../flutter/lib/web_ui/skwasm/vertices.cpp FILE: ../../../flutter/lib/web_ui/skwasm/wrappers.h FILE: ../../../flutter/runtime/dart_isolate.cc FILE: ../../../flutter/runtime/dart_isolate.h diff --git a/engine/src/flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl.dart b/engine/src/flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl.dart index 9874f6a552..cb59b9ed13 100644 --- a/engine/src/flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl.dart +++ b/engine/src/flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl.dart @@ -34,6 +34,7 @@ export 'skwasm_impl/raw/raw_shaders.dart'; export 'skwasm_impl/raw/raw_skdata.dart'; export 'skwasm_impl/raw/raw_skstring.dart'; export 'skwasm_impl/raw/raw_surface.dart'; +export 'skwasm_impl/raw/raw_vertices.dart'; export 'skwasm_impl/raw/skwasm_module.dart'; export 'skwasm_impl/raw/text/raw_line_metrics.dart'; export 'skwasm_impl/raw/text/raw_paragraph.dart'; diff --git a/engine/src/flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/canvas.dart b/engine/src/flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/canvas.dart index 5d02790a73..4eb409ba25 100644 --- a/engine/src/flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/canvas.dart +++ b/engine/src/flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/canvas.dart @@ -259,21 +259,47 @@ class SkwasmCanvas implements SceneCanvas { @override void drawPoints( - ui.PointMode pointMode, List points, ui.Paint paint) { - throw UnimplementedError(); - } + ui.PointMode pointMode, + List points, + ui.Paint paint + ) => withStackScope((StackScope scope) { + final RawPointArray rawPoints = scope.convertPointArrayToNative(points); + canvasDrawPoints( + _handle, + pointMode.index, + rawPoints, + points.length, + (paint as SkwasmPaint).handle, + ); + }); @override void drawRawPoints( - ui.PointMode pointMode, Float32List points, ui.Paint paint) { - throw UnimplementedError(); - } + ui.PointMode pointMode, + Float32List points, + ui.Paint paint + ) => withStackScope((StackScope scope) { + final RawPointArray rawPoints = scope.convertDoublesToNative(points); + canvasDrawPoints( + _handle, + pointMode.index, + rawPoints, + points.length ~/ 2, + (paint as SkwasmPaint).handle, + ); + }); @override void drawVertices( - ui.Vertices vertices, ui.BlendMode blendMode, ui.Paint paint) { - throw UnimplementedError(); - } + ui.Vertices vertices, + ui.BlendMode blendMode, + ui.Paint paint, + ) => canvasDrawVertices( + _handle, + (vertices as SkwasmVertices).handle, + blendMode.index, + (paint as SkwasmPaint).handle, + ); @override void drawAtlas( @@ -284,9 +310,27 @@ class SkwasmCanvas implements SceneCanvas { ui.BlendMode? blendMode, ui.Rect? cullRect, ui.Paint paint, - ) { - throw UnimplementedError(); - } + ) => withStackScope((StackScope scope) { + final RawRSTransformArray rawTransforms = scope.convertRSTransformsToNative(transforms); + final RawRect rawRects = scope.convertRectsToNative(rects); + final RawColorArray rawColors = colors != null + ? scope.convertColorArrayToNative(colors) + : nullptr; + final RawRect rawCullRect = cullRect != null + ? scope.convertRectToNative(cullRect) + : nullptr; + canvasDrawAtlas( + _handle, + (atlas as SkwasmImage).handle, + rawTransforms, + rawRects, + rawColors, + transforms.length, + (blendMode ?? ui.BlendMode.src).index, + rawCullRect, + (paint as SkwasmPaint).handle, + ); + }); @override void drawRawAtlas( @@ -297,9 +341,27 @@ class SkwasmCanvas implements SceneCanvas { ui.BlendMode? blendMode, ui.Rect? cullRect, ui.Paint paint, - ) { - throw UnimplementedError(); - } + ) => withStackScope((StackScope scope) { + final RawRSTransformArray rawTransforms = scope.convertDoublesToNative(rstTransforms); + final RawRect rawRects = scope.convertDoublesToNative(rects); + final RawColorArray rawColors = colors != null + ? scope.convertIntsToUint32Native(colors) + : nullptr; + final RawRect rawCullRect = cullRect != null + ? scope.convertRectToNative(cullRect) + : nullptr; + canvasDrawAtlas( + _handle, + (atlas as SkwasmImage).handle, + rawTransforms, + rawRects, + rawColors, + rstTransforms.length ~/ 4, + (blendMode ?? ui.BlendMode.src).index, + rawCullRect, + (paint as SkwasmPaint).handle, + ); + }); @override void drawShadow( diff --git a/engine/src/flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_canvas.dart b/engine/src/flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_canvas.dart index 6606903759..67637dd158 100644 --- a/engine/src/flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_canvas.dart +++ b/engine/src/flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_canvas.dart @@ -209,6 +209,57 @@ external void canvasDrawParagraph( double y, ); +@Native(symbol: 'canvas_drawVertices', isLeaf: true) +external void canvasDrawVertices( + CanvasHandle handle, + VerticesHandle vertices, + int blendMode, + PaintHandle paint, +); + +@Native(symbol: 'canvas_drawPoints', isLeaf: true) +external void canvasDrawPoints( + CanvasHandle handle, + int pointMode, + RawPointArray points, + int pointCount, + PaintHandle paint, +); + +@Native(symbol: 'canvas_drawAtlas', isLeaf: true) +external void canvasDrawAtlas( + CanvasHandle handle, + ImageHandle atlas, + RawRSTransformArray transforms, + RawRect rects, + RawColorArray colors, + int spriteCount, + int blendMode, + RawRect cullRect, + PaintHandle paint, +); + @Native( symbol: 'canvas_getTransform', isLeaf: true) external void canvasGetTransform(CanvasHandle canvas, RawMatrix44 outMatrix); diff --git a/engine/src/flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_geometry.dart b/engine/src/flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_geometry.dart index 3bf14ad9b2..6222eb279c 100644 --- a/engine/src/flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_geometry.dart +++ b/engine/src/flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_geometry.dart @@ -8,6 +8,7 @@ typedef RawRect = Pointer; typedef RawIRect = Pointer; typedef RawRRect = Pointer; typedef RawPointArray = Pointer; +typedef RawRSTransformArray = Pointer; typedef RawMatrix33 = Pointer; typedef RawMatrix44 = Pointer; typedef RawColorArray = Pointer; diff --git a/engine/src/flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_memory.dart b/engine/src/flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_memory.dart index 9c88cc5509..0396c2ea98 100644 --- a/engine/src/flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_memory.dart +++ b/engine/src/flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_memory.dart @@ -85,6 +85,18 @@ class StackScope { return pointer; } + Pointer convertRectsToNative(List rects) { + final Pointer pointer = allocFloatArray(rects.length * 4); + for (int i = 0; i < rects.length; i++) { + final ui.Rect rect = rects[i]; + pointer[i * 4] = rect.left; + pointer[i * 4 + 1] = rect.top; + pointer[i * 4 + 2] = rect.right; + pointer[i * 4 + 3] = rect.bottom; + } + return pointer; + } + ui.Rect convertRectFromNative(Pointer buffer) { return ui.Rect.fromLTRB( buffer[0], @@ -132,6 +144,18 @@ class StackScope { return pointer; } + Pointer convertRSTransformsToNative(List transforms) { + final Pointer pointer = allocFloatArray(transforms.length * 4); + for (int i = 0; i < transforms.length; i++) { + final ui.RSTransform transform = transforms[i]; + pointer[i * 4] = transform.scos; + pointer[i * 4 + 1] = transform.ssin; + pointer[i * 4 + 2] = transform.tx; + pointer[i * 4 + 3] = transform.ty; + } + return pointer; + } + Pointer convertDoublesToNative(List values) { final Pointer pointer = allocFloatArray(values.length); for (int i = 0; i < values.length; i++) { @@ -140,6 +164,22 @@ class StackScope { return pointer; } + Pointer convertIntsToUint16Native(List values) { + final Pointer pointer = allocUint16Array(values.length); + for (int i = 0; i < values.length; i++) { + pointer[i] = values[i]; + } + return pointer; + } + + Pointer convertIntsToUint32Native(List values) { + final Pointer pointer = allocUint32Array(values.length); + for (int i = 0; i < values.length; i++) { + pointer[i] = values[i]; + } + return pointer; + } + Pointer convertPointArrayToNative(List points) { final Pointer pointer = allocFloatArray(points.length * 2); for (int i = 0; i < points.length; i++) { @@ -162,6 +202,11 @@ class StackScope { return stackAlloc(length).cast(); } + Pointer allocUint16Array(int count) { + final int length = count * sizeOf(); + return stackAlloc(length).cast(); + } + Pointer allocInt32Array(int count) { final int length = count * sizeOf(); return stackAlloc(length).cast(); diff --git a/engine/src/flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_vertices.dart b/engine/src/flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_vertices.dart new file mode 100644 index 0000000000..dd9f61b914 --- /dev/null +++ b/engine/src/flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_vertices.dart @@ -0,0 +1,35 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@DefaultAsset('skwasm') +library skwasm_impl; + +import 'dart:ffi'; + +import 'package:ui/src/engine/skwasm/skwasm_impl.dart'; + +final class RawVertices extends Opaque {} +typedef VerticesHandle = Pointer; + +@Native indices, +)>(symbol: 'vertices_create', isLeaf: true) +external VerticesHandle verticesCreate( + int vertexMode, + int vertexCount, + RawPointArray positions, + RawPointArray textureCoordinates, + RawColorArray colors, + int indexCount, + Pointer indices, +); + +@Native(symbol: 'vertices_dispose', isLeaf: true) +external void verticesDispose(VerticesHandle handle); diff --git a/engine/src/flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/renderer.dart b/engine/src/flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/renderer.dart index d339fa6df9..4a0018acea 100644 --- a/engine/src/flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/renderer.dart +++ b/engine/src/flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/renderer.dart @@ -11,7 +11,6 @@ import 'package:ui/src/engine.dart'; import 'package:ui/src/engine/skwasm/skwasm_impl.dart'; import 'package:ui/ui.dart' as ui; -// TODO(jacksongardner): Actually implement skwasm renderer. class SkwasmRenderer implements Renderer { late DomCanvasElement sceneElement; late SkwasmSurface surface; diff --git a/engine/src/flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/vertices.dart b/engine/src/flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/vertices.dart index 977c68f970..8f26227316 100644 --- a/engine/src/flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/vertices.dart +++ b/engine/src/flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/vertices.dart @@ -4,8 +4,10 @@ // ignore_for_file: avoid_unused_constructor_parameters +import 'dart:ffi'; import 'dart:typed_data'; +import 'package:ui/src/engine/skwasm/skwasm_impl.dart'; import 'package:ui/ui.dart' as ui; class SkwasmVertices implements ui.Vertices { @@ -15,9 +17,28 @@ class SkwasmVertices implements ui.Vertices { List? textureCoordinates, List? colors, List? indices, - }) { - throw UnimplementedError(); - } + }) => withStackScope((StackScope scope) { + final RawPointArray rawPositions = scope.convertPointArrayToNative(positions); + final RawPointArray rawTextureCoordinates = textureCoordinates != null + ? scope.convertPointArrayToNative(textureCoordinates) + : nullptr; + final RawColorArray rawColors = colors != null + ? scope.convertColorArrayToNative(colors) + : nullptr; + final Pointer rawIndices = indices != null + ? scope.convertIntsToUint16Native(indices) + : nullptr; + final int indexCount = indices != null ? indices.length : 0; + return SkwasmVertices._(verticesCreate( + mode.index, + positions.length, + rawPositions, + rawTextureCoordinates, + rawColors, + indexCount, + rawIndices, + )); + }); factory SkwasmVertices.raw( ui.VertexMode mode, @@ -25,14 +46,42 @@ class SkwasmVertices implements ui.Vertices { Float32List? textureCoordinates, Int32List? colors, Uint16List? indices, - }) { - throw UnimplementedError(); - } + }) => withStackScope((StackScope scope) { + final RawPointArray rawPositions = scope.convertDoublesToNative(positions); + final RawPointArray rawTextureCoordinates = textureCoordinates != null + ? scope.convertDoublesToNative(textureCoordinates) + : nullptr; + final RawColorArray rawColors = colors != null + ? scope.convertIntsToUint32Native(colors) + : nullptr; + final Pointer rawIndices = indices != null + ? scope.convertIntsToUint16Native(indices) + : nullptr; + final int indexCount = indices != null ? indices.length : 0; + return SkwasmVertices._(verticesCreate( + mode.index, + positions.length ~/ 2, + rawPositions, + rawTextureCoordinates, + rawColors, + indexCount, + rawIndices, + )); + }); + + SkwasmVertices._(this.handle); + + final VerticesHandle handle; + bool _isDisposed = false; @override - bool get debugDisposed => throw UnimplementedError(); + bool get debugDisposed => _isDisposed; @override void dispose() { + if (!_isDisposed) { + verticesDispose(handle); + _isDisposed = true; + } } } diff --git a/engine/src/flutter/lib/web_ui/skwasm/BUILD.gn b/engine/src/flutter/lib/web_ui/skwasm/BUILD.gn index 96e38583b3..0cba9b2a49 100644 --- a/engine/src/flutter/lib/web_ui/skwasm/BUILD.gn +++ b/engine/src/flutter/lib/web_ui/skwasm/BUILD.gn @@ -27,6 +27,7 @@ wasm_lib("skwasm") { "text/paragraph_style.cpp", "text/strut_style.cpp", "text/text_style.cpp", + "vertices.cpp", "wrappers.h", ] diff --git a/engine/src/flutter/lib/web_ui/skwasm/canvas.cpp b/engine/src/flutter/lib/web_ui/skwasm/canvas.cpp index 47921d16fb..16318cef68 100644 --- a/engine/src/flutter/lib/web_ui/skwasm/canvas.cpp +++ b/engine/src/flutter/lib/web_ui/skwasm/canvas.cpp @@ -7,6 +7,7 @@ #include "wrappers.h" #include "third_party/skia/include/core/SkPoint3.h" +#include "third_party/skia/include/core/SkVertices.h" #include "third_party/skia/include/utils/SkShadowUtils.h" #include "third_party/skia/modules/skparagraph/include/Paragraph.h" @@ -227,6 +228,34 @@ SKWASM_EXPORT void canvas_drawImageNine(SkCanvas* canvas, filterModeForQuality(quality), paint); } +SKWASM_EXPORT void canvas_drawVertices(SkCanvas* canvas, + SkVertices* vertices, + SkBlendMode mode, + SkPaint* paint) { + canvas->drawVertices(sk_ref_sp(vertices), mode, *paint); +} + +SKWASM_EXPORT void canvas_drawPoints(SkCanvas* canvas, + SkCanvas::PointMode mode, + SkPoint* points, + int pointCount, + SkPaint* paint) { + canvas->drawPoints(mode, pointCount, points, *paint); +} + +SKWASM_EXPORT void canvas_drawAtlas(SkCanvas* canvas, + SkImage* atlas, + SkRSXform* transforms, + SkRect* rects, + SkColor* colors, + int spriteCount, + SkBlendMode mode, + SkRect* cullRect, + SkPaint* paint) { + canvas->drawAtlas(atlas, transforms, rects, colors, spriteCount, mode, + SkSamplingOptions{}, cullRect, paint); +} + SKWASM_EXPORT void canvas_getTransform(SkCanvas* canvas, SkM44* outTransform) { *outTransform = canvas->getLocalToDevice(); } diff --git a/engine/src/flutter/lib/web_ui/skwasm/vertices.cpp b/engine/src/flutter/lib/web_ui/skwasm/vertices.cpp new file mode 100644 index 0000000000..caf187f1c7 --- /dev/null +++ b/engine/src/flutter/lib/web_ui/skwasm/vertices.cpp @@ -0,0 +1,23 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "export.h" + +#include "third_party/skia/include/core/SkVertices.h" + +SKWASM_EXPORT SkVertices* vertices_create(SkVertices::VertexMode vertexMode, + int vertexCount, + SkPoint* positions, + SkPoint* textureCoordinates, + SkColor* colors, + int indexCount, + uint16_t* indices) { + return SkVertices::MakeCopy(vertexMode, vertexCount, positions, + textureCoordinates, colors, indexCount, indices) + .release(); +} + +SKWASM_EXPORT void vertices_dispose(SkVertices* vertices) { + vertices->unref(); +} diff --git a/engine/src/flutter/lib/web_ui/test/html/drawing/canvas_draw_points_golden_test.dart b/engine/src/flutter/lib/web_ui/test/html/drawing/canvas_draw_points_golden_test.dart deleted file mode 100644 index 97e19fd0e7..0000000000 --- a/engine/src/flutter/lib/web_ui/test/html/drawing/canvas_draw_points_golden_test.dart +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'dart:typed_data'; - -import 'package:test/bootstrap/browser.dart'; -import 'package:test/test.dart'; -import 'package:ui/src/engine.dart'; -import 'package:ui/ui.dart'; - -import 'package:web_engine_tester/golden_tester.dart'; - -void main() { - internalBootstrapBrowserTest(() => testMain); -} - -Future testMain() async { - const Rect region = Rect.fromLTWH(0, 0, 400, 600); - - late BitmapCanvas canvas; - - setUp(() { - canvas = BitmapCanvas(region, RenderStrategy()); - }); - - tearDown(() { - canvas.rootElement.remove(); - }); - - test('draws points in all 3 modes', () async { - final SurfacePaintData paint = SurfacePaintData(); - paint.strokeWidth = 2.0; - paint.color = 0xFF0000FF; - final Float32List points = offsetListToFloat32List(const [ - Offset(10, 10), - Offset(50, 10), - Offset(70, 70), - Offset(170, 70) - ]); - canvas.drawPoints(PointMode.points, points, paint); - final Float32List points2 = offsetListToFloat32List(const [ - Offset(10, 110), - Offset(50, 110), - Offset(70, 170), - Offset(170, 170) - ]); - canvas.drawPoints(PointMode.lines, points2, paint); - final Float32List points3 = offsetListToFloat32List(const [ - Offset(10, 210), - Offset(50, 210), - Offset(70, 270), - Offset(170, 270) - ]); - canvas.drawPoints(PointMode.polygon, points3, paint); - - domDocument.body!.append(canvas.rootElement); - await matchGoldenFile('canvas_draw_points.png', region: region); - }); - - test('Should draw points with strokeWidth', () async { - final SurfacePaintData nullStrokePaint = - SurfacePaintData()..color = 0xffff0000; - canvas.drawPoints(PointMode.lines, Float32List.fromList([ - 30.0, 20.0, 200.0, 20.0]), nullStrokePaint); - final SurfacePaintData strokePaint1 = SurfacePaintData() - ..strokeWidth = 1.0 - ..color = 0xff0000ff; - canvas.drawPoints(PointMode.lines, Float32List.fromList([ - 30.0, 30.0, 200.0, 30.0]), strokePaint1); - final SurfacePaintData strokePaint3 = SurfacePaintData() - ..strokeWidth = 3.0 - ..color = 0xff00a000; - canvas.drawPoints(PointMode.lines, Float32List.fromList([ - 30.0, 40.0, 200.0, 40.0]), strokePaint3); - canvas.drawPoints(PointMode.points, Float32List.fromList([ - 30.0, 50.0, 40.0, 50.0, 50.0, 50.0]), strokePaint3); - domDocument.body!.append(canvas.rootElement); - await matchGoldenFile('canvas_draw_points_stroke.png', region: region); - }); -} diff --git a/engine/src/flutter/lib/web_ui/test/ui/canvas_draw_points_golden_test.dart b/engine/src/flutter/lib/web_ui/test/ui/canvas_draw_points_golden_test.dart new file mode 100644 index 0000000000..879536d633 --- /dev/null +++ b/engine/src/flutter/lib/web_ui/test/ui/canvas_draw_points_golden_test.dart @@ -0,0 +1,119 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:typed_data'; + +import 'package:test/bootstrap/browser.dart'; +import 'package:test/test.dart'; +import 'package:ui/src/engine.dart'; +import 'package:ui/ui.dart' as ui; + +import 'package:web_engine_tester/golden_tester.dart'; + +import '../common/test_initialization.dart'; +import 'utils.dart'; + +void main() { + internalBootstrapBrowserTest(() => testMain); +} + +Future testMain() async { + setUpUnitTests( + setUpTestViewDimensions: false, + ); + + const ui.Rect region = ui.Rect.fromLTWH(0, 0, 400, 600); + + late ui.PictureRecorder recorder; + late ui.Canvas canvas; + + setUp(() { + recorder = ui.PictureRecorder(); + canvas = ui.Canvas(recorder, region); + }); + + tearDown(() { + }); + + test('draws points in all 3 modes', () async { + final ui.Paint paint = ui.Paint(); + paint.strokeWidth = 2.0; + paint.color = const ui.Color(0xFF00FF00); + const List points = [ + ui.Offset(10, 10), + ui.Offset(50, 10), + ui.Offset(70, 70), + ui.Offset(170, 70) + ]; + canvas.drawPoints(ui.PointMode.points, points, paint); + const List points2 = [ + ui.Offset(10, 110), + ui.Offset(50, 110), + ui.Offset(70, 170), + ui.Offset(170, 170) + ]; + canvas.drawPoints(ui.PointMode.lines, points2, paint); + const List points3 = [ + ui.Offset(10, 210), + ui.Offset(50, 210), + ui.Offset(70, 270), + ui.Offset(170, 270) + ]; + canvas.drawPoints(ui.PointMode.polygon, points3, paint); + + await drawPictureUsingCurrentRenderer(recorder.endRecording()); + await matchGoldenFile('ui_canvas_draw_points.png', region: region); + }); + + test('draws raw points in all 3 modes', () async { + final ui.Paint paint = ui.Paint(); + paint.strokeWidth = 2.0; + paint.color = const ui.Color(0xFF0000FF); + final Float32List points = offsetListToFloat32List(const [ + ui.Offset(10, 10), + ui.Offset(50, 10), + ui.Offset(70, 70), + ui.Offset(170, 70) + ]); + canvas.drawRawPoints(ui.PointMode.points, points, paint); + final Float32List points2 = offsetListToFloat32List(const [ + ui.Offset(10, 110), + ui.Offset(50, 110), + ui.Offset(70, 170), + ui.Offset(170, 170) + ]); + canvas.drawRawPoints(ui.PointMode.lines, points2, paint); + final Float32List points3 = offsetListToFloat32List(const [ + ui.Offset(10, 210), + ui.Offset(50, 210), + ui.Offset(70, 270), + ui.Offset(170, 270) + ]); + canvas.drawRawPoints(ui.PointMode.polygon, points3, paint); + + await drawPictureUsingCurrentRenderer(recorder.endRecording()); + await matchGoldenFile('ui_canvas_draw_raw_points.png', region: region); + }); + + test('Should draw points with strokeWidth', () async { + final ui.Paint nullStrokePaint = + ui.Paint()..color = const ui.Color(0xffff0000); + canvas.drawRawPoints(ui.PointMode.lines, Float32List.fromList([ + 30.0, 20.0, 200.0, 20.0]), nullStrokePaint); + final ui.Paint strokePaint1 = ui.Paint() + ..strokeWidth = 1.0 + ..color = const ui.Color(0xff0000ff); + canvas.drawRawPoints(ui.PointMode.lines, Float32List.fromList([ + 30.0, 30.0, 200.0, 30.0]), strokePaint1); + final ui.Paint strokePaint3 = ui.Paint() + ..strokeWidth = 3.0 + ..color = const ui.Color(0xff00a000); + canvas.drawRawPoints(ui.PointMode.lines, Float32List.fromList([ + 30.0, 40.0, 200.0, 40.0]), strokePaint3); + canvas.drawRawPoints(ui.PointMode.points, Float32List.fromList([ + 30.0, 50.0, 40.0, 50.0, 50.0, 50.0]), strokePaint3); + await drawPictureUsingCurrentRenderer(recorder.endRecording()); + await matchGoldenFile('ui_canvas_draw_points_stroke.png', region: region); + }); +} diff --git a/engine/src/flutter/lib/web_ui/test/ui/draw_atlas_golden_test.dart b/engine/src/flutter/lib/web_ui/test/ui/draw_atlas_golden_test.dart new file mode 100644 index 0000000000..30ade95b7c --- /dev/null +++ b/engine/src/flutter/lib/web_ui/test/ui/draw_atlas_golden_test.dart @@ -0,0 +1,203 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:math' as math; +import 'dart:typed_data'; + +import 'package:test/bootstrap/browser.dart'; +import 'package:test/test.dart'; +import 'package:ui/ui.dart' as ui; +import 'package:web_engine_tester/golden_tester.dart'; + +import '../common/test_initialization.dart'; +import 'utils.dart'; + +void main() { + internalBootstrapBrowserTest(() => testMain); +} + +const ui.Rect kBlueSquareRegion = ui.Rect.fromLTRB(0, 0, 25, 25); +const ui.Rect kRedCircleRegion = ui.Rect.fromLTRB(25, 0, 50, 25); +const ui.Rect kMagentaStarRegion = ui.Rect.fromLTRB(0, 25, 30, 55); +const ui.Rect kGreenSquiggleRegion = ui.Rect.fromLTRB(30, 25, 50, 55); +const ui.Rect kTotalAtlasRegion = ui.Rect.fromLTRB(0, 0, 55, 55); + +ui.Image generateAtlas() { + final ui.PictureRecorder recorder = ui.PictureRecorder(); + final ui.Canvas canvas = ui.Canvas(recorder); + + canvas.drawColor(const ui.Color(0), ui.BlendMode.src); + + // Draw the square + canvas.save(); + canvas.clipRect(kBlueSquareRegion); + canvas.drawPaint(ui.Paint()..color = const ui.Color(0xFF0000FF)); + canvas.restore(); + + // Draw the circle + canvas.save(); + canvas.clipRect(kRedCircleRegion); + canvas.drawCircle(kRedCircleRegion.center, kRedCircleRegion.width / 2.0, ui.Paint()..color = const ui.Color(0xFFFF0000)); + canvas.restore(); + + // Draw the star + canvas.save(); + canvas.clipRect(kMagentaStarRegion); + final ui.Offset starCenter = kMagentaStarRegion.center; + final double radius = kMagentaStarRegion.height / 2.0; + + // Start at the top (rotated 90 degrees) + double theta = -math.pi / 2.0; + + // Rotate two fifths of the circle each time + const double rotation = 4.0 * math.pi / 5.0; + final ui.Path starPath = ui.Path(); + starPath.moveTo( + starCenter.dx + radius * math.cos(theta), + starCenter.dy + radius * math.sin(theta) + ); + for (int i = 0; i < 5; i++) { + theta += rotation; + starPath.lineTo( + starCenter.dx + radius * math.cos(theta), + starCenter.dy + radius * math.sin(theta) + ); + } + canvas.drawPath( + starPath, + ui.Paint() + ..color = const ui.Color(0xFFFF00FF) + ..style = ui.PaintingStyle.fill + ); + canvas.restore(); + + // Draw the Squiggle + canvas.save(); + canvas.clipRect(kGreenSquiggleRegion); + final ui.Path squigglePath = ui.Path(); + squigglePath.moveTo(kGreenSquiggleRegion.topCenter.dx, kGreenSquiggleRegion.topCenter.dy); + squigglePath.cubicTo( + kGreenSquiggleRegion.left - 10.0, kGreenSquiggleRegion.top + kGreenSquiggleRegion.height * 0.33, + kGreenSquiggleRegion.right + 10.0, kGreenSquiggleRegion.top + kGreenSquiggleRegion.height * 0.66, + kGreenSquiggleRegion.bottomCenter.dx, kGreenSquiggleRegion.bottomCenter.dy + ); + canvas.drawPath( + squigglePath, + ui.Paint() + ..color = const ui.Color(0xFF00FF00) + ..style = ui.PaintingStyle.stroke + ..strokeWidth = 5.0 + ); + canvas.restore(); + + final ui.Picture picture = recorder.endRecording(); + return picture.toImageSync( + kTotalAtlasRegion.width.toInt(), + kTotalAtlasRegion.height.toInt() + ); +} + +Future testMain() async { + setUpUnitTests( + setUpTestViewDimensions: false, + ); + + const ui.Rect region = ui.Rect.fromLTWH(0, 0, 300, 300); + test('drawAtlas', () async { + final ui.PictureRecorder recorder = ui.PictureRecorder(); + final ui.Canvas canvas = ui.Canvas(recorder, region); + final ui.Image atlas = generateAtlas(); + final List transforms = List.generate( + 12, (int index) { + const double radius = 100; + const double rotation = math.pi / 6.0; + final double angle = rotation * index; + final double scos = math.sin(angle); + final double ssin = math.cos(angle); + return ui.RSTransform( + scos, + ssin, + region.center.dx + radius * scos, + region.center.dy + radius * ssin, + ); + } + ); + final List rects = [ + kBlueSquareRegion, + kRedCircleRegion, + kMagentaStarRegion, + kGreenSquiggleRegion, + kBlueSquareRegion, + kRedCircleRegion, + kMagentaStarRegion, + kGreenSquiggleRegion, + kBlueSquareRegion, + kRedCircleRegion, + kMagentaStarRegion, + kGreenSquiggleRegion, + ]; + canvas.drawAtlas( + atlas, transforms, rects, null, null, null, ui.Paint()); + + await drawPictureUsingCurrentRenderer(recorder.endRecording()); + await matchGoldenFile('ui_draw_atlas.png', region: region); + }, skip: isHtml); // HTML renderer doesn't support drawAtlas + + test('drawAtlasRaw', () async { + final ui.PictureRecorder recorder = ui.PictureRecorder(); + final ui.Canvas canvas = ui.Canvas(recorder, region); + final ui.Image atlas = generateAtlas(); + final Float32List transforms = Float32List(12 * 4); + for (int i = 0; i < 12; i++) { + const double radius = 100; + const double rotation = math.pi / 6.0; + final double angle = rotation * i; + final double scos = math.sin(angle); + final double ssin = math.cos(angle); + transforms[i * 4] = scos; + transforms[i * 4 + 1] = ssin; + transforms[i * 4 + 2] = region.center.dx + radius * scos; + transforms[i * 4 + 3] = region.center.dy + radius * ssin; + } + final List rects = [ + kBlueSquareRegion, + kRedCircleRegion, + kMagentaStarRegion, + kGreenSquiggleRegion, + kBlueSquareRegion, + kRedCircleRegion, + kMagentaStarRegion, + kGreenSquiggleRegion, + kBlueSquareRegion, + kRedCircleRegion, + kMagentaStarRegion, + kGreenSquiggleRegion, + ]; + final Float32List rawRects = Float32List(rects.length * 4); + for (int i = 0; i < rects.length; i++) { + rawRects[i * 4] = rects[i].left; + rawRects[i * 4 + 1] = rects[i].top; + rawRects[i * 4 + 2] = rects[i].right; + rawRects[i * 4 + 3] = rects[i].bottom; + } + + final Int32List colors = Int32List(12); + for (int i = 0; i < 12; i++) { + final int rgb = 0xFF << (8 * (i % 3)); + colors[i] = 0xFF000000 | rgb; + } + canvas.drawRawAtlas( + atlas, + transforms, + rawRects, + colors, + ui.BlendMode.dstIn, + null, + ui.Paint() + ); + + await drawPictureUsingCurrentRenderer(recorder.endRecording()); + await matchGoldenFile('ui_draw_atlas_raw.png', region: region); + }, skip: isHtml); // HTML renderer doesn't support drawAtlas +} diff --git a/engine/src/flutter/lib/web_ui/test/canvaskit/vertices_test.dart b/engine/src/flutter/lib/web_ui/test/ui/vertices_test.dart similarity index 76% rename from engine/src/flutter/lib/web_ui/test/canvaskit/vertices_test.dart rename to engine/src/flutter/lib/web_ui/test/ui/vertices_test.dart index a070522c5f..e7373bb0aa 100644 --- a/engine/src/flutter/lib/web_ui/test/canvaskit/vertices_test.dart +++ b/engine/src/flutter/lib/web_ui/test/ui/vertices_test.dart @@ -6,12 +6,11 @@ import 'dart:typed_data'; import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; -import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; import 'package:web_engine_tester/golden_tester.dart'; -import '../common/matchers.dart'; -import 'common.dart'; +import '../common/test_initialization.dart'; +import 'utils.dart'; void main() { internalBootstrapBrowserTest(() => testMain); @@ -19,56 +18,49 @@ void main() { void testMain() { group('Vertices', () { - setUpCanvasKitTest(); + setUpUnitTests(setUpTestViewDimensions: false); test('can be constructed, drawn, and disposed of', () { - final CkVertices vertices = _testVertices(); - expect(vertices, isA()); - expect(vertices.skiaObject, isNotNull); + final ui.Vertices vertices = _testVertices(); expect(vertices.debugDisposed, isFalse); - final CkPictureRecorder recorder = CkPictureRecorder(); - final CkCanvas canvas = - recorder.beginRecording(const ui.Rect.fromLTRB(0, 0, 100, 100)); + final ui.PictureRecorder recorder = ui.PictureRecorder(); + final ui.Canvas canvas = ui.Canvas( + recorder, + const ui.Rect.fromLTRB(0, 0, 100, 100) + ); canvas.drawVertices( vertices, ui.BlendMode.srcOver, - CkPaint(), + ui.Paint(), ); vertices.dispose(); expect(vertices.debugDisposed, isTrue); - expect(() => vertices.skiaObject, throwsA(isAssertionError)); }); }); test('Vertices are not anti-aliased by default', () async { const ui.Rect region = ui.Rect.fromLTRB(0, 0, 500, 500); - final CkPictureRecorder recorder = CkPictureRecorder(); - final CkCanvas canvas = recorder.beginRecording(region); - final CkVertices vertices = ui.Vertices.raw( + final ui.PictureRecorder recorder = ui.PictureRecorder(); + final ui.Canvas canvas = ui.Canvas(recorder, region); + final ui.Vertices vertices = ui.Vertices.raw( ui.VertexMode.triangles, Float32List.fromList(_circularVertices), indices: Uint16List.fromList(_circularVertexIndices), - ) as CkVertices; + ); canvas.scale(3.0, 3.0); canvas.drawVertices( vertices, ui.BlendMode.srcOver, - CkPaint()..color = const ui.Color(0xFFFF0000), + ui.Paint()..color = const ui.Color(0xFFFF0000), ); - final CkPicture verticesPicture = recorder.endRecording(); - - final LayerSceneBuilder builder = LayerSceneBuilder(); - builder.pushOffset(0, 0); - builder.addPicture(ui.Offset.zero, verticesPicture); - CanvasKitRenderer.instance.rasterizer - .draw(builder.build().layerTree); - await matchGoldenFile('canvaskit_vertices_antialiased.png', region: region); - }, skip: isSafari); + await drawPictureUsingCurrentRenderer(recorder.endRecording()); + await matchGoldenFile('ui_vertices_antialiased.png', region: region); + }, skip: isHtml); // https://github.com/flutter/flutter/issues/127454 } -CkVertices _testVertices() { +ui.Vertices _testVertices() { return ui.Vertices( ui.VertexMode.triangles, const [ @@ -87,7 +79,7 @@ CkVertices _testVertices() { ui.Color.fromRGBO(0, 0, 255, 1.0), ], indices: [0, 1, 2], - ) as CkVertices; + ); } const List _circularVertices = [