blob: d5d9a333215e5a595760629c43eb402b95b6dd15 [file] [log] [blame]
// 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.
// @dart = 2.6
import 'dart:typed_data';
import 'package:test/test.dart';
import 'package:ui/src/engine.dart';
import 'package:ui/ui.dart' as ui;
import 'common.dart';
void main() {
group('CanvasKit API', () {
setUpAll(() async {
await ui.webOnlyInitializePlatform();
});
test('Using CanvasKit', () {
expect(experimentalUseSkia, true);
});
_blendModeTests();
_paintStyleTests();
_strokeCapTests();
_strokeJoinTests();
_filterQualityTests();
_blurStyleTests();
_tileModeTests();
_fillTypeTests();
_pathOpTests();
_clipOpTests();
_pointModeTests();
_vertexModeTests();
_imageTests();
_shaderTests();
_paintTests();
_maskFilterTests();
_colorFilterTests();
_imageFilterTests();
_mallocTests();
_sharedColorTests();
_toSkPointTests();
_toSkColorStopsTests();
_toSkMatrixFromFloat32Tests();
_skSkRectTests();
_skVerticesTests();
group('SkPath', () {
_pathTests();
});
group('SkCanvas', () {
_canvasTests();
});
// TODO: https://github.com/flutter/flutter/issues/60040
}, skip: isIosSafari);
}
void _blendModeTests() {
test('blend mode mapping is correct', () {
expect(canvasKitJs.BlendMode.Clear.value, ui.BlendMode.clear.index);
expect(canvasKitJs.BlendMode.Src.value, ui.BlendMode.src.index);
expect(canvasKitJs.BlendMode.Dst.value, ui.BlendMode.dst.index);
expect(canvasKitJs.BlendMode.SrcOver.value, ui.BlendMode.srcOver.index);
expect(canvasKitJs.BlendMode.DstOver.value, ui.BlendMode.dstOver.index);
expect(canvasKitJs.BlendMode.SrcIn.value, ui.BlendMode.srcIn.index);
expect(canvasKitJs.BlendMode.DstIn.value, ui.BlendMode.dstIn.index);
expect(canvasKitJs.BlendMode.SrcOut.value, ui.BlendMode.srcOut.index);
expect(canvasKitJs.BlendMode.DstOut.value, ui.BlendMode.dstOut.index);
expect(canvasKitJs.BlendMode.SrcATop.value, ui.BlendMode.srcATop.index);
expect(canvasKitJs.BlendMode.DstATop.value, ui.BlendMode.dstATop.index);
expect(canvasKitJs.BlendMode.Xor.value, ui.BlendMode.xor.index);
expect(canvasKitJs.BlendMode.Plus.value, ui.BlendMode.plus.index);
expect(canvasKitJs.BlendMode.Modulate.value, ui.BlendMode.modulate.index);
expect(canvasKitJs.BlendMode.Screen.value, ui.BlendMode.screen.index);
expect(canvasKitJs.BlendMode.Overlay.value, ui.BlendMode.overlay.index);
expect(canvasKitJs.BlendMode.Darken.value, ui.BlendMode.darken.index);
expect(canvasKitJs.BlendMode.Lighten.value, ui.BlendMode.lighten.index);
expect(canvasKitJs.BlendMode.ColorDodge.value, ui.BlendMode.colorDodge.index);
expect(canvasKitJs.BlendMode.ColorBurn.value, ui.BlendMode.colorBurn.index);
expect(canvasKitJs.BlendMode.HardLight.value, ui.BlendMode.hardLight.index);
expect(canvasKitJs.BlendMode.SoftLight.value, ui.BlendMode.softLight.index);
expect(canvasKitJs.BlendMode.Difference.value, ui.BlendMode.difference.index);
expect(canvasKitJs.BlendMode.Exclusion.value, ui.BlendMode.exclusion.index);
expect(canvasKitJs.BlendMode.Multiply.value, ui.BlendMode.multiply.index);
expect(canvasKitJs.BlendMode.Hue.value, ui.BlendMode.hue.index);
expect(canvasKitJs.BlendMode.Saturation.value, ui.BlendMode.saturation.index);
expect(canvasKitJs.BlendMode.Color.value, ui.BlendMode.color.index);
expect(canvasKitJs.BlendMode.Luminosity.value, ui.BlendMode.luminosity.index);
});
test('ui.BlendMode converts to SkBlendMode', () {
for (ui.BlendMode blendMode in ui.BlendMode.values) {
expect(toSkBlendMode(blendMode).value, blendMode.index);
}
});
}
void _paintStyleTests() {
test('paint style mapping is correct', () {
expect(canvasKitJs.PaintStyle.Fill.value, ui.PaintingStyle.fill.index);
expect(canvasKitJs.PaintStyle.Stroke.value, ui.PaintingStyle.stroke.index);
});
test('ui.PaintingStyle converts to SkPaintStyle', () {
for (ui.PaintingStyle style in ui.PaintingStyle.values) {
expect(toSkPaintStyle(style).value, style.index);
}
});
}
void _strokeCapTests() {
test('stroke cap mapping is correct', () {
expect(canvasKitJs.StrokeCap.Butt.value, ui.StrokeCap.butt.index);
expect(canvasKitJs.StrokeCap.Round.value, ui.StrokeCap.round.index);
expect(canvasKitJs.StrokeCap.Square.value, ui.StrokeCap.square.index);
});
test('ui.StrokeCap converts to SkStrokeCap', () {
for (ui.StrokeCap cap in ui.StrokeCap.values) {
expect(toSkStrokeCap(cap).value, cap.index);
}
});
}
void _strokeJoinTests() {
test('stroke cap mapping is correct', () {
expect(canvasKitJs.StrokeJoin.Miter.value, ui.StrokeJoin.miter.index);
expect(canvasKitJs.StrokeJoin.Round.value, ui.StrokeJoin.round.index);
expect(canvasKitJs.StrokeJoin.Bevel.value, ui.StrokeJoin.bevel.index);
});
test('ui.StrokeJoin converts to SkStrokeJoin', () {
for (ui.StrokeJoin join in ui.StrokeJoin.values) {
expect(toSkStrokeJoin(join).value, join.index);
}
});
}
void _filterQualityTests() {
test('filter quality mapping is correct', () {
expect(canvasKitJs.FilterQuality.None.value, ui.FilterQuality.none.index);
expect(canvasKitJs.FilterQuality.Low.value, ui.FilterQuality.low.index);
expect(canvasKitJs.FilterQuality.Medium.value, ui.FilterQuality.medium.index);
expect(canvasKitJs.FilterQuality.High.value, ui.FilterQuality.high.index);
});
test('ui.FilterQuality converts to SkFilterQuality', () {
for (ui.FilterQuality cap in ui.FilterQuality.values) {
expect(toSkFilterQuality(cap).value, cap.index);
}
});
}
void _blurStyleTests() {
test('blur style mapping is correct', () {
expect(canvasKitJs.BlurStyle.Normal.value, ui.BlurStyle.normal.index);
expect(canvasKitJs.BlurStyle.Solid.value, ui.BlurStyle.solid.index);
expect(canvasKitJs.BlurStyle.Outer.value, ui.BlurStyle.outer.index);
expect(canvasKitJs.BlurStyle.Inner.value, ui.BlurStyle.inner.index);
});
test('ui.BlurStyle converts to SkBlurStyle', () {
for (ui.BlurStyle style in ui.BlurStyle.values) {
expect(toSkBlurStyle(style).value, style.index);
}
});
}
void _tileModeTests() {
test('tile mode mapping is correct', () {
expect(canvasKitJs.TileMode.Clamp.value, ui.TileMode.clamp.index);
expect(canvasKitJs.TileMode.Repeat.value, ui.TileMode.repeated.index);
expect(canvasKitJs.TileMode.Mirror.value, ui.TileMode.mirror.index);
});
test('ui.TileMode converts to SkTileMode', () {
for (ui.TileMode mode in ui.TileMode.values) {
expect(toSkTileMode(mode).value, mode.index);
}
});
}
void _fillTypeTests() {
test('fill type mapping is correct', () {
expect(canvasKitJs.FillType.Winding.value, ui.PathFillType.nonZero.index);
expect(canvasKitJs.FillType.EvenOdd.value, ui.PathFillType.evenOdd.index);
});
test('ui.PathFillType converts to SkFillType', () {
for (ui.PathFillType type in ui.PathFillType.values) {
expect(toSkFillType(type).value, type.index);
}
});
}
void _pathOpTests() {
// TODO(yjbanov): https://github.com/flutter/flutter/issues/61403
// test('path op mapping is correct', () {
// expect(canvasKitJs.PathOp.Difference.value, ui.PathOperation.difference.index);
// expect(canvasKitJs.PathOp.Intersect.value, ui.PathOperation.intersect.index);
// expect(canvasKitJs.PathOp.Union.value, ui.PathOperation.union.index);
// expect(canvasKitJs.PathOp.XOR.value, ui.PathOperation.xor.index);
// expect(canvasKitJs.PathOp.ReverseDifference, ui.PathOperation.reverseDifference.index);
// });
// test('ui.PathOperation converts to SkPathOp', () {
// for (ui.PathOperation op in ui.PathOperation.values) {
// expect(toSkPathOp(op).value, op.index);
// }
// });
}
void _clipOpTests() {
test('clip op mapping is correct', () {
expect(canvasKitJs.ClipOp.Difference.value, ui.ClipOp.difference.index);
expect(canvasKitJs.ClipOp.Intersect.value, ui.ClipOp.intersect.index);
});
test('ui.ClipOp converts to SkClipOp', () {
for (ui.ClipOp op in ui.ClipOp.values) {
expect(toSkClipOp(op).value, op.index);
}
});
}
void _pointModeTests() {
test('point mode mapping is correct', () {
expect(canvasKitJs.PointMode.Points.value, ui.PointMode.points.index);
expect(canvasKitJs.PointMode.Lines.value, ui.PointMode.lines.index);
expect(canvasKitJs.PointMode.Polygon.value, ui.PointMode.polygon.index);
});
test('ui.PointMode converts to SkPointMode', () {
for (ui.PointMode op in ui.PointMode.values) {
expect(toSkPointMode(op).value, op.index);
}
});
}
void _vertexModeTests() {
test('vertex mode mapping is correct', () {
expect(canvasKitJs.VertexMode.Triangles.value, ui.VertexMode.triangles.index);
expect(canvasKitJs.VertexMode.TrianglesStrip.value, ui.VertexMode.triangleStrip.index);
expect(canvasKitJs.VertexMode.TriangleFan.value, ui.VertexMode.triangleFan.index);
});
test('ui.VertexMode converts to SkVertexMode', () {
for (ui.VertexMode op in ui.VertexMode.values) {
expect(toSkVertexMode(op).value, op.index);
}
});
}
void _imageTests() {
test('MakeAnimatedImageFromEncoded makes a non-animated image', () {
final SkAnimatedImage nonAnimated = canvasKitJs.MakeAnimatedImageFromEncoded(kTransparentImage);
expect(nonAnimated.getFrameCount(), 1);
expect(nonAnimated.getRepetitionCount(), 0);
expect(nonAnimated.width(), 1);
expect(nonAnimated.height(), 1);
final SkImage frame = nonAnimated.getCurrentFrame();
expect(frame.width(), 1);
expect(frame.height(), 1);
expect(nonAnimated.decodeNextFrame(), -1);
expect(frame.makeShader(canvasKitJs.TileMode.Repeat, canvasKitJs.TileMode.Mirror), isNotNull);
});
test('MakeAnimatedImageFromEncoded makes an animated image', () {
final SkAnimatedImage animated = canvasKitJs.MakeAnimatedImageFromEncoded(kAnimatedGif);
expect(animated.getFrameCount(), 3);
expect(animated.getRepetitionCount(), -1); // animates forever
expect(animated.width(), 1);
expect(animated.height(), 1);
for (int i = 0; i < 100; i++) {
final SkImage frame = animated.getCurrentFrame();
expect(frame.width(), 1);
expect(frame.height(), 1);
expect(animated.decodeNextFrame(), 100);
}
});
}
void _shaderTests() {
test('MakeLinearGradient', () {
expect(_makeTestShader(), isNotNull);
});
test('MakeRadialGradient', () {
expect(canvasKitJs.SkShader.MakeRadialGradient(
Float32List.fromList([1, 1]),
10.0,
<Float32List>[
Float32List.fromList([0, 0, 0, 1]),
Float32List.fromList([1, 1, 1, 1]),
],
Float32List.fromList([0, 1]),
canvasKitJs.TileMode.Repeat,
toSkMatrixFromFloat32(Matrix4.identity().storage),
0,
), isNotNull);
});
test('MakeTwoPointConicalGradient', () {
expect(canvasKitJs.SkShader.MakeTwoPointConicalGradient(
Float32List.fromList([1, 1]),
10.0,
Float32List.fromList([1, 1]),
10.0,
<Float32List>[
Float32List.fromList([0, 0, 0, 1]),
Float32List.fromList([1, 1, 1, 1]),
],
Float32List.fromList([0, 1]),
canvasKitJs.TileMode.Repeat,
toSkMatrixFromFloat32(Matrix4.identity().storage),
0,
), isNotNull);
});
}
SkShader _makeTestShader() {
return canvasKitJs.SkShader.MakeLinearGradient(
Float32List.fromList([0, 0]),
Float32List.fromList([1, 1]),
[
Float32List.fromList([255, 0, 0, 255]),
],
Float32List.fromList([0, 1]),
canvasKitJs.TileMode.Repeat,
);
}
void _paintTests() {
test('can make SkPaint', () async {
final SkPaint paint = SkPaint();
paint.setBlendMode(canvasKitJs.BlendMode.SrcOut);
paint.setStyle(canvasKitJs.PaintStyle.Stroke);
paint.setStrokeWidth(3.0);
paint.setStrokeCap(canvasKitJs.StrokeCap.Round);
paint.setStrokeJoin(canvasKitJs.StrokeJoin.Bevel);
paint.setAntiAlias(true);
paint.setColorInt(0x00FFCCAA);
paint.setShader(_makeTestShader());
paint.setMaskFilter(canvasKitJs.MakeBlurMaskFilter(
canvasKitJs.BlurStyle.Outer,
2.0,
true,
));
paint.setFilterQuality(canvasKitJs.FilterQuality.High);
paint.setColorFilter(canvasKitJs.SkColorFilter.MakeLinearToSRGBGamma());
paint.setStrokeMiter(1.4);
paint.setImageFilter(canvasKitJs.SkImageFilter.MakeBlur(
1,
2,
canvasKitJs.TileMode.Repeat,
null,
));
});
}
void _maskFilterTests() {
test('MakeBlurMaskFilter', () {
expect(canvasKitJs.MakeBlurMaskFilter(
canvasKitJs.BlurStyle.Outer,
5.0,
false,
), isNotNull);
});
}
void _colorFilterTests() {
test('MakeBlend', () {
expect(
canvasKitJs.SkColorFilter.MakeBlend(
Float32List.fromList([0, 0, 0, 1]),
canvasKitJs.BlendMode.SrcATop,
),
isNotNull,
);
});
test('MakeMatrix', () {
expect(
canvasKitJs.SkColorFilter.MakeMatrix(
Float32List(20),
),
isNotNull,
);
});
test('MakeSRGBToLinearGamma', () {
expect(
canvasKitJs.SkColorFilter.MakeSRGBToLinearGamma(),
isNotNull,
);
});
test('MakeLinearToSRGBGamma', () {
expect(
canvasKitJs.SkColorFilter.MakeLinearToSRGBGamma(),
isNotNull,
);
});
}
void _imageFilterTests() {
test('MakeBlur', () {
expect(
canvasKitJs.SkImageFilter.MakeBlur(1, 2, canvasKitJs.TileMode.Repeat, null),
isNotNull,
);
});
test('MakeMatrixTransform', () {
expect(
canvasKitJs.SkImageFilter.MakeMatrixTransform(
toSkMatrixFromFloat32(Matrix4.identity().storage),
canvasKitJs.FilterQuality.Medium,
null,
),
isNotNull,
);
});
}
void _mallocTests() {
test('SkFloat32List', () {
for (int size = 0; size < 1000; size++) {
final SkFloat32List skList = mallocFloat32List(4);
expect(skList, isNotNull);
expect(skList.toTypedArray().length, 4);
}
});
}
void _sharedColorTests() {
test('toSharedSkColor1', () {
expect(
toSharedSkColor1(const ui.Color(0xAABBCCDD)),
Float32List(4)
..[0] = 0xBB / 255.0
..[1] = 0xCC / 255.0
..[2] = 0xDD / 255.0
..[3] = 0xAA / 255.0,
);
});
test('toSharedSkColor2', () {
expect(
toSharedSkColor2(const ui.Color(0xAABBCCDD)),
Float32List(4)
..[0] = 0xBB / 255.0
..[1] = 0xCC / 255.0
..[2] = 0xDD / 255.0
..[3] = 0xAA / 255.0,
);
});
test('toSharedSkColor3', () {
expect(
toSharedSkColor3(const ui.Color(0xAABBCCDD)),
Float32List(4)
..[0] = 0xBB / 255.0
..[1] = 0xCC / 255.0
..[2] = 0xDD / 255.0
..[3] = 0xAA / 255.0,
);
});
}
void _toSkPointTests() {
test('toSkPoint', () {
expect(
toSkPoint(const ui.Offset(4, 5)),
Float32List(2)
..[0] = 4.0
..[1] = 5.0,
);
});
}
void _toSkColorStopsTests() {
test('toSkColorStops default', () {
expect(
toSkColorStops(null),
Float32List(2)
..[0] = 0
..[1] = 1,
);
});
test('toSkColorStops custom', () {
expect(
toSkColorStops(<double>[1, 2, 3, 4]),
Float32List(4)
..[0] = 1
..[1] = 2
..[2] = 3
..[3] = 4,
);
});
}
void _toSkMatrixFromFloat32Tests() {
test('toSkMatrixFromFloat32', () {
final Matrix4 matrix = Matrix4.identity()
..translate(1, 2, 3)
..rotateZ(4);
expect(
toSkMatrixFromFloat32(matrix.storage),
Float32List.fromList(<double>[
-0.6536436080932617,
0.756802499294281,
1,
-0.756802499294281,
-0.6536436080932617,
2,
-0.0,
0,
1,
])
);
});
}
SkPath _testClosedSkPath() {
return SkPath()
..moveTo(10, 10)
..lineTo(20, 10)
..lineTo(20, 20)
..lineTo(10, 20)
..close();
}
void _pathTests() {
SkPath path;
setUp(() {
path = SkPath();
});
test('setFillType', () {
path.setFillType(canvasKitJs.FillType.Winding);
});
test('addArc', () {
path.addArc(
SkRect(fLeft: 10, fTop: 20, fRight: 30, fBottom: 40),
1,
5,
);
});
test('addOval', () {
path.addOval(
SkRect(fLeft: 10, fTop: 20, fRight: 30, fBottom: 40),
false,
1,
);
});
test('addPath', () {
path.addPath(_testClosedSkPath(), 1, 0, 0, 0, 1, 0, 0, 0, 0, false);
});
test('addPoly', () {
final SkFloat32List encodedPoints = toMallocedSkPoints(const <ui.Offset>[
ui.Offset.zero,
ui.Offset(10, 10),
]);
path.addPoly(encodedPoints.toTypedArray(), true);
freeFloat32List(encodedPoints);
});
test('addRoundRect', () {
final ui.RRect rrect = ui.RRect.fromRectAndRadius(
ui.Rect.fromLTRB(10, 10, 20, 20),
ui.Radius.circular(3),
);
final SkFloat32List skRadii = mallocFloat32List(8);
final Float32List radii = skRadii.toTypedArray();
radii[0] = rrect.tlRadiusX;
radii[1] = rrect.tlRadiusY;
radii[2] = rrect.trRadiusX;
radii[3] = rrect.trRadiusY;
radii[4] = rrect.brRadiusX;
radii[5] = rrect.brRadiusY;
radii[6] = rrect.blRadiusX;
radii[7] = rrect.blRadiusY;
path.addRoundRect(
toOuterSkRect(rrect),
radii,
false,
);
freeFloat32List(skRadii);
});
test('addRect', () {
path.addRect(SkRect(fLeft: 1, fTop: 2, fRight: 3, fBottom: 4));
});
test('arcTo', () {
path.arcTo(
SkRect(fLeft: 1, fTop: 2, fRight: 3, fBottom: 4),
5,
40,
false,
);
});
test('overloaded arcTo (used for arcToPoint)', () {
final SkPathArcToPointOverload overload = debugJsObjectWrapper.castToSkPathArcToPointOverload(path);
overload.arcTo(
1,
2,
3,
false,
true,
4,
5,
);
});
test('close', () {
_testClosedSkPath();
});
test('conicTo', () {
path.conicTo(1, 2, 3, 4, 5);
});
test('contains', () {
final SkPath testPath = _testClosedSkPath();
expect(testPath.contains(15, 15), true);
expect(testPath.contains(100, 100), false);
});
test('cubicTo', () {
path.cubicTo(1, 2, 3, 4, 5, 6);
});
test('getBounds', () {
final SkPath testPath = _testClosedSkPath();
final ui.Rect bounds = testPath.getBounds().toRect();
expect(bounds, const ui.Rect.fromLTRB(10, 10, 20, 20));
});
test('lineTo', () {
path.lineTo(10, 10);
});
test('moveTo', () {
path.moveTo(10, 10);
});
test('quadTo', () {
path.quadTo(10, 10, 20, 20);
});
test('rArcTo', () {
path.rArcTo(
10,
20,
30,
false,
true,
40,
50,
);
});
test('rConicTo', () {
path.rConicTo(1, 2, 3, 4, 5);
});
test('rCubicTo', () {
path.rCubicTo(1, 2, 3, 4, 5, 6);
});
test('rLineTo', () {
path.rLineTo(10, 10);
});
test('rMoveTo', () {
path.rMoveTo(10, 10);
});
test('rQuadTo', () {
path.rQuadTo(10, 10, 20, 20);
});
test('reset', () {
final SkPath testPath = _testClosedSkPath();
expect(testPath.getBounds().toRect(), const ui.Rect.fromLTRB(10, 10, 20, 20));
testPath.reset();
expect(testPath.getBounds().toRect(), ui.Rect.zero);
});
test('toSVGString', () {
expect(_testClosedSkPath().toSVGString(), 'M10 10L20 10L20 20L10 20L10 10Z');
});
test('isEmpty', () {
expect(SkPath().isEmpty(), true);
expect(_testClosedSkPath().isEmpty(), false);
});
test('copy', () {
final SkPath original = _testClosedSkPath();
final SkPath copy = original.copy();
expect(original.getBounds().toRect(), copy.getBounds().toRect());
});
test('transform', () {
path = _testClosedSkPath();
path.transform(2, 0, 10, 0, 2, 10, 0, 0, 0);
final ui.Rect transformedBounds = path.getBounds().toRect();
expect(transformedBounds, ui.Rect.fromLTRB(30, 30, 50, 50));
});
test('SkContourMeasureIter/SkContourMeasure', () {
final SkContourMeasureIter iter = SkContourMeasureIter(_testClosedSkPath(), false, 0);
final SkContourMeasure measure1 = iter.next();
expect(measure1.length(), 40);
expect(measure1.getPosTan(5), Float32List.fromList(<double>[15, 10, 1, 0]));
expect(measure1.getPosTan(15), Float32List.fromList(<double>[20, 15, 0, 1]));
expect(measure1.isClosed(), true);
// Starting with a box path:
//
// 10 20
// 10 +-----------+
// | |
// | |
// | |
// | |
// | |
// 20 +-----------+
//
// Cut out the top-right quadrant:
//
// 10 15 20
// 10 +-----+=====+
// | â•‘+++++â•‘
// | â•‘+++++â•‘
// | +=====+ 15
// | |
// | |
// 20 +-----------+
final SkPath segment = measure1.getSegment(5, 15, true);
expect(segment.getBounds().toRect(), ui.Rect.fromLTRB(15, 10, 20, 15));
final SkContourMeasure measure2 = iter.next();
expect(measure2, isNull);
});
}
void _skSkRectTests() {
test('SkRect', () {
final SkRect rect = SkRect(fLeft: 1, fTop: 2, fRight: 3, fBottom: 4);
expect(rect.fLeft, 1);
expect(rect.fTop, 2);
expect(rect.fRight, 3);
expect(rect.fBottom, 4);
final ui.Rect uiRect = rect.toRect();
expect(uiRect.left, 1);
expect(uiRect.top, 2);
expect(uiRect.right, 3);
expect(uiRect.bottom, 4);
});
}
SkVertices _testVertices() {
return canvasKitJs.MakeSkVertices(
canvasKitJs.VertexMode.Triangles,
[
Float32List.fromList([0, 0]),
Float32List.fromList([10, 10]),
Float32List.fromList([0, 20]),
],
[
Float32List.fromList([0, 0]),
Float32List.fromList([10, 10]),
Float32List.fromList([0, 20]),
],
[
Float32List.fromList([255, 0, 0, 255]),
Float32List.fromList([0, 255, 0, 255]),
Float32List.fromList([0, 0, 255, 255]),
],
Uint16List.fromList([0, 1, 2]),
);
}
void _skVerticesTests() {
test('SkVertices', () {
expect(_testVertices(), isNotNull);
});
}
void _canvasTests() {
SkPictureRecorder recorder;
SkCanvas canvas;
setUp(() {
recorder = SkPictureRecorder();
canvas = recorder.beginRecording(SkRect(
fLeft: 0,
fTop: 0,
fRight: 100,
fBottom: 100,
));
});
tearDown(() {
expect(recorder.finishRecordingAsPicture(), isNotNull);
});
test('save/getSaveCount/restore/restoreToCount', () {
expect(canvas.save(), 1);
expect(canvas.save(), 2);
expect(canvas.save(), 3);
expect(canvas.save(), 4);
expect(canvas.getSaveCount(), 5);
canvas.restoreToCount(2);
expect(canvas.getSaveCount(), 2);
canvas.restore();
expect(canvas.getSaveCount(), 1);
});
test('saveLayer', () {
canvas.saveLayer(
SkRect(
fLeft: 0,
fTop: 0,
fRight: 100,
fBottom: 100,
),
SkPaint(),
);
});
test('SkCanvasSaveLayerWithoutBoundsOverride.saveLayer', () {
final SkCanvasSaveLayerWithoutBoundsOverride override = debugJsObjectWrapper.castToSkCanvasSaveLayerWithoutBoundsOverride(canvas);
override.saveLayer(SkPaint());
});
test('SkCanvasSaveLayerWithFilterOverride.saveLayer', () {
final SkCanvasSaveLayerWithFilterOverride override = debugJsObjectWrapper.castToSkCanvasSaveLayerWithFilterOverride(canvas);
override.saveLayer(
SkPaint(),
canvasKitJs.SkImageFilter.MakeBlur(1, 2, canvasKitJs.TileMode.Repeat, null),
0,
SkRect(
fLeft: 0,
fTop: 0,
fRight: 100,
fBottom: 100,
),
);
});
test('clear', () {
canvas.clear(Float32List.fromList([0, 0, 0, 0]));
});
test('clipPath', () {
canvas.clipPath(
_testClosedSkPath(),
canvasKitJs.ClipOp.Intersect,
true,
);
});
test('clipRRect', () {
canvas.clipRRect(
SkRRect(
rect: SkRect(
fLeft: 0,
fTop: 0,
fRight: 100,
fBottom: 100,
),
rx1: 1,
ry1: 2,
rx2: 3,
ry2: 4,
rx3: 5,
ry3: 6,
rx4: 7,
ry4: 8,
),
canvasKitJs.ClipOp.Intersect,
true,
);
});
test('clipRect', () {
canvas.clipRect(
SkRect(
fLeft: 0,
fTop: 0,
fRight: 100,
fBottom: 100,
),
canvasKitJs.ClipOp.Intersect,
true,
);
});
test('drawArc', () {
canvas.drawArc(
SkRect(
fLeft: 0,
fTop: 0,
fRight: 100,
fBottom: 50,
),
0,
100,
true,
SkPaint(),
);
});
test('drawAtlas', () {
final SkAnimatedImage image = canvasKitJs.MakeAnimatedImageFromEncoded(kTransparentImage);
canvas.drawAtlas(
image.getCurrentFrame(),
Float32List.fromList([0, 0, 1, 1]),
Float32List.fromList([1, 0, 2, 3]),
SkPaint(),
canvasKitJs.BlendMode.SrcOver,
[
Float32List.fromList([0, 0, 0, 1]),
Float32List.fromList([1, 1, 1, 1]),
],
);
});
test('drawCircle', () {
canvas.drawCircle(1, 2, 3, SkPaint());
});
test('drawColorInt', () {
canvas.drawColorInt(0xFFFFFFFF, canvasKitJs.BlendMode.SoftLight);
});
test('drawDRRect', () {
canvas.drawDRRect(
SkRRect(
rect: SkRect(
fLeft: 0,
fTop: 0,
fRight: 100,
fBottom: 100,
),
rx1: 1,
ry1: 2,
rx2: 3,
ry2: 4,
rx3: 5,
ry3: 6,
rx4: 7,
ry4: 8,
),
SkRRect(
rect: SkRect(
fLeft: 20,
fTop: 20,
fRight: 80,
fBottom: 80,
),
rx1: 1,
ry1: 2,
rx2: 3,
ry2: 4,
rx3: 5,
ry3: 6,
rx4: 7,
ry4: 8,
),
SkPaint(),
);
});
test('drawImage', () {
final SkAnimatedImage image = canvasKitJs.MakeAnimatedImageFromEncoded(kTransparentImage);
canvas.drawImage(
image.getCurrentFrame(),
10,
20,
SkPaint(),
);
});
test('drawImageRect', () {
final SkAnimatedImage image = canvasKitJs.MakeAnimatedImageFromEncoded(kTransparentImage);
canvas.drawImageRect(
image.getCurrentFrame(),
SkRect(fLeft: 0, fTop: 0, fRight: 1, fBottom: 1),
SkRect(fLeft: 0, fTop: 0, fRight: 1, fBottom: 1),
SkPaint(),
false,
);
});
test('drawImageNine', () {
final SkAnimatedImage image = canvasKitJs.MakeAnimatedImageFromEncoded(kTransparentImage);
canvas.drawImageNine(
image.getCurrentFrame(),
SkRect(fLeft: 0, fTop: 0, fRight: 1, fBottom: 1),
SkRect(fLeft: 0, fTop: 0, fRight: 1, fBottom: 1),
SkPaint(),
);
});
test('drawLine', () {
canvas.drawLine(0, 1, 2, 3, SkPaint());
});
test('drawOval', () {
canvas.drawOval(SkRect(fLeft: 0, fTop: 0, fRight: 1, fBottom: 1), SkPaint());
});
test('drawPaint', () {
canvas.drawPaint(SkPaint());
});
test('drawPath', () {
canvas.drawPath(
_testClosedSkPath(),
SkPaint(),
);
});
test('drawPoints', () {
canvas.drawPoints(
canvasKitJs.PointMode.Lines,
Float32List.fromList([0, 0, 10, 10, 0, 10]),
SkPaint(),
);
});
test('drawRRect', () {
canvas.drawRRect(
SkRRect(
rect: SkRect(
fLeft: 0,
fTop: 0,
fRight: 100,
fBottom: 100,
),
rx1: 1,
ry1: 2,
rx2: 3,
ry2: 4,
rx3: 5,
ry3: 6,
rx4: 7,
ry4: 8,
),
SkPaint(),
);
});
test('drawRect', () {
canvas.drawRect(
SkRect(
fLeft: 0,
fTop: 0,
fRight: 100,
fBottom: 100,
),
SkPaint(),
);
});
test('drawShadow', () {
for (int flags in const <int>[0x01, 0x00]) {
const double devicePixelRatio = 2.0;
const double elevation = 4.0;
const double ambientAlpha = 0.039;
const double spotAlpha = 0.25;
final SkPath path = _testClosedSkPath();
final ui.Rect bounds = path.getBounds().toRect();
final double shadowX = (bounds.left + bounds.right) / 2.0;
final double shadowY = bounds.top - 600.0;
const ui.Color color = ui.Color(0xAABBCCDD);
ui.Color inAmbient = color.withAlpha((color.alpha * ambientAlpha).round());
ui.Color inSpot = color.withAlpha((color.alpha * spotAlpha).round());
final SkTonalColors inTonalColors = SkTonalColors(
ambient: makeFreshSkColor(inAmbient),
spot: makeFreshSkColor(inSpot),
);
final SkTonalColors tonalColors =
canvasKitJs.computeTonalColors(inTonalColors);
canvas.drawShadow(
path,
Float32List(3)
..[2] = devicePixelRatio * elevation,
Float32List(3)
..[0] = shadowX
..[1] = shadowY
..[2] = devicePixelRatio * kLightHeight,
devicePixelRatio * kLightRadius,
tonalColors.ambient,
tonalColors.spot,
flags,
);
}
});
test('drawVertices', () {
canvas.drawVertices(
_testVertices(),
canvasKitJs.BlendMode.SrcOver,
SkPaint(),
);
});
test('rotate', () {
canvas.rotate(5, 10, 20);
});
test('scale', () {
canvas.scale(2, 3);
});
test('skew', () {
canvas.skew(4, 5);
});
test('concat', () {
canvas.concat(toSkMatrixFromFloat32(Matrix4.identity().storage));
});
test('translate', () {
canvas.translate(4, 5);
});
test('flush', () {
canvas.flush();
});
test('drawPicture', () {
final SkPictureRecorder otherRecorder = SkPictureRecorder();
final SkCanvas otherCanvas = otherRecorder.beginRecording(SkRect(
fLeft: 0,
fTop: 0,
fRight: 100,
fBottom: 100,
));
otherCanvas.drawLine(0, 0, 10, 10, SkPaint());
canvas.drawPicture(otherRecorder.finishRecordingAsPicture());
});
test('drawParagraph', () {
final CkParagraphBuilder builder = CkParagraphBuilder(
CkParagraphStyle(),
);
builder.addText('Hello');
final CkParagraph paragraph = builder.build();
paragraph.layout(const ui.ParagraphConstraints(width: 100));
canvas.drawParagraph(
debugJsObjectWrapper.unwrapSkParagraph(paragraph.legacySkiaObject),
10,
20,
);
});
}
final Uint8List kTransparentImage = Uint8List.fromList(<int>[
0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49,
0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x06,
0x00, 0x00, 0x00, 0x1F, 0x15, 0xC4, 0x89, 0x00, 0x00, 0x00, 0x0A, 0x49, 0x44,
0x41, 0x54, 0x78, 0x9C, 0x63, 0x00, 0x01, 0x00, 0x00, 0x05, 0x00, 0x01, 0x0D,
0x0A, 0x2D, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE,
]);
/// An animated GIF image with 3 1x1 pixel frames (a red, green, and blue
/// frames). The GIF animates forever, and each frame has a 100ms delay.
final Uint8List kAnimatedGif = Uint8List.fromList(<int> [
0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x01, 0x00, 0x01, 0x00, 0xa1, 0x03, 0x00,
0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0x21,
0xff, 0x0b, 0x4e, 0x45, 0x54, 0x53, 0x43, 0x41, 0x50, 0x45, 0x32, 0x2e, 0x30,
0x03, 0x01, 0x00, 0x00, 0x00, 0x21, 0xf9, 0x04, 0x00, 0x0a, 0x00, 0xff, 0x00,
0x2c, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x02, 0x02, 0x4c,
0x01, 0x00, 0x21, 0xf9, 0x04, 0x00, 0x0a, 0x00, 0xff, 0x00, 0x2c, 0x00, 0x00,
0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x02, 0x02, 0x54, 0x01, 0x00, 0x21,
0xf9, 0x04, 0x00, 0x0a, 0x00, 0xff, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x01,
0x00, 0x01, 0x00, 0x00, 0x02, 0x02, 0x44, 0x01, 0x00, 0x3b,
]);