[web] last batch of test null safety (flutter/engine#26719)

This commit is contained in:
Yegor 2021-06-11 17:14:02 -07:00 committed by GitHub
parent 09f69b628b
commit 347bd4f98d
21 changed files with 926 additions and 914 deletions

View File

@ -23,7 +23,7 @@ class EnginePictureRecorder implements ui.PictureRecorder {
bool get isRecording => _isRecording;
@override
ui.Picture endRecording() {
EnginePicture endRecording() {
if (!_isRecording) {
// The mobile version returns an empty picture in this case. To match the
// behavior we produce a blank picture too.

View File

@ -2,7 +2,6 @@
// 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:html' as html;
import 'dart:typed_data';
@ -47,7 +46,7 @@ void testMain() {
browserSupportsFinalizationRegistry = false;
Future<void> expectFrameData(ui.FrameInfo frame, List<int> data) async {
final ByteData frameData = await frame.image.toByteData();
final ByteData frameData = (await frame.image.toByteData())!;
expect(frameData.buffer.asUint8List(), Uint8List.fromList(data));
}
@ -73,7 +72,7 @@ void testMain() {
test('CkImage toString', () {
final SkImage skImage =
canvasKit.MakeAnimatedImageFromEncoded(kTransparentImage)
canvasKit.MakeAnimatedImageFromEncoded(kTransparentImage)!
.makeImageAtCurrentFrame();
final CkImage image = CkImage(skImage);
expect(image.toString(), '[1×1]');
@ -83,7 +82,7 @@ void testMain() {
test('CkImage can be explicitly disposed of', () {
final SkImage skImage =
canvasKit.MakeAnimatedImageFromEncoded(kTransparentImage)
canvasKit.MakeAnimatedImageFromEncoded(kTransparentImage)!
.makeImageAtCurrentFrame();
final CkImage image = CkImage(skImage);
expect(image.debugDisposed, isFalse);
@ -99,7 +98,7 @@ void testMain() {
test('CkImage can be explicitly disposed of when cloned', () async {
final SkImage skImage =
canvasKit.MakeAnimatedImageFromEncoded(kTransparentImage)
canvasKit.MakeAnimatedImageFromEncoded(kTransparentImage)!
.makeImageAtCurrentFrame();
final CkImage image = CkImage(skImage);
final SkiaObjectBox<CkImage, SkImage> box = image.box;
@ -133,7 +132,7 @@ void testMain() {
test('CkImage toByteData', () async {
final SkImage skImage =
canvasKit.MakeAnimatedImageFromEncoded(kTransparentImage)
canvasKit.MakeAnimatedImageFromEncoded(kTransparentImage)!
.makeImageAtCurrentFrame();
final CkImage image = CkImage(skImage);
expect((await image.toByteData()).lengthInBytes, greaterThan(0));
@ -145,7 +144,7 @@ void testMain() {
test('CkImage can be resurrected', () {
browserSupportsFinalizationRegistry = false;
final SkImage skImage =
canvasKit.MakeAnimatedImageFromEncoded(kTransparentImage)
canvasKit.MakeAnimatedImageFromEncoded(kTransparentImage)!
.makeImageAtCurrentFrame();
final CkImage image = CkImage(skImage);
expect(image.box.rawSkiaObject, isNotNull);
@ -259,13 +258,13 @@ void testMain() {
class TestHttpRequest implements html.HttpRequest {
@override
String responseType;
String responseType = 'invalid';
@override
int timeout = 10;
int? timeout = 10;
@override
bool withCredentials = false;
bool? withCredentials = false;
@override
void abort() {
@ -273,7 +272,7 @@ class TestHttpRequest implements html.HttpRequest {
}
@override
void addEventListener(String type, listener, [bool useCapture]) {
void addEventListener(String type, listener, [bool? useCapture]) {
throw UnimplementedError();
}
@ -320,7 +319,7 @@ class TestHttpRequest implements html.HttpRequest {
Stream<html.ProgressEvent> get onTimeout => throw UnimplementedError();
@override
void open(String method, String url, {bool async, String user, String password}) {}
void open(String method, String url, {bool? async, String? user, String? password}) {}
@override
void overrideMimeType(String mime) {
@ -331,7 +330,7 @@ class TestHttpRequest implements html.HttpRequest {
int get readyState => throw UnimplementedError();
@override
void removeEventListener(String type, listener, [bool useCapture]) {
void removeEventListener(String type, listener, [bool? useCapture]) {
throw UnimplementedError();
}

View File

@ -2,7 +2,6 @@
// 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:ui/ui.dart';
@ -23,21 +22,21 @@ void testMain() async {
});
test('Picture.toImage().toByteData()', () async {
final EnginePictureRecorder recorder = PictureRecorder();
final EnginePictureRecorder recorder = EnginePictureRecorder();
final RecordingCanvas canvas =
recorder.beginRecording(Rect.fromLTRB(0, 0, 2, 2));
canvas.drawColor(Color(0xFFCCDD00), BlendMode.srcOver);
final Picture testPicture = recorder.endRecording();
final Image testImage = await testPicture.toImage(2, 2);
final ByteData bytes =
await testImage.toByteData(format: ImageByteFormat.rawRgba);
(await testImage.toByteData(format: ImageByteFormat.rawRgba))!;
expect(
bytes.buffer.asUint32List(),
<int>[0xFF00DDCC, 0xFF00DDCC, 0xFF00DDCC, 0xFF00DDCC],
);
final ByteData pngBytes =
await testImage.toByteData(format: ImageByteFormat.png);
(await testImage.toByteData(format: ImageByteFormat.png))!;
// PNG-encoding is browser-specific, but the header is standard. We only
// test the header.

View File

@ -2,11 +2,9 @@
// 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:html' as html;
import 'dart:js_util' as js_util;
import 'package:meta/meta.dart';
import 'package:test/bootstrap/browser.dart';
import 'package:test/test.dart';
import 'package:ui/src/engine.dart' show domRenderer, window;
@ -47,7 +45,7 @@ void main() {
}
void testMain() {
html.Element glassPane = domRenderer.glassPaneElement;
html.Element glassPane = domRenderer.glassPaneElement!;
double dpi = 1.0;
setUp(() {
@ -65,7 +63,7 @@ void testMain() {
html.PointerEvent expectCorrectType(html.Event e) {
expect(e.runtimeType, equals(html.PointerEvent));
return e;
return e as html.PointerEvent;
}
List<html.PointerEvent> expectCorrectTypes(List<html.Event> events) {
@ -233,7 +231,7 @@ void testMain() {
html.TouchEvent expectCorrectType(html.Event e) {
expect(e.runtimeType, equals(html.TouchEvent));
return e;
return e as html.TouchEvent;
}
List<html.TouchEvent> expectCorrectTypes(List<html.Event> events) {
@ -246,10 +244,10 @@ void testMain() {
event = expectCorrectType(context.primaryDown(clientX: 100, clientY: 101));
expect(event.type, equals('touchstart'));
expect(event.changedTouches.length, equals(1));
expect(event.changedTouches[0].identifier, equals(1));
expect(event.changedTouches[0].client.x, equals(100));
expect(event.changedTouches[0].client.y, equals(101));
expect(event.changedTouches!.length, equals(1));
expect(event.changedTouches![0].identifier, equals(1));
expect(event.changedTouches![0].client.x, equals(100));
expect(event.changedTouches![0].client.y, equals(101));
events = expectCorrectTypes(context.multiTouchDown(<_TouchDetails>[
_TouchDetails(pointer: 100, clientX: 120, clientY: 121),
@ -257,20 +255,20 @@ void testMain() {
]));
expect(events.length, equals(1));
expect(events[0].type, equals('touchstart'));
expect(events[0].changedTouches.length, equals(2));
expect(events[0].changedTouches[0].identifier, equals(100));
expect(events[0].changedTouches[0].client.x, equals(120));
expect(events[0].changedTouches[0].client.y, equals(121));
expect(events[0].changedTouches[1].identifier, equals(101));
expect(events[0].changedTouches[1].client.x, equals(122));
expect(events[0].changedTouches[1].client.y, equals(123));
expect(events[0].changedTouches!.length, equals(2));
expect(events[0].changedTouches![0].identifier, equals(100));
expect(events[0].changedTouches![0].client.x, equals(120));
expect(events[0].changedTouches![0].client.y, equals(121));
expect(events[0].changedTouches![1].identifier, equals(101));
expect(events[0].changedTouches![1].client.x, equals(122));
expect(events[0].changedTouches![1].client.y, equals(123));
event = expectCorrectType(context.primaryMove(clientX: 200, clientY: 201));
expect(event.type, equals('touchmove'));
expect(event.changedTouches.length, equals(1));
expect(event.changedTouches[0].identifier, equals(1));
expect(event.changedTouches[0].client.x, equals(200));
expect(event.changedTouches[0].client.y, equals(201));
expect(event.changedTouches!.length, equals(1));
expect(event.changedTouches![0].identifier, equals(1));
expect(event.changedTouches![0].client.x, equals(200));
expect(event.changedTouches![0].client.y, equals(201));
events = expectCorrectTypes(context.multiTouchMove(<_TouchDetails>[
_TouchDetails(pointer: 102, clientX: 220, clientY: 221),
@ -278,20 +276,20 @@ void testMain() {
]));
expect(events.length, equals(1));
expect(events[0].type, equals('touchmove'));
expect(events[0].changedTouches.length, equals(2));
expect(events[0].changedTouches[0].identifier, equals(102));
expect(events[0].changedTouches[0].client.x, equals(220));
expect(events[0].changedTouches[0].client.y, equals(221));
expect(events[0].changedTouches[1].identifier, equals(103));
expect(events[0].changedTouches[1].client.x, equals(222));
expect(events[0].changedTouches[1].client.y, equals(223));
expect(events[0].changedTouches!.length, equals(2));
expect(events[0].changedTouches![0].identifier, equals(102));
expect(events[0].changedTouches![0].client.x, equals(220));
expect(events[0].changedTouches![0].client.y, equals(221));
expect(events[0].changedTouches![1].identifier, equals(103));
expect(events[0].changedTouches![1].client.x, equals(222));
expect(events[0].changedTouches![1].client.y, equals(223));
event = expectCorrectType(context.primaryUp(clientX: 300, clientY: 301));
expect(event.type, equals('touchend'));
expect(event.changedTouches.length, equals(1));
expect(event.changedTouches[0].identifier, equals(1));
expect(event.changedTouches[0].client.x, equals(300));
expect(event.changedTouches[0].client.y, equals(301));
expect(event.changedTouches!.length, equals(1));
expect(event.changedTouches![0].identifier, equals(1));
expect(event.changedTouches![0].client.x, equals(300));
expect(event.changedTouches![0].client.y, equals(301));
events = expectCorrectTypes(context.multiTouchUp(<_TouchDetails>[
_TouchDetails(pointer: 104, clientX: 320, clientY: 321),
@ -299,13 +297,13 @@ void testMain() {
]));
expect(events.length, equals(1));
expect(events[0].type, equals('touchend'));
expect(events[0].changedTouches.length, equals(2));
expect(events[0].changedTouches[0].identifier, equals(104));
expect(events[0].changedTouches[0].client.x, equals(320));
expect(events[0].changedTouches[0].client.y, equals(321));
expect(events[0].changedTouches[1].identifier, equals(105));
expect(events[0].changedTouches[1].client.x, equals(322));
expect(events[0].changedTouches[1].client.y, equals(323));
expect(events[0].changedTouches!.length, equals(2));
expect(events[0].changedTouches![0].identifier, equals(104));
expect(events[0].changedTouches![0].client.x, equals(320));
expect(events[0].changedTouches![0].client.y, equals(321));
expect(events[0].changedTouches![1].identifier, equals(105));
expect(events[0].changedTouches![1].client.x, equals(322));
expect(events[0].changedTouches![1].client.y, equals(323));
events = expectCorrectTypes(context.multiTouchCancel(<_TouchDetails>[
_TouchDetails(pointer: 104, clientX: 320, clientY: 321),
@ -313,13 +311,13 @@ void testMain() {
]));
expect(events.length, equals(1));
expect(events[0].type, equals('touchcancel'));
expect(events[0].changedTouches.length, equals(2));
expect(events[0].changedTouches[0].identifier, equals(104));
expect(events[0].changedTouches[0].client.x, equals(320));
expect(events[0].changedTouches[0].client.y, equals(321));
expect(events[0].changedTouches[1].identifier, equals(105));
expect(events[0].changedTouches[1].client.x, equals(322));
expect(events[0].changedTouches[1].client.y, equals(323));
expect(events[0].changedTouches!.length, equals(2));
expect(events[0].changedTouches![0].identifier, equals(104));
expect(events[0].changedTouches![0].client.x, equals(320));
expect(events[0].changedTouches![0].client.y, equals(321));
expect(events[0].changedTouches![1].identifier, equals(105));
expect(events[0].changedTouches![1].client.x, equals(322));
expect(events[0].changedTouches![1].client.y, equals(323));
});
test('_MouseEventContext generates expected events', () {
@ -329,7 +327,7 @@ void testMain() {
html.MouseEvent expectCorrectType(html.Event e) {
expect(e.runtimeType, equals(html.MouseEvent));
return e;
return e as html.MouseEvent;
}
final _MouseEventContext context = _MouseEventContext();
@ -414,8 +412,8 @@ void testMain() {
],
'can receive pointer events on the glass pane',
(_BasicEventContext context) {
PointerBinding.instance.debugOverrideDetector(context);
ui.PointerDataPacket receivedPacket;
PointerBinding.instance!.debugOverrideDetector(context);
ui.PointerDataPacket? receivedPacket;
ui.window.onPointerDataPacket = (ui.PointerDataPacket packet) {
receivedPacket = packet;
};
@ -423,7 +421,7 @@ void testMain() {
glassPane.dispatchEvent(context.primaryDown());
expect(receivedPacket, isNotNull);
expect(receivedPacket.data[0].buttons, equals(1));
expect(receivedPacket!.data[0].buttons, equals(1));
},
);
@ -435,7 +433,7 @@ void testMain() {
],
'does create an add event if got a pointerdown',
(_BasicEventContext context) {
PointerBinding.instance.debugOverrideDetector(context);
PointerBinding.instance!.debugOverrideDetector(context);
List<ui.PointerDataPacket> packets = <ui.PointerDataPacket>[];
ui.window.onPointerDataPacket = (ui.PointerDataPacket packet) {
packets.add(packet);
@ -458,7 +456,7 @@ void testMain() {
],
'correctly detects events on the semantics placeholder',
(_ButtonedEventMixin context) {
PointerBinding.instance.debugOverrideDetector(context);
PointerBinding.instance!.debugOverrideDetector(context);
List<ui.PointerDataPacket> packets = <ui.PointerDataPacket>[];
ui.window.onPointerDataPacket = (ui.PointerDataPacket packet) {
packets.add(packet);
@ -532,7 +530,7 @@ void testMain() {
],
'creates an add event if the first pointer activity is a hover',
(_ButtonedEventMixin context) {
PointerBinding.instance.debugOverrideDetector(context);
PointerBinding.instance!.debugOverrideDetector(context);
List<ui.PointerDataPacket> packets = <ui.PointerDataPacket>[];
ui.window.onPointerDataPacket = (ui.PointerDataPacket packet) {
packets.add(packet);
@ -556,7 +554,7 @@ void testMain() {
],
'sends a pointermove event instead of the second pointerdown in a row',
(_ButtonedEventMixin context) {
PointerBinding.instance.debugOverrideDetector(context);
PointerBinding.instance!.debugOverrideDetector(context);
List<ui.PointerDataPacket> packets = <ui.PointerDataPacket>[];
ui.window.onPointerDataPacket = (ui.PointerDataPacket packet) {
packets.add(packet);
@ -593,7 +591,7 @@ void testMain() {
],
'does synthesize add or hover or move for scroll',
(_ButtonedEventMixin context) {
PointerBinding.instance.debugOverrideDetector(context);
PointerBinding.instance!.debugOverrideDetector(context);
List<ui.PointerDataPacket> packets = <ui.PointerDataPacket>[];
ui.window.onPointerDataPacket = (ui.PointerDataPacket packet) {
packets.add(packet);
@ -712,7 +710,7 @@ void testMain() {
],
'does calculate delta and pointer identifier correctly',
(_ButtonedEventMixin context) {
PointerBinding.instance.debugOverrideDetector(context);
PointerBinding.instance!.debugOverrideDetector(context);
List<ui.PointerDataPacket> packets = <ui.PointerDataPacket>[];
ui.window.onPointerDataPacket = (ui.PointerDataPacket packet) {
packets.add(packet);
@ -840,7 +838,7 @@ void testMain() {
],
'correctly converts buttons of down, move and up events',
(_ButtonedEventMixin context) {
PointerBinding.instance.debugOverrideDetector(context);
PointerBinding.instance!.debugOverrideDetector(context);
List<ui.PointerDataPacket> packets = <ui.PointerDataPacket>[];
ui.window.onPointerDataPacket = (ui.PointerDataPacket packet) {
packets.add(packet);
@ -1010,7 +1008,7 @@ void testMain() {
],
'correctly handles button changes during a down sequence',
(_ButtonedEventMixin context) {
PointerBinding.instance.debugOverrideDetector(context);
PointerBinding.instance!.debugOverrideDetector(context);
List<ui.PointerDataPacket> packets = <ui.PointerDataPacket>[];
ui.window.onPointerDataPacket = (ui.PointerDataPacket packet) {
packets.add(packet);
@ -1075,7 +1073,7 @@ void testMain() {
],
'synthesizes a pointerup event when pointermove comes before the up',
(_ButtonedEventMixin context) {
PointerBinding.instance.debugOverrideDetector(context);
PointerBinding.instance!.debugOverrideDetector(context);
// This can happen when the user pops up the context menu by right
// clicking, then dismisses it with a left click.
@ -1158,7 +1156,7 @@ void testMain() {
],
'correctly handles uncontinuous button changes during a down sequence',
(_ButtonedEventMixin context) {
PointerBinding.instance.debugOverrideDetector(context);
PointerBinding.instance!.debugOverrideDetector(context);
// This can happen with the following gesture sequence:
//
// - Pops up the context menu by right clicking, but holds RMB;
@ -1230,7 +1228,7 @@ void testMain() {
],
'correctly handles missing right mouse button up when followed by move',
(_ButtonedEventMixin context) {
PointerBinding.instance.debugOverrideDetector(context);
PointerBinding.instance!.debugOverrideDetector(context);
// This can happen with the following gesture sequence:
//
// - Pops up the context menu by right clicking;
@ -1282,7 +1280,7 @@ void testMain() {
],
'handles RMB click when the browser sends it as a move',
(_ButtonedEventMixin context) {
PointerBinding.instance.debugOverrideDetector(context);
PointerBinding.instance!.debugOverrideDetector(context);
// When the user clicks the RMB and moves the mouse quickly (before the
// context menu shows up), the browser sends a move event before down.
// The move event will have "button:-1, buttons:2".
@ -1318,7 +1316,7 @@ void testMain() {
],
'correctly handles hover after RMB click',
(_ButtonedEventMixin context) {
PointerBinding.instance.debugOverrideDetector(context);
PointerBinding.instance!.debugOverrideDetector(context);
// This can happen with the following gesture sequence:
//
// - Pops up the context menu by right clicking, but holds RMB;
@ -1375,7 +1373,7 @@ void testMain() {
],
'correctly handles LMB click after RMB click',
(_ButtonedEventMixin context) {
PointerBinding.instance.debugOverrideDetector(context);
PointerBinding.instance!.debugOverrideDetector(context);
// This can happen with the following gesture sequence:
//
// - Pops up the context menu by right clicking, but holds RMB;
@ -1444,7 +1442,7 @@ void testMain() {
],
'correctly handles two consecutive RMB clicks with no up in between',
(_ButtonedEventMixin context) {
PointerBinding.instance.debugOverrideDetector(context);
PointerBinding.instance!.debugOverrideDetector(context);
// This can happen with the following gesture sequence:
//
// - Pops up the context menu by right clicking, but holds RMB;
@ -1517,7 +1515,7 @@ void testMain() {
],
'correctly handles two consecutive RMB clicks with up in between',
(_ButtonedEventMixin context) {
PointerBinding.instance.debugOverrideDetector(context);
PointerBinding.instance!.debugOverrideDetector(context);
// This can happen with the following gesture sequence:
//
// - Pops up the context menu by right clicking, but doesn't hold RMB;
@ -1600,7 +1598,7 @@ void testMain() {
],
'correctly handles two consecutive RMB clicks in two different locations',
(_ButtonedEventMixin context) {
PointerBinding.instance.debugOverrideDetector(context);
PointerBinding.instance!.debugOverrideDetector(context);
// This can happen with the following gesture sequence:
//
// - Pops up the context menu by right clicking;
@ -1670,7 +1668,7 @@ void testMain() {
],
'handles overlapping left/right down and up events',
(_ButtonedEventMixin context) {
PointerBinding.instance.debugOverrideDetector(context);
PointerBinding.instance!.debugOverrideDetector(context);
// This can happen with the following gesture sequence:
//
// LMB: down-------------------up
@ -1754,7 +1752,7 @@ void testMain() {
],
'correctly detects up event outside of glasspane',
(_ButtonedEventMixin context) {
PointerBinding.instance.debugOverrideDetector(context);
PointerBinding.instance!.debugOverrideDetector(context);
// This can happen when the up event occurs while the mouse is outside the
// browser window.
@ -1821,7 +1819,7 @@ void testMain() {
],
'treats each pointer separately',
(_MultiPointerEventMixin context) {
PointerBinding.instance.debugOverrideDetector(context);
PointerBinding.instance!.debugOverrideDetector(context);
List<ui.PointerDataPacket> packets = <ui.PointerDataPacket>[];
List<ui.PointerData> data;
ui.window.onPointerDataPacket = (ui.PointerDataPacket packet) {
@ -2012,7 +2010,7 @@ void testMain() {
],
'correctly parses cancel event',
(_MultiPointerEventMixin context) {
PointerBinding.instance.debugOverrideDetector(context);
PointerBinding.instance!.debugOverrideDetector(context);
List<ui.PointerDataPacket> packets = <ui.PointerDataPacket>[];
ui.window.onPointerDataPacket = (ui.PointerDataPacket packet) {
packets.add(packet);
@ -2058,7 +2056,7 @@ void testMain() {
],
'does not synthesize pointer up if from different device',
(_PointerEventContext context) {
PointerBinding.instance.debugOverrideDetector(context);
PointerBinding.instance!.debugOverrideDetector(context);
List<ui.PointerDataPacket> packets = <ui.PointerDataPacket>[];
ui.window.onPointerDataPacket = (ui.PointerDataPacket packet) {
packets.add(packet);
@ -2098,7 +2096,7 @@ void testMain() {
],
'handles random pointer id on up events',
(_PointerEventContext context) {
PointerBinding.instance.debugOverrideDetector(context);
PointerBinding.instance!.debugOverrideDetector(context);
// This happens with pens that are simulated with mouse events
// (e.g. Wacom). It sends events with the pointer type "mouse", and
// assigns a random pointer ID to each event.
@ -2155,7 +2153,7 @@ void testMain() {
'does calculate delta and pointer identifier correctly',
(_TouchEventContext context) {
// Mouse and Pointer are in another test since these tests can involve hovering
PointerBinding.instance.debugOverrideDetector(context);
PointerBinding.instance!.debugOverrideDetector(context);
List<ui.PointerDataPacket> packets = <ui.PointerDataPacket>[];
ui.window.onPointerDataPacket = (ui.PointerDataPacket packet) {
packets.add(packet);
@ -2271,19 +2269,19 @@ abstract class _BasicEventContext implements PointerSupportDetector {
mixin _ButtonedEventMixin on _BasicEventContext {
// Generate an event that is a mouse down with the specific buttons.
html.Event mouseDown(
{double clientX, double clientY, int button, int buttons});
{double? clientX, double? clientY, int? button, int? buttons});
// Generate an event that is a mouse drag with the specific buttons, or button
// changes during the drag.
//
// If there is no button change, assign `button` with _kNoButtonChange.
html.Event mouseMove(
{double clientX, double clientY, int button, int buttons});
{double? clientX, double? clientY, required int button, required int buttons});
// Generate an event that releases all mouse buttons.
html.Event mouseUp({double clientX, double clientY, int button, int buttons});
html.Event mouseUp({double? clientX, double? clientY, int? button, int? buttons});
html.Event hover({double clientX, double clientY}) {
html.Event hover({double? clientX, double? clientY}) {
return mouseMove(
buttons: 0,
button: _kNoButtonChange,
@ -2293,7 +2291,7 @@ mixin _ButtonedEventMixin on _BasicEventContext {
}
@override
html.Event primaryDown({double clientX, double clientY}) {
html.Event primaryDown({double? clientX, double? clientY}) {
return mouseDown(
buttons: 1,
button: 0,
@ -2303,7 +2301,7 @@ mixin _ButtonedEventMixin on _BasicEventContext {
}
@override
html.Event primaryMove({double clientX, double clientY}) {
html.Event primaryMove({double? clientX, double? clientY}) {
return mouseMove(
buttons: 1,
button: _kNoButtonChange,
@ -2313,7 +2311,7 @@ mixin _ButtonedEventMixin on _BasicEventContext {
}
@override
html.Event primaryUp({double clientX, double clientY}) {
html.Event primaryUp({double? clientX, double? clientY}) {
return mouseUp(
button: 0,
clientX: clientX,
@ -2322,11 +2320,11 @@ mixin _ButtonedEventMixin on _BasicEventContext {
}
html.Event wheel({
@required int buttons,
@required double clientX,
@required double clientY,
@required double deltaX,
@required double deltaY,
required int? buttons,
required double? clientX,
required double? clientY,
required double? deltaX,
required double? deltaY,
}) {
final Function jsWheelEvent = js_util.getProperty(html.window, 'WheelEvent');
final List<dynamic> eventArgs = <dynamic>[
@ -2346,9 +2344,9 @@ mixin _ButtonedEventMixin on _BasicEventContext {
class _TouchDetails {
const _TouchDetails({this.pointer, this.clientX, this.clientY});
final int pointer;
final double clientX;
final double clientY;
final int? pointer;
final double? clientX;
final double? clientY;
}
mixin _MultiPointerEventMixin on _BasicEventContext {
@ -2358,7 +2356,7 @@ mixin _MultiPointerEventMixin on _BasicEventContext {
List<html.Event> multiTouchCancel(List<_TouchDetails> touches);
@override
html.Event primaryDown({double clientX, double clientY}) {
html.Event primaryDown({double? clientX, double? clientY}) {
return multiTouchDown(<_TouchDetails>[
_TouchDetails(
pointer: 1,
@ -2369,7 +2367,7 @@ mixin _MultiPointerEventMixin on _BasicEventContext {
}
@override
html.Event primaryMove({double clientX, double clientY}) {
html.Event primaryMove({double? clientX, double? clientY}) {
return multiTouchMove(<_TouchDetails>[
_TouchDetails(
pointer: 1,
@ -2380,7 +2378,7 @@ mixin _MultiPointerEventMixin on _BasicEventContext {
}
@override
html.Event primaryUp({double clientX, double clientY}) {
html.Event primaryUp({double? clientX, double? clientY}) {
return multiTouchUp(<_TouchDetails>[
_TouchDetails(
pointer: 1,
@ -2396,9 +2394,8 @@ mixin _MultiPointerEventMixin on _BasicEventContext {
class _TouchEventContext extends _BasicEventContext
with _MultiPointerEventMixin
implements PointerSupportDetector {
_TouchEventContext() {
_TouchEventContext() :
_target = html.document.createElement('div');
}
@override
String get name => 'TouchAdapter';
@ -2418,9 +2415,9 @@ class _TouchEventContext extends _BasicEventContext
html.EventTarget _target;
html.Touch _createTouch({
int identifier,
double clientX,
double clientY,
int? identifier,
double? clientX,
double? clientY,
}) {
return html.Touch(<String, dynamic>{
'identifier': identifier,
@ -2492,8 +2489,12 @@ class _MouseEventContext extends _BasicEventContext
bool get hasMouseEvents => true;
@override
html.Event mouseDown(
{double clientX, double clientY, int button, int buttons}) {
html.Event mouseDown({
double? clientX,
double? clientY,
int? button,
int? buttons,
}) {
return _createMouseEvent(
'mousedown',
buttons: buttons,
@ -2504,8 +2505,12 @@ class _MouseEventContext extends _BasicEventContext
}
@override
html.Event mouseMove(
{double clientX, double clientY, int button, int buttons}) {
html.Event mouseMove({
double? clientX,
double? clientY,
required int button,
required int buttons,
}) {
final bool hasButtonChange = button != _kNoButtonChange;
final bool changeIsButtonDown =
hasButtonChange && (buttons & convertButtonToButtons(button)) != 0;
@ -2523,7 +2528,12 @@ class _MouseEventContext extends _BasicEventContext
}
@override
html.Event mouseUp({double clientX, double clientY, int button, int buttons}) {
html.Event mouseUp({
double? clientX,
double? clientY,
int? button,
int? buttons,
}) {
return _createMouseEvent(
'mouseup',
buttons: buttons,
@ -2535,10 +2545,10 @@ class _MouseEventContext extends _BasicEventContext
html.MouseEvent _createMouseEvent(
String type, {
int buttons,
int button,
double clientX,
double clientY,
int? buttons,
int? button,
double? clientX,
double? clientY,
}) {
final Function jsMouseEvent =
js_util.getProperty(html.window, 'MouseEvent');
@ -2592,8 +2602,13 @@ class _PointerEventContext extends _BasicEventContext
}
@override
html.Event mouseDown(
{double clientX, double clientY, int button, int buttons, int pointerId = 1}) {
html.Event mouseDown({
double? clientX,
double? clientY,
int? button,
int? buttons,
int? pointerId = 1,
}) {
return _downWithFullDetails(
pointer: pointerId,
buttons: buttons,
@ -2604,13 +2619,14 @@ class _PointerEventContext extends _BasicEventContext
);
}
html.Event _downWithFullDetails(
{double clientX,
double clientY,
int button,
int buttons,
int pointer,
String pointerType}) {
html.Event _downWithFullDetails({
double? clientX,
double? clientY,
int? button,
int? buttons,
int? pointer,
String? pointerType,
}) {
return html.PointerEvent('pointerdown', <String, dynamic>{
'pointerId': pointer,
'button': button,
@ -2636,8 +2652,13 @@ class _PointerEventContext extends _BasicEventContext
}
@override
html.Event mouseMove(
{double clientX, double clientY, int button, int buttons, int pointerId = 1}) {
html.Event mouseMove({
double? clientX,
double? clientY,
required int button,
required int buttons,
int pointerId = 1,
}) {
return _moveWithFullDetails(
pointer: pointerId,
buttons: buttons,
@ -2648,13 +2669,14 @@ class _PointerEventContext extends _BasicEventContext
);
}
html.Event _moveWithFullDetails(
{double clientX,
double clientY,
int button,
int buttons,
int pointer,
String pointerType}) {
html.Event _moveWithFullDetails({
double? clientX,
double? clientY,
int? button,
int? buttons,
int? pointer,
String? pointerType,
}) {
return html.PointerEvent('pointermove', <String, dynamic>{
'pointerId': pointer,
'button': button,
@ -2679,7 +2701,13 @@ class _PointerEventContext extends _BasicEventContext
}
@override
html.Event mouseUp({double clientX, double clientY, int button, int buttons, int pointerId = 1}) {
html.Event mouseUp({
double? clientX,
double? clientY,
int? button,
int? buttons,
int? pointerId = 1,
}) {
return _upWithFullDetails(
pointer: pointerId,
button: button,
@ -2690,13 +2718,14 @@ class _PointerEventContext extends _BasicEventContext
);
}
html.Event _upWithFullDetails(
{double clientX,
double clientY,
int button,
int buttons,
int pointer,
String pointerType}) {
html.Event _upWithFullDetails({
double? clientX,
double? clientY,
int? button,
int? buttons,
int? pointer,
String? pointerType,
}) {
return html.PointerEvent('pointerup', <String, dynamic>{
'pointerId': pointer,
'button': button,

View File

@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.6
import 'package:test/bootstrap/browser.dart';
import 'package:test/test.dart';
import 'package:ui/ui.dart';
@ -15,8 +14,8 @@ void main() {
}
void testMain() {
RecordingCanvas underTest;
MockEngineCanvas mockCanvas;
late RecordingCanvas underTest;
late MockEngineCanvas mockCanvas;
final Rect screenRect = Rect.largest;
setUp(() {
@ -113,62 +112,62 @@ void testMain() {
test('Filters out paint commands outside the clip rect', () {
// Outside to the left
underTest.drawRect(Rect.fromLTWH(0.0, 20.0, 10.0, 10.0), Paint());
underTest.drawRect(Rect.fromLTWH(0.0, 20.0, 10.0, 10.0), SurfacePaint());
// Outside above
underTest.drawRect(Rect.fromLTWH(20.0, 0.0, 10.0, 10.0), Paint());
underTest.drawRect(Rect.fromLTWH(20.0, 0.0, 10.0, 10.0), SurfacePaint());
// Visible
underTest.drawRect(Rect.fromLTWH(20.0, 20.0, 10.0, 10.0), Paint());
underTest.drawRect(Rect.fromLTWH(20.0, 20.0, 10.0, 10.0), SurfacePaint());
// Inside the layer clip rect but zero-size
underTest.drawRect(Rect.fromLTRB(20.0, 20.0, 30.0, 20.0), Paint());
underTest.drawRect(Rect.fromLTRB(20.0, 20.0, 30.0, 20.0), SurfacePaint());
// Inside the layer clip but clipped out by a canvas clip
underTest.save();
underTest.clipRect(Rect.fromLTWH(0, 0, 10, 10), ClipOp.intersect);
underTest.drawRect(Rect.fromLTWH(20.0, 20.0, 10.0, 10.0), Paint());
underTest.drawRect(Rect.fromLTWH(20.0, 20.0, 10.0, 10.0), SurfacePaint());
underTest.restore();
// Outside to the right
underTest.drawRect(Rect.fromLTWH(40.0, 20.0, 10.0, 10.0), Paint());
underTest.drawRect(Rect.fromLTWH(40.0, 20.0, 10.0, 10.0), SurfacePaint());
// Outside below
underTest.drawRect(Rect.fromLTWH(20.0, 40.0, 10.0, 10.0), Paint());
underTest.drawRect(Rect.fromLTWH(20.0, 40.0, 10.0, 10.0), SurfacePaint());
underTest.endRecording();
expect(underTest.debugPaintCommands, hasLength(10));
final PaintDrawRect outsideLeft = underTest.debugPaintCommands[0];
final PaintDrawRect outsideLeft = underTest.debugPaintCommands[0] as PaintDrawRect;
expect(outsideLeft.isClippedOut, isFalse);
expect(outsideLeft.leftBound, 0);
expect(outsideLeft.topBound, 20);
expect(outsideLeft.rightBound, 10);
expect(outsideLeft.bottomBound, 30);
final PaintDrawRect outsideAbove = underTest.debugPaintCommands[1];
final PaintDrawRect outsideAbove = underTest.debugPaintCommands[1] as PaintDrawRect;
expect(outsideAbove.isClippedOut, isFalse);
final PaintDrawRect visible = underTest.debugPaintCommands[2];
final PaintDrawRect visible = underTest.debugPaintCommands[2] as PaintDrawRect;
expect(visible.isClippedOut, isFalse);
final PaintDrawRect zeroSize = underTest.debugPaintCommands[3];
final PaintDrawRect zeroSize = underTest.debugPaintCommands[3] as PaintDrawRect;
expect(zeroSize.isClippedOut, isTrue);
expect(underTest.debugPaintCommands[4], isA<PaintSave>());
final PaintClipRect clip = underTest.debugPaintCommands[5];
final PaintClipRect clip = underTest.debugPaintCommands[5] as PaintClipRect;
expect(clip.isClippedOut, isFalse);
final PaintDrawRect clippedOut = underTest.debugPaintCommands[6];
final PaintDrawRect clippedOut = underTest.debugPaintCommands[6] as PaintDrawRect;
expect(clippedOut.isClippedOut, isTrue);
expect(underTest.debugPaintCommands[7], isA<PaintRestore>());
final PaintDrawRect outsideRight = underTest.debugPaintCommands[8];
final PaintDrawRect outsideRight = underTest.debugPaintCommands[8] as PaintDrawRect;
expect(outsideRight.isClippedOut, isFalse);
final PaintDrawRect outsideBelow = underTest.debugPaintCommands[9];
final PaintDrawRect outsideBelow = underTest.debugPaintCommands[9] as PaintDrawRect;
expect(outsideBelow.isClippedOut, isFalse);
// Give it the entire screen so everything paints.

View File

@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.6
@TestOn('chrome || firefox')
import 'dart:async';
@ -12,9 +11,7 @@ import 'dart:js_util' as js_util;
import 'package:test/bootstrap/browser.dart';
import 'package:test/test.dart';
import 'package:ui/src/engine.dart';
import 'package:ui/ui.dart' hide window;
import 'package:ui/ui.dart' as ui;
import '../../matchers.dart';
@ -23,33 +20,32 @@ void main() {
}
void testMain() {
setUpAll(() async {
await webOnlyInitializeEngine();
setUpAll(() {
ui.webOnlyInitializeEngine();
});
group('SceneBuilder', ()
{
group('SceneBuilder', () {
test('pushOffset implements surface lifecycle', () {
testLayerLifeCycle((SceneBuilder sceneBuilder, EngineLayer oldLayer) {
return sceneBuilder.pushOffset(10, 20, oldLayer: oldLayer);
testLayerLifeCycle((ui.SceneBuilder sceneBuilder, ui.EngineLayer? oldLayer) {
return sceneBuilder.pushOffset(10, 20, oldLayer: oldLayer as ui.OffsetEngineLayer?);
}, () {
return '''<s><flt-offset></flt-offset></s>''';
});
});
test('pushTransform implements surface lifecycle', () {
testLayerLifeCycle((SceneBuilder sceneBuilder, EngineLayer oldLayer) {
testLayerLifeCycle((ui.SceneBuilder sceneBuilder, ui.EngineLayer? oldLayer) {
return sceneBuilder.pushTransform(
(Matrix4.identity()..scale(html.window.devicePixelRatio)).toFloat64());
(Matrix4.identity()..scale(html.window.devicePixelRatio as double)).toFloat64());
}, () {
return '''<s><flt-transform></flt-transform></s>''';
});
});
test('pushClipRect implements surface lifecycle', () {
testLayerLifeCycle((SceneBuilder sceneBuilder, EngineLayer oldLayer) {
return sceneBuilder.pushClipRect(const Rect.fromLTRB(10, 20, 30, 40),
oldLayer: oldLayer);
testLayerLifeCycle((ui.SceneBuilder sceneBuilder, ui.EngineLayer? oldLayer) {
return sceneBuilder.pushClipRect(const ui.Rect.fromLTRB(10, 20, 30, 40),
oldLayer: oldLayer as ui.ClipRectEngineLayer?);
}, () {
return '''
<s>
@ -60,11 +56,11 @@ void testMain() {
});
test('pushClipRRect implements surface lifecycle', () {
testLayerLifeCycle((SceneBuilder sceneBuilder, EngineLayer oldLayer) {
testLayerLifeCycle((ui.SceneBuilder sceneBuilder, ui.EngineLayer? oldLayer) {
return sceneBuilder.pushClipRRect(
RRect.fromLTRBR(10, 20, 30, 40, const Radius.circular(3)),
oldLayer: oldLayer,
clipBehavior: Clip.none);
ui.RRect.fromLTRBR(10, 20, 30, 40, const ui.Radius.circular(3)),
oldLayer: oldLayer as ui.ClipRRectEngineLayer?,
clipBehavior: ui.Clip.none);
}, () {
return '''
<s>
@ -75,9 +71,9 @@ void testMain() {
});
test('pushClipPath implements surface lifecycle', () {
testLayerLifeCycle((SceneBuilder sceneBuilder, EngineLayer oldLayer) {
final Path path = Path()..addRect(const Rect.fromLTRB(10, 20, 30, 40));
return sceneBuilder.pushClipPath(path, oldLayer: oldLayer);
testLayerLifeCycle((ui.SceneBuilder sceneBuilder, ui.EngineLayer? oldLayer) {
final ui.Path path = ui.Path()..addRect(const ui.Rect.fromLTRB(10, 20, 30, 40));
return sceneBuilder.pushClipPath(path, oldLayer: oldLayer as ui.ClipPathEngineLayer?);
}, () {
return '''
<s>
@ -90,22 +86,22 @@ void testMain() {
});
test('pushOpacity implements surface lifecycle', () {
testLayerLifeCycle((SceneBuilder sceneBuilder, EngineLayer oldLayer) {
return sceneBuilder.pushOpacity(10, oldLayer: oldLayer);
testLayerLifeCycle((ui.SceneBuilder sceneBuilder, ui.EngineLayer? oldLayer) {
return sceneBuilder.pushOpacity(10, oldLayer: oldLayer as ui.OpacityEngineLayer?);
}, () {
return '''<s><o></o></s>''';
});
});
test('pushPhysicalShape implements surface lifecycle', () {
testLayerLifeCycle((SceneBuilder sceneBuilder, EngineLayer oldLayer) {
final Path path = Path()..addRect(const Rect.fromLTRB(10, 20, 30, 40));
testLayerLifeCycle((ui.SceneBuilder sceneBuilder, ui.EngineLayer? oldLayer) {
final ui.Path path = ui.Path()..addRect(const ui.Rect.fromLTRB(10, 20, 30, 40));
return sceneBuilder.pushPhysicalShape(
path: path,
elevation: 2,
color: const Color.fromRGBO(0, 0, 0, 1),
shadowColor: const Color.fromRGBO(0, 0, 0, 1),
oldLayer: oldLayer,
color: const ui.Color.fromRGBO(0, 0, 0, 1),
shadowColor: const ui.Color.fromRGBO(0, 0, 0, 1),
oldLayer: oldLayer as ui.PhysicalShapeEngineLayer?,
);
}, () {
return '''<s><pshape><clip-i></clip-i></pshape></s>''';
@ -113,10 +109,10 @@ void testMain() {
});
test('pushBackdropFilter implements surface lifecycle', () {
testLayerLifeCycle((SceneBuilder sceneBuilder, EngineLayer oldLayer) {
testLayerLifeCycle((ui.SceneBuilder sceneBuilder, ui.EngineLayer? oldLayer) {
return sceneBuilder.pushBackdropFilter(
ImageFilter.blur(sigmaX: 1.0, sigmaY: 1.0),
oldLayer: oldLayer,
ui.ImageFilter.blur(sigmaX: 1.0, sigmaY: 1.0),
oldLayer: oldLayer as ui.BackdropFilterEngineLayer?,
);
}, () {
return '<s><flt-backdrop>'
@ -133,9 +129,9 @@ void testMain() {
() {
final PersistedScene scene1 = PersistedScene(null);
final PersistedClipRect clip1 =
PersistedClipRect(null, const Rect.fromLTRB(10, 10, 20, 20),
Clip.antiAlias);
final PersistedOpacity opacity = PersistedOpacity(null, 100, Offset.zero);
PersistedClipRect(null, const ui.Rect.fromLTRB(10, 10, 20, 20),
ui.Clip.antiAlias);
final PersistedOpacity opacity = PersistedOpacity(null, 100, ui.Offset.zero);
final MockPersistedPicture picture = MockPersistedPicture();
scene1.appendChild(clip1);
@ -159,8 +155,8 @@ void testMain() {
// because the clip didn't change no repaints should happen.
final PersistedScene scene2 = PersistedScene(scene1);
final PersistedClipRect clip2 =
PersistedClipRect(clip1, const Rect.fromLTRB(10, 10, 20, 20),
Clip.antiAlias);
PersistedClipRect(clip1, const ui.Rect.fromLTRB(10, 10, 20, 20),
ui.Clip.antiAlias);
clip1.state = PersistedSurfaceState.pendingUpdate;
scene2.appendChild(clip2);
opacity.state = PersistedSurfaceState.pendingRetention;
@ -178,8 +174,8 @@ void testMain() {
// This should cause the picture to repaint despite being retained.
final PersistedScene scene3 = PersistedScene(scene2);
final PersistedClipRect clip3 =
PersistedClipRect(clip2, const Rect.fromLTRB(10, 10, 50, 50),
Clip.antiAlias);
PersistedClipRect(clip2, const ui.Rect.fromLTRB(10, 10, 50, 50),
ui.Clip.antiAlias);
clip2.state = PersistedSurfaceState.pendingUpdate;
scene3.appendChild(clip3);
opacity.state = PersistedSurfaceState.pendingRetention;
@ -203,54 +199,54 @@ void testMain() {
// canvas needs to have a -1 zIndex so it can preserve compositing order.
test('Canvas element should retain -1 zIndex after update', () async {
final SurfaceSceneBuilder builder = SurfaceSceneBuilder();
final Picture picture1 = _drawPicture();
EngineLayer oldLayer = builder.pushClipRect(
const Rect.fromLTRB(10, 10, 300, 300),
final ui.Picture picture1 = _drawPicture();
final ui.ClipRectEngineLayer oldLayer = builder.pushClipRect(
const ui.Rect.fromLTRB(10, 10, 300, 300),
);
builder.addPicture(Offset.zero, picture1);
builder.addPicture(ui.Offset.zero, picture1);
builder.pop();
html.HtmlElement content = builder.build().webOnlyRootElement;
expect(content.querySelector('canvas').style.zIndex, '-1');
html.Element content = builder.build().webOnlyRootElement!;
expect(content.querySelector('canvas')!.style.zIndex, '-1');
// Force update to scene which will utilize reuse code path.
final SurfaceSceneBuilder builder2 = SurfaceSceneBuilder();
builder2.pushClipRect(
const Rect.fromLTRB(5, 10, 300, 300),
const ui.Rect.fromLTRB(5, 10, 300, 300),
oldLayer: oldLayer
);
final Picture picture2 = _drawPicture();
builder2.addPicture(Offset.zero, picture2);
final ui.Picture picture2 = _drawPicture();
builder2.addPicture(ui.Offset.zero, picture2);
builder2.pop();
html.HtmlElement contentAfterReuse = builder2.build().webOnlyRootElement;
expect(contentAfterReuse.querySelector('canvas').style.zIndex, '-1');
html.Element contentAfterReuse = builder2.build().webOnlyRootElement!;
expect(contentAfterReuse.querySelector('canvas')!.style.zIndex, '-1');
});
test('Multiple canvas elements should retain zIndex after update', () async {
final SurfaceSceneBuilder builder = SurfaceSceneBuilder();
final Picture picture1 = _drawPathImagePath();
EngineLayer oldLayer = builder.pushClipRect(
const Rect.fromLTRB(10, 10, 300, 300),
final ui.Picture picture1 = _drawPathImagePath();
ui.ClipRectEngineLayer oldLayer = builder.pushClipRect(
const ui.Rect.fromLTRB(10, 10, 300, 300),
);
builder.addPicture(Offset.zero, picture1);
builder.addPicture(ui.Offset.zero, picture1);
builder.pop();
html.HtmlElement content = builder.build().webOnlyRootElement;
html.document.body.append(content);
expect(content.querySelector('canvas').style.zIndex, '-1');
html.Element content = builder.build().webOnlyRootElement!;
html.document.body!.append(content);
expect(content.querySelector('canvas')!.style.zIndex, '-1');
// Force update to scene which will utilize reuse code path.
final SurfaceSceneBuilder builder2 = SurfaceSceneBuilder();
builder2.pushClipRect(
const Rect.fromLTRB(5, 10, 300, 300),
const ui.Rect.fromLTRB(5, 10, 300, 300),
oldLayer: oldLayer
);
final Picture picture2 = _drawPathImagePath();
builder2.addPicture(Offset.zero, picture2);
final ui.Picture picture2 = _drawPathImagePath();
builder2.addPicture(ui.Offset.zero, picture2);
builder2.pop();
html.HtmlElement contentAfterReuse = builder2.build().webOnlyRootElement;
html.Element contentAfterReuse = builder2.build().webOnlyRootElement!;
List<html.CanvasElement> list =
contentAfterReuse.querySelectorAll('canvas');
expect(list[0].style.zIndex, '-1');
@ -262,15 +258,15 @@ void testMain() {
/// image elements.
test('Should retain same image element', () async {
final SurfaceSceneBuilder builder = SurfaceSceneBuilder();
final Picture picture1 = _drawPathImagePath();
EngineLayer oldLayer = builder.pushClipRect(
const Rect.fromLTRB(10, 10, 300, 300),
final ui.Picture picture1 = _drawPathImagePath();
ui.ClipRectEngineLayer oldLayer = builder.pushClipRect(
const ui.Rect.fromLTRB(10, 10, 300, 300),
);
builder.addPicture(Offset.zero, picture1);
builder.addPicture(ui.Offset.zero, picture1);
builder.pop();
html.HtmlElement content = builder.build().webOnlyRootElement;
html.document.body.append(content);
html.Element content = builder.build().webOnlyRootElement!;
html.document.body!.append(content);
List<html.ImageElement> list = content.querySelectorAll('img');
for (html.ImageElement image in list) {
image.alt = 'marked';
@ -279,14 +275,14 @@ void testMain() {
// Force update to scene which will utilize reuse code path.
final SurfaceSceneBuilder builder2 = SurfaceSceneBuilder();
builder2.pushClipRect(
const Rect.fromLTRB(5, 10, 300, 300),
const ui.Rect.fromLTRB(5, 10, 300, 300),
oldLayer: oldLayer
);
final Picture picture2 = _drawPathImagePath();
builder2.addPicture(Offset.zero, picture2);
final ui.Picture picture2 = _drawPathImagePath();
builder2.addPicture(ui.Offset.zero, picture2);
builder2.pop();
html.HtmlElement contentAfterReuse = builder2.build().webOnlyRootElement;
html.Element contentAfterReuse = builder2.build().webOnlyRootElement!;
list = contentAfterReuse.querySelectorAll('img');
for (html.ImageElement image in list) {
expect(image.alt, 'marked');
@ -294,24 +290,24 @@ void testMain() {
expect(list.length, 1);
});
PersistedPicture findPictureSurfaceChild(PersistedContainerSurface parent) {
PersistedPicture pictureSurface;
PersistedPicture? findPictureSurfaceChild(PersistedContainerSurface parent) {
PersistedPicture? pictureSurface;
parent.visitChildren((PersistedSurface child) {
pictureSurface = child;
pictureSurface = child as PersistedPicture;
});
return pictureSurface;
}
test('skips painting picture when picture fully clipped out', () async {
final Picture picture = _drawPicture();
final ui.Picture picture = _drawPicture();
// Picture not clipped out, so we should see a `<flt-canvas>`
{
final SurfaceSceneBuilder builder = SurfaceSceneBuilder();
builder.pushOffset(0, 0);
builder.addPicture(Offset.zero, picture);
builder.addPicture(ui.Offset.zero, picture);
builder.pop();
html.HtmlElement content = builder.build().webOnlyRootElement;
html.Element content = builder.build().webOnlyRootElement!;
expect(content.querySelectorAll('flt-picture').single.children, isNotEmpty);
}
@ -319,69 +315,69 @@ void testMain() {
{
final SurfaceSceneBuilder builder = SurfaceSceneBuilder();
builder.pushOffset(0, 0);
final PersistedContainerSurface clip = builder.pushClipRect(const Rect.fromLTRB(1000, 1000, 2000, 2000)) as PersistedContainerSurface;
builder.addPicture(Offset.zero, picture);
final PersistedContainerSurface clip = builder.pushClipRect(const ui.Rect.fromLTRB(1000, 1000, 2000, 2000)) as PersistedContainerSurface;
builder.addPicture(ui.Offset.zero, picture);
builder.pop();
builder.pop();
html.HtmlElement content = builder.build().webOnlyRootElement;
html.Element content = builder.build().webOnlyRootElement!;
expect(content.querySelectorAll('flt-picture').single.children, isEmpty);
expect(findPictureSurfaceChild(clip).debugCanvas, isNull);
expect(findPictureSurfaceChild(clip)!.debugCanvas, isNull);
}
});
test('does not skip painting picture when picture is '
'inside transform with offset', () async {
final Picture picture = _drawPicture();
final ui.Picture picture = _drawPicture();
// Picture should not be clipped out since transform will offset it to 500,500
final SurfaceSceneBuilder builder = SurfaceSceneBuilder();
builder.pushOffset(0, 0);
builder.pushClipRect(const Rect.fromLTRB(0, 0, 1000, 1000)) as PersistedContainerSurface;
builder.pushClipRect(const ui.Rect.fromLTRB(0, 0, 1000, 1000)) as PersistedContainerSurface;
builder.pushTransform((Matrix4.identity()..scale(0.5, 0.5)).toFloat64());
builder.addPicture(Offset(1000, 1000), picture);
builder.addPicture(ui.Offset(1000, 1000), picture);
builder.pop();
builder.pop();
builder.pop();
html.HtmlElement content = builder.build().webOnlyRootElement;
html.Element content = builder.build().webOnlyRootElement!;
expect(content.querySelectorAll('flt-picture').single.children, isNotEmpty);
});
test('does not skip painting picture when picture is '
'inside transform', () async {
final Picture picture = _drawPicture();
final ui.Picture picture = _drawPicture();
// Picture should not be clipped out since transform will offset it to 500,500
final SurfaceSceneBuilder builder = SurfaceSceneBuilder();
builder.pushOffset(0, 0);
builder.pushClipRect(const Rect.fromLTRB(0, 0, 1000, 1000)) as PersistedContainerSurface;
builder.pushClipRect(const ui.Rect.fromLTRB(0, 0, 1000, 1000)) as PersistedContainerSurface;
builder.pushTransform((Matrix4.identity()..scale(0.5, 0.5)).toFloat64());
builder.pushOffset(1000, 1000);
builder.addPicture(Offset.zero, picture);
builder.addPicture(ui.Offset.zero, picture);
builder.pop();
builder.pop();
builder.pop();
html.HtmlElement content = builder.build().webOnlyRootElement;
html.Element content = builder.build().webOnlyRootElement!;
expect(content.querySelectorAll('flt-picture').single.children, isNotEmpty);
});
test(
'skips painting picture when picture fully clipped out with'
' transform and offset', () async {
final Picture picture = _drawPicture();
final ui.Picture picture = _drawPicture();
// Picture should be clipped out since transform will offset it to 500,500
final SurfaceSceneBuilder builder = SurfaceSceneBuilder();
builder.pushOffset(50, 50);
builder.pushClipRect(
const Rect.fromLTRB(0, 0, 1000, 1000)) as PersistedContainerSurface;
const ui.Rect.fromLTRB(0, 0, 1000, 1000)) as PersistedContainerSurface;
builder.pushTransform((Matrix4.identity()
..scale(2, 2)).toFloat64());
builder.pushOffset(500, 500);
builder.addPicture(Offset.zero, picture);
builder.addPicture(ui.Offset.zero, picture);
builder.pop();
builder.pop();
builder.pop();
builder.pop();
html.HtmlElement content = builder
html.Element content = builder
.build()
.webOnlyRootElement;
.webOnlyRootElement!;
expect(content
.querySelectorAll('flt-picture')
.single
@ -389,40 +385,40 @@ void testMain() {
});
test('releases old canvas when picture is fully clipped out after addRetained', () async {
final Picture picture = _drawPicture();
final ui.Picture picture = _drawPicture();
// Frame 1: picture visible
final SurfaceSceneBuilder builder1 = SurfaceSceneBuilder();
final PersistedOffset offset1 = builder1.pushOffset(0, 0) as PersistedOffset;
builder1.addPicture(Offset.zero, picture);
builder1.addPicture(ui.Offset.zero, picture);
builder1.pop();
html.HtmlElement content1 = builder1.build().webOnlyRootElement;
html.Element content1 = builder1.build().webOnlyRootElement!;
expect(content1.querySelectorAll('flt-picture').single.children, isNotEmpty);
expect(findPictureSurfaceChild(offset1).debugCanvas, isNotNull);
expect(findPictureSurfaceChild(offset1)!.debugCanvas, isNotNull);
// Frame 2: picture is clipped out after an update
final SurfaceSceneBuilder builder2 = SurfaceSceneBuilder();
final PersistedOffset offset2 = builder2.pushOffset(-10000, -10000, oldLayer: offset1);
builder2.addPicture(Offset.zero, picture);
final PersistedOffset offset2 = builder2.pushOffset(-10000, -10000, oldLayer: offset1) as PersistedOffset;
builder2.addPicture(ui.Offset.zero, picture);
builder2.pop();
html.HtmlElement content = builder2.build().webOnlyRootElement;
html.Element content = builder2.build().webOnlyRootElement!;
expect(content.querySelectorAll('flt-picture').single.children, isEmpty);
expect(findPictureSurfaceChild(offset2).debugCanvas, isNull);
expect(findPictureSurfaceChild(offset2)!.debugCanvas, isNull);
});
test('releases old canvas when picture is fully clipped out after addRetained', () async {
final Picture picture = _drawPicture();
final ui.Picture picture = _drawPicture();
// Frame 1: picture visible
final SurfaceSceneBuilder builder1 = SurfaceSceneBuilder();
final PersistedOffset offset1 = builder1.pushOffset(0, 0) as PersistedOffset;
final PersistedOffset subOffset1 = builder1.pushOffset(0, 0) as PersistedOffset;
builder1.addPicture(Offset.zero, picture);
builder1.addPicture(ui.Offset.zero, picture);
builder1.pop();
builder1.pop();
html.HtmlElement content1 = builder1.build().webOnlyRootElement;
html.Element content1 = builder1.build().webOnlyRootElement!;
expect(content1.querySelectorAll('flt-picture').single.children, isNotEmpty);
expect(findPictureSurfaceChild(subOffset1).debugCanvas, isNotNull);
expect(findPictureSurfaceChild(subOffset1)!.debugCanvas, isNotNull);
// Frame 2: picture is clipped out after addRetained
final SurfaceSceneBuilder builder2 = SurfaceSceneBuilder();
@ -433,20 +429,20 @@ void testMain() {
// the clipped area. We should see the canvas being released.
builder2.addRetained(subOffset1);
builder2.pop();
html.HtmlElement content = builder2.build().webOnlyRootElement;
html.Element content = builder2.build().webOnlyRootElement!;
expect(content.querySelectorAll('flt-picture').single.children, isEmpty);
expect(findPictureSurfaceChild(subOffset1).debugCanvas, isNull);
expect(findPictureSurfaceChild(subOffset1)!.debugCanvas, isNull);
});
test('auto-pops pushed layers', () async {
final Picture picture = _drawPicture();
final ui.Picture picture = _drawPicture();
final SurfaceSceneBuilder builder = SurfaceSceneBuilder();
builder.pushOffset(0, 0);
builder.pushOffset(0, 0);
builder.pushOffset(0, 0);
builder.pushOffset(0, 0);
builder.pushOffset(0, 0);
builder.addPicture(Offset.zero, picture);
builder.addPicture(ui.Offset.zero, picture);
// Intentionally pop fewer layers than we pushed
builder.pop();
@ -454,7 +450,7 @@ void testMain() {
builder.pop();
// Expect as many layers as we pushed (not popped).
html.HtmlElement content = builder.build().webOnlyRootElement;
html.Element content = builder.build().webOnlyRootElement!;
expect(content.querySelectorAll('flt-offset'), hasLength(5));
});
@ -465,27 +461,27 @@ void testMain() {
// an offset layer. Test cases use this to control how layers are reused.
// Layers of the same type can be reused even if they are not explicitly
// updated. Conversely, layers of different types are never reused.
EngineLayer pushChild(SurfaceSceneBuilder builder, String char, {EngineLayer oldLayer}) {
ui.EngineLayer pushChild(SurfaceSceneBuilder builder, String char, {ui.EngineLayer? oldLayer}) {
// Numbers use opacity layers, letters use offset layers. This is used to
// control DOM reuse. Layers of the same type can reuse DOM nodes from other
// dropped layers.
final bool useOffset = int.tryParse(char) == null;
final EnginePictureRecorder recorder = PictureRecorder();
final RecordingCanvas canvas = recorder.beginRecording(const Rect.fromLTRB(0, 0, 400, 400));
final DomParagraph paragraph = (DomParagraphBuilder(ParagraphStyle())..addText(char)).build();
paragraph.layout(ParagraphConstraints(width: 1000));
canvas.drawParagraph(paragraph, Offset.zero);
final EngineLayer newLayer = useOffset
? builder.pushOffset(0, 0, oldLayer: oldLayer)
: builder.pushOpacity(100, oldLayer: oldLayer);
builder.addPicture(Offset.zero, recorder.endRecording());
final EnginePictureRecorder recorder = EnginePictureRecorder();
final RecordingCanvas canvas = recorder.beginRecording(const ui.Rect.fromLTRB(0, 0, 400, 400));
final DomParagraph paragraph = (DomParagraphBuilder(EngineParagraphStyle())..addText(char)).build() as DomParagraph;
paragraph.layout(ui.ParagraphConstraints(width: 1000));
canvas.drawParagraph(paragraph, ui.Offset.zero);
final ui.EngineLayer newLayer = useOffset
? builder.pushOffset(0, 0, oldLayer: oldLayer as ui.OffsetEngineLayer)
: builder.pushOpacity(100, oldLayer: oldLayer as ui.OpacityEngineLayer);
builder.addPicture(ui.Offset.zero, recorder.endRecording());
builder.pop();
return newLayer;
}
// Maps letters to layers used to render them in the last frame, used to
// supply `oldLayer` to guarantee update.
final Map<String, EngineLayer> renderedLayers = <String, EngineLayer>{};
final Map<String, ui.EngineLayer> renderedLayers = <String, ui.EngineLayer>{};
// Pump an empty scene to reset it, otherwise the first frame will attempt
// to diff left-overs from a previous test, which results in unpredictable
@ -502,11 +498,11 @@ void testMain() {
// list of the `<flt-scene>` element.
final html.MutationObserver observer = html.MutationObserver((List mutations, _) {
for (html.MutationRecord record in mutations.cast<html.MutationRecord>()) {
actualDeletions.addAll(record.removedNodes);
actualAdditions.addAll(record.addedNodes);
actualDeletions.addAll(record.removedNodes!);
actualAdditions.addAll(record.addedNodes!);
}
});
observer.observe(SurfaceSceneBuilder.debugLastFrameScene.rootElement, childList: true);
observer.observe(SurfaceSceneBuilder.debugLastFrameScene!.rootElement!, childList: true);
final SurfaceSceneBuilder builder = SurfaceSceneBuilder();
for (int i = 0; i < string.length; i++) {
@ -514,10 +510,10 @@ void testMain() {
renderedLayers[char] = pushChild(builder, char, oldLayer: renderedLayers[char]);
}
final SurfaceScene scene = builder.build();
final List<html.HtmlElement> pTags = scene.webOnlyRootElement.querySelectorAll('p');
final List<html.Element> pTags = scene.webOnlyRootElement!.querySelectorAll('p');
expect(pTags, hasLength(string.length));
expect(
scene.webOnlyRootElement.querySelectorAll('p').map((p) => p.innerText).join(''),
scene.webOnlyRootElement!.querySelectorAll('p').map((p) => p.innerText).join(''),
string,
);
renderedLayers.removeWhere((key, value) => !string.contains(key));
@ -586,105 +582,105 @@ void testMain() {
test('Canvas should allocate fewer pixels when zoomed out', () async {
final SurfaceSceneBuilder builder = SurfaceSceneBuilder();
final Picture picture1 = _drawPicture();
builder.pushClipRect(const Rect.fromLTRB(10, 10, 300, 300));
builder.addPicture(Offset.zero, picture1);
final ui.Picture picture1 = _drawPicture();
builder.pushClipRect(const ui.Rect.fromLTRB(10, 10, 300, 300));
builder.addPicture(ui.Offset.zero, picture1);
builder.pop();
html.HtmlElement content = builder.build().webOnlyRootElement;
html.CanvasElement canvas = content.querySelector('canvas');
final int unscaledWidth = canvas.width;
final int unscaledHeight = canvas.height;
html.Element content = builder.build().webOnlyRootElement!;
html.CanvasElement canvas = content.querySelector('canvas') as html.CanvasElement;
final int unscaledWidth = canvas.width!;
final int unscaledHeight = canvas.height!;
// Force update to scene which will utilize reuse code path.
final SurfaceSceneBuilder builder2 = SurfaceSceneBuilder();
builder2.pushOffset(0, 0);
builder2.pushTransform(Matrix4.identity().scaled(0.5, 0.5).toFloat64());
builder2.pushClipRect(
const Rect.fromLTRB(10, 10, 300, 300),
const ui.Rect.fromLTRB(10, 10, 300, 300),
);
builder2.addPicture(Offset.zero, picture1);
builder2.addPicture(ui.Offset.zero, picture1);
builder2.pop();
builder2.pop();
builder2.pop();
html.HtmlElement contentAfterScale = builder2.build().webOnlyRootElement;
html.CanvasElement canvas2 = contentAfterScale.querySelector('canvas');
html.Element contentAfterScale = builder2.build().webOnlyRootElement!;
html.CanvasElement canvas2 = contentAfterScale.querySelector('canvas') as html.CanvasElement;
// Although we are drawing same picture, due to scaling the new canvas
// should have fewer pixels.
expect(canvas2.width < unscaledWidth, isTrue);
expect(canvas2.height < unscaledHeight, isTrue);
expect(canvas2.width! < unscaledWidth, isTrue);
expect(canvas2.height! < unscaledHeight, isTrue);
});
test('Canvas should allocate more pixels when zoomed in', () async {
final SurfaceSceneBuilder builder = SurfaceSceneBuilder();
final Picture picture1 = _drawPicture();
builder.pushClipRect(const Rect.fromLTRB(10, 10, 300, 300));
builder.addPicture(Offset.zero, picture1);
final ui.Picture picture1 = _drawPicture();
builder.pushClipRect(const ui.Rect.fromLTRB(10, 10, 300, 300));
builder.addPicture(ui.Offset.zero, picture1);
builder.pop();
html.HtmlElement content = builder.build().webOnlyRootElement;
html.CanvasElement canvas = content.querySelector('canvas');
final int unscaledWidth = canvas.width;
final int unscaledHeight = canvas.height;
html.Element content = builder.build().webOnlyRootElement!;
html.CanvasElement canvas = content.querySelector('canvas') as html.CanvasElement;
final int unscaledWidth = canvas.width!;
final int unscaledHeight = canvas.height!;
// Force update to scene which will utilize reuse code path.
final SurfaceSceneBuilder builder2 = SurfaceSceneBuilder();
builder2.pushOffset(0, 0);
builder2.pushTransform(Matrix4.identity().scaled(2, 2).toFloat64());
builder2.pushClipRect(
const Rect.fromLTRB(10, 10, 300, 300),
const ui.Rect.fromLTRB(10, 10, 300, 300),
);
builder2.addPicture(Offset.zero, picture1);
builder2.addPicture(ui.Offset.zero, picture1);
builder2.pop();
builder2.pop();
builder2.pop();
html.HtmlElement contentAfterScale = builder2.build().webOnlyRootElement;
html.CanvasElement canvas2 = contentAfterScale.querySelector('canvas');
html.Element contentAfterScale = builder2.build().webOnlyRootElement!;
html.CanvasElement canvas2 = contentAfterScale.querySelector('canvas') as html.CanvasElement;
// Although we are drawing same picture, due to scaling the new canvas
// should have more pixels.
expect(canvas2.width > unscaledWidth, isTrue);
expect(canvas2.height > unscaledHeight, isTrue);
expect(canvas2.width! > unscaledWidth, isTrue);
expect(canvas2.height! > unscaledHeight, isTrue);
});
test('Should recycle canvas once', () async {
final SurfaceSceneBuilder builder = SurfaceSceneBuilder();
final Picture picture1 = _drawPicture();
EngineLayer oldLayer = builder.pushClipRect(
const Rect.fromLTRB(10, 10, 300, 300),
final ui.Picture picture1 = _drawPicture();
ui.ClipRectEngineLayer oldLayer = builder.pushClipRect(
const ui.Rect.fromLTRB(10, 10, 300, 300),
);
builder.addPicture(Offset.zero, picture1);
builder.addPicture(ui.Offset.zero, picture1);
builder.pop();
builder.build();
// Force update to scene which will utilize reuse code path.
final SurfaceSceneBuilder builder2 = SurfaceSceneBuilder();
EngineLayer oldLayer2 = builder2.pushClipRect(
const Rect.fromLTRB(5, 10, 300, 300),
ui.ClipRectEngineLayer oldLayer2 = builder2.pushClipRect(
const ui.Rect.fromLTRB(5, 10, 300, 300),
oldLayer: oldLayer
);
builder2.addPicture(Offset.zero, _drawEmptyPicture());
builder2.addPicture(ui.Offset.zero, _drawEmptyPicture());
builder2.pop();
html.HtmlElement contentAfterReuse = builder2.build().webOnlyRootElement;
html.Element contentAfterReuse = builder2.build().webOnlyRootElement!;
expect(contentAfterReuse, isNotNull);
final SurfaceSceneBuilder builder3 = SurfaceSceneBuilder();
builder3.pushClipRect(
const Rect.fromLTRB(25, 10, 300, 300),
const ui.Rect.fromLTRB(25, 10, 300, 300),
oldLayer: oldLayer2
);
builder3.addPicture(Offset.zero, _drawEmptyPicture());
builder3.addPicture(ui.Offset.zero, _drawEmptyPicture());
builder3.pop();
// This build will crash if canvas gets recycled twice.
html.HtmlElement contentAfterReuse2 = builder3.build().webOnlyRootElement;
html.Element contentAfterReuse2 = builder3.build().webOnlyRootElement!;
expect(contentAfterReuse2, isNotNull);
});
}
typedef TestLayerBuilder = EngineLayer Function(
SceneBuilder sceneBuilder, EngineLayer oldLayer);
typedef TestLayerBuilder = ui.EngineLayer Function(
ui.SceneBuilder sceneBuilder, ui.EngineLayer? oldLayer);
typedef ExpectedHtmlGetter = String Function();
void testLayerLifeCycle(
@ -694,8 +690,8 @@ void testLayerLifeCycle(
SurfaceSceneBuilder.debugForgetFrameScene();
// Build: builds a brand new layer.
SceneBuilder sceneBuilder = SceneBuilder();
final EngineLayer layer1 = layerBuilder(sceneBuilder, null);
SurfaceSceneBuilder sceneBuilder = SurfaceSceneBuilder();
final ui.EngineLayer layer1 = layerBuilder(sceneBuilder, null);
final Type surfaceType = layer1.runtimeType;
sceneBuilder.pop();
@ -709,24 +705,24 @@ void testLayerLifeCycle(
}
final PersistedSurface surface1 = findSurface();
final html.Element surfaceElement1 = surface1.rootElement;
final html.Element surfaceElement1 = surface1.rootElement!;
// Retain: reuses a layer as is along with its DOM elements.
sceneBuilder = SceneBuilder();
sceneBuilder = SurfaceSceneBuilder();
sceneBuilder.addRetained(layer1);
tester = SceneTester(sceneBuilder.build());
tester.expectSceneHtml(expectedHtmlGetter());
final PersistedSurface surface2 = findSurface();
final html.Element surfaceElement2 = surface2.rootElement;
final html.Element surfaceElement2 = surface2.rootElement!;
expect(surface2, same(surface1));
expect(surfaceElement2, same(surfaceElement1));
// Reuse: reuses a layer's DOM elements by matching it.
sceneBuilder = SceneBuilder();
final EngineLayer layer3 = layerBuilder(sceneBuilder, layer1);
sceneBuilder = SurfaceSceneBuilder();
final ui.EngineLayer layer3 = layerBuilder(sceneBuilder, layer1);
sceneBuilder.pop();
expect(layer3, isNot(same(layer1)));
tester = SceneTester(sceneBuilder.build());
@ -734,13 +730,13 @@ void testLayerLifeCycle(
final PersistedSurface surface3 = findSurface();
expect(surface3, same(layer3));
final html.Element surfaceElement3 = surface3.rootElement;
final html.Element surfaceElement3 = surface3.rootElement!;
expect(surface3, isNot(same(surface2)));
expect(surfaceElement3, isNotNull);
expect(surfaceElement3, same(surfaceElement2));
// Recycle: discards all the layers.
sceneBuilder = SceneBuilder();
sceneBuilder = SurfaceSceneBuilder();
tester = SceneTester(sceneBuilder.build());
tester.expectSceneHtml('<s></s>');
@ -749,7 +745,7 @@ void testLayerLifeCycle(
// Retain again: the framework should be able to request that a layer is added
// as retained even after it has been recycled. In this case the
// engine would "rehydrate" the layer with new DOM elements.
sceneBuilder = SceneBuilder();
sceneBuilder = SurfaceSceneBuilder();
sceneBuilder.addRetained(layer3);
tester = SceneTester(sceneBuilder.build());
tester.expectSceneHtml(expectedHtmlGetter());
@ -761,21 +757,21 @@ void testLayerLifeCycle(
class MockPersistedPicture extends PersistedPicture {
factory MockPersistedPicture() {
final EnginePictureRecorder recorder = PictureRecorder();
final EnginePictureRecorder recorder = EnginePictureRecorder();
// Use the largest cull rect so that layer clips are effective. The tests
// rely on this.
recorder.beginRecording(Rect.largest)..drawPaint(Paint());
recorder.beginRecording(ui.Rect.largest)..drawPaint(SurfacePaint());
return MockPersistedPicture._(recorder.endRecording());
}
MockPersistedPicture._(Picture picture) : super(0, 0, picture, 0);
MockPersistedPicture._(EnginePicture picture) : super(0, 0, picture, 0);
int retainCount = 0;
int buildCount = 0;
int updateCount = 0;
int applyPaintCount = 0;
final BitmapCanvas _fakeCanvas = BitmapCanvas(const Rect.fromLTRB(0, 0, 10, 10), RenderStrategy());
final BitmapCanvas _fakeCanvas = BitmapCanvas(const ui.Rect.fromLTRB(0, 0, 10, 10), RenderStrategy());
@override
EngineCanvas get debugCanvas {
@ -788,7 +784,7 @@ class MockPersistedPicture extends PersistedPicture {
}
@override
Matrix4 get localTransformInverse => null;
Matrix4 get localTransformInverse => Matrix4.identity();
@override
void build() {
@ -803,7 +799,7 @@ class MockPersistedPicture extends PersistedPicture {
}
@override
void applyPaint(EngineCanvas oldCanvas) {
void applyPaint(EngineCanvas? oldCanvas) {
applyPaintCount++;
}
@ -818,89 +814,89 @@ class MockPersistedPicture extends PersistedPicture {
}
/// Draw 4 circles within 50, 50, 120, 120 bounds
Picture _drawPicture() {
ui.Picture _drawPicture() {
const double offsetX = 50;
const double offsetY = 50;
final EnginePictureRecorder recorder = PictureRecorder();
final EnginePictureRecorder recorder = EnginePictureRecorder();
final RecordingCanvas canvas =
recorder.beginRecording(const Rect.fromLTRB(0, 0, 400, 400));
Shader gradient = Gradient.radial(
Offset(100, 100), 50, [
const Color.fromARGB(255, 0, 0, 0),
const Color.fromARGB(255, 0, 0, 255)
recorder.beginRecording(const ui.Rect.fromLTRB(0, 0, 400, 400));
ui.Shader gradient = ui.Gradient.radial(
ui.Offset(100, 100), 50, [
const ui.Color.fromARGB(255, 0, 0, 0),
const ui.Color.fromARGB(255, 0, 0, 255)
]);
canvas.drawCircle(
Offset(offsetX + 10, offsetY + 10), 10,
Paint()
..style = PaintingStyle.fill
ui.Offset(offsetX + 10, offsetY + 10), 10,
SurfacePaint()
..style = ui.PaintingStyle.fill
..shader = gradient);
canvas.drawCircle(
Offset(offsetX + 60, offsetY + 10),
ui.Offset(offsetX + 60, offsetY + 10),
10,
Paint()
..style = PaintingStyle.fill
..color = const Color.fromRGBO(255, 0, 0, 1));
SurfacePaint()
..style = ui.PaintingStyle.fill
..color = const ui.Color.fromRGBO(255, 0, 0, 1));
canvas.drawCircle(
Offset(offsetX + 10, offsetY + 60),
ui.Offset(offsetX + 10, offsetY + 60),
10,
Paint()
..style = PaintingStyle.fill
..color = const Color.fromRGBO(0, 255, 0, 1));
SurfacePaint()
..style = ui.PaintingStyle.fill
..color = const ui.Color.fromRGBO(0, 255, 0, 1));
canvas.drawCircle(
Offset(offsetX + 60, offsetY + 60),
ui.Offset(offsetX + 60, offsetY + 60),
10,
Paint()
..style = PaintingStyle.fill
..color = const Color.fromRGBO(0, 0, 255, 1));
SurfacePaint()
..style = ui.PaintingStyle.fill
..color = const ui.Color.fromRGBO(0, 0, 255, 1));
return recorder.endRecording();
}
Picture _drawEmptyPicture() {
final EnginePictureRecorder recorder = PictureRecorder();
recorder.beginRecording(const Rect.fromLTRB(0, 0, 400, 400));
EnginePicture _drawEmptyPicture() {
final EnginePictureRecorder recorder = EnginePictureRecorder();
recorder.beginRecording(const ui.Rect.fromLTRB(0, 0, 400, 400));
return recorder.endRecording();
}
Picture _drawPathImagePath() {
EnginePicture _drawPathImagePath() {
const double offsetX = 50;
const double offsetY = 50;
final EnginePictureRecorder recorder = PictureRecorder();
final EnginePictureRecorder recorder = EnginePictureRecorder();
final RecordingCanvas canvas =
recorder.beginRecording(const Rect.fromLTRB(0, 0, 400, 400));
Shader gradient = Gradient.radial(
Offset(100, 100), 50, [
const Color.fromARGB(255, 0, 0, 0),
const Color.fromARGB(255, 0, 0, 255)
recorder.beginRecording(const ui.Rect.fromLTRB(0, 0, 400, 400));
ui.Shader gradient = ui.Gradient.radial(
ui.Offset(100, 100), 50, [
const ui.Color.fromARGB(255, 0, 0, 0),
const ui.Color.fromARGB(255, 0, 0, 255)
]);
canvas.drawCircle(
Offset(offsetX + 10, offsetY + 10), 10,
Paint()
..style = PaintingStyle.fill
ui.Offset(offsetX + 10, offsetY + 10), 10,
SurfacePaint()
..style = ui.PaintingStyle.fill
..shader = gradient);
canvas.drawCircle(
Offset(offsetX + 60, offsetY + 10),
ui.Offset(offsetX + 60, offsetY + 10),
10,
Paint()
..style = PaintingStyle.fill
..color = const Color.fromRGBO(255, 0, 0, 1));
SurfacePaint()
..style = ui.PaintingStyle.fill
..color = const ui.Color.fromRGBO(255, 0, 0, 1));
canvas.drawCircle(
Offset(offsetX + 10, offsetY + 60),
ui.Offset(offsetX + 10, offsetY + 60),
10,
Paint()
..style = PaintingStyle.fill
..color = const Color.fromRGBO(0, 255, 0, 1));
canvas.drawImage(createTestImage(), Offset(0, 0), Paint());
SurfacePaint()
..style = ui.PaintingStyle.fill
..color = const ui.Color.fromRGBO(0, 255, 0, 1));
canvas.drawImage(createTestImage(), ui.Offset(0, 0), SurfacePaint());
canvas.drawCircle(
Offset(offsetX + 10, offsetY + 10), 10,
Paint()
..style = PaintingStyle.fill
ui.Offset(offsetX + 10, offsetY + 10), 10,
SurfacePaint()
..style = ui.PaintingStyle.fill
..shader = gradient);
canvas.drawCircle(
Offset(offsetX + 60, offsetY + 60),
ui.Offset(offsetX + 60, offsetY + 60),
10,
Paint()
..style = PaintingStyle.fill
..color = const Color.fromRGBO(0, 0, 255, 1));
SurfacePaint()
..style = ui.PaintingStyle.fill
..color = const ui.Color.fromRGBO(0, 0, 255, 1));
return recorder.endRecording();
}

View File

@ -2,7 +2,6 @@
// 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:html' as html;
import 'package:ui/src/engine.dart';
@ -23,7 +22,7 @@ void testMain() {
test('debugAssertSurfaceState produces a human-readable message', () {
final SceneBuilder builder = SceneBuilder();
final PersistedOpacity opacityLayer = builder.pushOpacity(100);
final PersistedOpacity opacityLayer = builder.pushOpacity(100) as PersistedOpacity;
try {
debugAssertSurfaceState(opacityLayer, PersistedSurfaceState.active, PersistedSurfaceState.pendingRetention);
fail('Expected $PersistedSurfaceException');
@ -39,7 +38,7 @@ void testMain() {
test('is created', () {
final SceneBuilder builder = SceneBuilder();
final PersistedOpacity opacityLayer = builder.pushOpacity(100);
final PersistedOpacity opacityLayer = builder.pushOpacity(100) as PersistedOpacity;
builder.pop();
expect(opacityLayer, isNotNull);
@ -48,13 +47,13 @@ void testMain() {
builder.build();
expect(opacityLayer.rootElement.tagName.toLowerCase(), 'flt-opacity');
expect(opacityLayer.rootElement!.tagName.toLowerCase(), 'flt-opacity');
expect(opacityLayer.isActive, isTrue);
});
test('is released', () {
final SceneBuilder builder1 = SceneBuilder();
final PersistedOpacity opacityLayer = builder1.pushOpacity(100);
final PersistedOpacity opacityLayer = builder1.pushOpacity(100) as PersistedOpacity;
builder1.pop();
builder1.build();
expect(opacityLayer.isActive, isTrue);
@ -66,9 +65,9 @@ void testMain() {
test('discarding is recursive', () {
final SceneBuilder builder1 = SceneBuilder();
final PersistedOpacity opacityLayer = builder1.pushOpacity(100);
final PersistedOpacity opacityLayer = builder1.pushOpacity(100) as PersistedOpacity;
final PersistedTransform transformLayer =
builder1.pushTransform(Matrix4.identity().toFloat64());
builder1.pushTransform(Matrix4.identity().toFloat64()) as PersistedTransform;
builder1.pop();
builder1.pop();
builder1.build();
@ -84,15 +83,15 @@ void testMain() {
test('is updated', () {
final SceneBuilder builder1 = SceneBuilder();
final PersistedOpacity opacityLayer1 = builder1.pushOpacity(100);
final PersistedOpacity opacityLayer1 = builder1.pushOpacity(100) as PersistedOpacity;
builder1.pop();
builder1.build();
expect(opacityLayer1.isActive, isTrue);
final html.Element element = opacityLayer1.rootElement;
final html.Element element = opacityLayer1.rootElement!;
final SceneBuilder builder2 = SceneBuilder();
final PersistedOpacity opacityLayer2 =
builder2.pushOpacity(200, oldLayer: opacityLayer1);
builder2.pushOpacity(200, oldLayer: opacityLayer1) as PersistedOpacity;
expect(opacityLayer1.isPendingUpdate, isTrue);
expect(opacityLayer2.isCreated, isTrue);
expect(opacityLayer2.oldLayer, same(opacityLayer1));
@ -110,11 +109,11 @@ void testMain() {
test('ignores released surface when updated', () {
// Build a surface
final SceneBuilder builder1 = SceneBuilder();
final PersistedOpacity opacityLayer1 = builder1.pushOpacity(100);
final PersistedOpacity opacityLayer1 = builder1.pushOpacity(100) as PersistedOpacity;
builder1.pop();
builder1.build();
expect(opacityLayer1.isActive, isTrue);
final html.Element element = opacityLayer1.rootElement;
final html.Element element = opacityLayer1.rootElement!;
// Release it
SceneBuilder().build();
@ -124,7 +123,7 @@ void testMain() {
// Attempt to update it
final SceneBuilder builder2 = SceneBuilder();
final PersistedOpacity opacityLayer2 =
builder2.pushOpacity(200, oldLayer: opacityLayer1);
builder2.pushOpacity(200, oldLayer: opacityLayer1) as PersistedOpacity;
builder2.pop();
expect(opacityLayer1.isReleased, isTrue);
expect(opacityLayer2.isCreated, isTrue);
@ -160,10 +159,10 @@ void testMain() {
final SurfaceSceneBuilder builder1 = SurfaceSceneBuilder();
final PersistedTransform a1 =
builder1.pushTransform(
(Matrix4.identity()..scale(html.window.devicePixelRatio)).toFloat64());
final PersistedOpacity b1 = builder1.pushOpacity(100);
(Matrix4.identity()..scale(html.window.devicePixelRatio as double)).toFloat64()) as PersistedTransform;
final PersistedOpacity b1 = builder1.pushOpacity(100) as PersistedOpacity;
final PersistedTransform c1 =
builder1.pushTransform(Matrix4.identity().toFloat64());
builder1.pushTransform(Matrix4.identity().toFloat64()) as PersistedTransform;
builder1.debugAddSurface(logger);
builder1.pop();
builder1.pop();
@ -171,9 +170,9 @@ void testMain() {
builder1.build();
expect(logger.log, <String>['build', 'createElement', 'apply']);
final html.Element elementA = a1.rootElement;
final html.Element elementB = b1.rootElement;
final html.Element elementC = c1.rootElement;
final html.Element elementA = a1.rootElement!;
final html.Element elementB = b1.rootElement!;
final html.Element elementC = c1.rootElement!;
expect(elementC.parent, elementB);
expect(elementB.parent, elementA);
@ -181,10 +180,10 @@ void testMain() {
final SurfaceSceneBuilder builder2 = SurfaceSceneBuilder();
final PersistedTransform a2 =
builder2.pushTransform(
(Matrix4.identity()..scale(html.window.devicePixelRatio)).toFloat64(),
oldLayer: a1);
(Matrix4.identity()..scale(html.window.devicePixelRatio as double)).toFloat64(),
oldLayer: a1) as PersistedTransform;
final PersistedTransform c2 =
builder2.pushTransform(Matrix4.identity().toFloat64(), oldLayer: c1);
builder2.pushTransform(Matrix4.identity().toFloat64(), oldLayer: c1) as PersistedTransform;
builder2.addRetained(logger);
builder2.pop();
builder2.pop();
@ -210,11 +209,11 @@ void testMain() {
test('is retained', () {
final SceneBuilder builder1 = SceneBuilder();
final PersistedOpacity opacityLayer = builder1.pushOpacity(100);
final PersistedOpacity opacityLayer = builder1.pushOpacity(100) as PersistedOpacity;
builder1.pop();
builder1.build();
expect(opacityLayer.isActive, isTrue);
final html.Element element = opacityLayer.rootElement;
final html.Element element = opacityLayer.rootElement!;
final SceneBuilder builder2 = SceneBuilder();
@ -229,14 +228,14 @@ void testMain() {
test('revives released surface when retained', () {
final SurfaceSceneBuilder builder1 = SurfaceSceneBuilder();
final PersistedOpacity opacityLayer = builder1.pushOpacity(100);
final PersistedOpacity opacityLayer = builder1.pushOpacity(100) as PersistedOpacity;
final _LoggingTestSurface logger = _LoggingTestSurface();
builder1.debugAddSurface(logger);
builder1.pop();
builder1.build();
expect(opacityLayer.isActive, isTrue);
expect(logger.log, <String>['build', 'createElement', 'apply']);
final html.Element element = opacityLayer.rootElement;
final html.Element element = opacityLayer.rootElement!;
SceneBuilder().build();
expect(opacityLayer.isReleased, isTrue);
@ -255,16 +254,16 @@ void testMain() {
test('reviving is recursive', () {
final SceneBuilder builder1 = SceneBuilder();
final PersistedOpacity opacityLayer = builder1.pushOpacity(100);
final PersistedOpacity opacityLayer = builder1.pushOpacity(100) as PersistedOpacity;
final PersistedTransform transformLayer =
builder1.pushTransform(Matrix4.identity().toFloat64());
builder1.pushTransform(Matrix4.identity().toFloat64()) as PersistedTransform;
builder1.pop();
builder1.pop();
builder1.build();
expect(opacityLayer.isActive, isTrue);
expect(transformLayer.isActive, isTrue);
final html.Element opacityElement = opacityLayer.rootElement;
final html.Element transformElement = transformLayer.rootElement;
final html.Element opacityElement = opacityLayer.rootElement!;
final html.Element transformElement = transformLayer.rootElement!;
SceneBuilder().build();
@ -299,28 +298,28 @@ void testMain() {
// D
test('reparents DOM elements when retained', () {
final SceneBuilder builder1 = SceneBuilder();
final PersistedOpacity a1 = builder1.pushOpacity(10);
final PersistedOpacity b1 = builder1.pushOpacity(20);
final PersistedOpacity a1 = builder1.pushOpacity(10) as PersistedOpacity;
final PersistedOpacity b1 = builder1.pushOpacity(20) as PersistedOpacity;
builder1.pop();
final PersistedOpacity c1 = builder1.pushOpacity(30);
final PersistedOpacity d1 = builder1.pushOpacity(40);
final PersistedOpacity c1 = builder1.pushOpacity(30) as PersistedOpacity;
final PersistedOpacity d1 = builder1.pushOpacity(40) as PersistedOpacity;
builder1.pop();
builder1.pop();
builder1.pop();
builder1.build();
final html.Element elementA = a1.rootElement;
final html.Element elementB = b1.rootElement;
final html.Element elementC = c1.rootElement;
final html.Element elementD = d1.rootElement;
final html.Element elementA = a1.rootElement!;
final html.Element elementB = b1.rootElement!;
final html.Element elementC = c1.rootElement!;
final html.Element elementD = d1.rootElement!;
expect(elementB.parent, elementA);
expect(elementC.parent, elementA);
expect(elementD.parent, elementC);
final SceneBuilder builder2 = SceneBuilder();
final PersistedOpacity a2 = builder2.pushOpacity(10, oldLayer: a1);
final PersistedOpacity b2 = builder2.pushOpacity(20, oldLayer: b1);
final PersistedOpacity a2 = builder2.pushOpacity(10, oldLayer: a1) as PersistedOpacity;
final PersistedOpacity b2 = builder2.pushOpacity(20, oldLayer: b1) as PersistedOpacity;
builder2.addRetained(c1);
builder2.pop();
builder2.pop();
@ -333,9 +332,9 @@ void testMain() {
expect(
<html.Element>[
elementD.parent,
elementC.parent,
elementB.parent,
elementD.parent!,
elementC.parent!,
elementB.parent!,
],
<html.Element>[elementC, elementB, elementA],
);
@ -343,14 +342,14 @@ void testMain() {
test('is updated by matching', () {
final SceneBuilder builder1 = SceneBuilder();
final PersistedOpacity opacityLayer1 = builder1.pushOpacity(100);
final PersistedOpacity opacityLayer1 = builder1.pushOpacity(100) as PersistedOpacity;
builder1.pop();
builder1.build();
expect(opacityLayer1.isActive, isTrue);
final html.Element element = opacityLayer1.rootElement;
final html.Element element = opacityLayer1.rootElement!;
final SceneBuilder builder2 = SceneBuilder();
final PersistedOpacity opacityLayer2 = builder2.pushOpacity(200);
final PersistedOpacity opacityLayer2 = builder2.pushOpacity(200) as PersistedOpacity;
expect(opacityLayer1.isActive, isTrue);
expect(opacityLayer2.isCreated, isTrue);
builder2.pop();
@ -374,7 +373,7 @@ void testMain() {
final Path path = Path();
path.addPolygon([Offset(50, 0), Offset(100, 80), Offset(20, 40)], true);
PersistedPhysicalShape shape = builder1.pushPhysicalShape(path: path,
color: Color(0xFF00FF00), elevation: 1);
color: Color(0xFF00FF00), elevation: 1) as PersistedPhysicalShape;
builder1.build();
expect(() => shape.apply(), returnsNormally);
});
@ -430,7 +429,7 @@ class _LoggingTestSurface extends PersistedContainerSurface {
}
@override
double matchForUpdate(PersistedSurface existingSurface) {
double matchForUpdate(PersistedSurface? existingSurface) {
return 1.0;
}
}

View File

@ -2,7 +2,6 @@
// 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:async';
import 'dart:js_util' as js_util;
import 'dart:html' as html;
@ -98,7 +97,7 @@ void testMain() {
expect(window.onBeginFrame, same(callback));
});
EnginePlatformDispatcher.instance.invokeOnBeginFrame(null);
EnginePlatformDispatcher.instance.invokeOnBeginFrame(Duration.zero);
});
test('onReportTimings preserves the zone', () {
@ -114,7 +113,7 @@ void testMain() {
expect(window.onReportTimings, same(callback));
});
EnginePlatformDispatcher.instance.invokeOnReportTimings(null);
EnginePlatformDispatcher.instance.invokeOnReportTimings(<ui.FrameTiming>[]);
});
test('onDrawFrame preserves the zone', () {
@ -146,7 +145,7 @@ void testMain() {
expect(window.onPointerDataPacket, same(callback));
});
EnginePlatformDispatcher.instance.invokeOnPointerDataPacket(null);
EnginePlatformDispatcher.instance.invokeOnPointerDataPacket(ui.PointerDataPacket());
});
test('invokeOnKeyData returns normally when onKeyData is null', () {
@ -224,7 +223,7 @@ void testMain() {
expect(window.onSemanticsAction, same(callback));
});
EnginePlatformDispatcher.instance.invokeOnSemanticsAction(null, null, null);
EnginePlatformDispatcher.instance.invokeOnSemanticsAction(0, ui.SemanticsAction.tap, null);
});
test('onAccessibilityFeaturesChanged preserves the zone', () {
@ -256,7 +255,9 @@ void testMain() {
expect(window.onPlatformMessage, same(callback));
});
EnginePlatformDispatcher.instance.invokeOnPlatformMessage(null, null, null);
EnginePlatformDispatcher.instance.invokeOnPlatformMessage('foo', null, (ByteData? data) {
// Not testing anything here.
});
});
test('sendPlatformMessage preserves the zone', () async {
@ -299,13 +300,13 @@ void testMain() {
/// Regression test for https://github.com/flutter/flutter/issues/66128.
test('setPreferredOrientation responds even if browser doesn\'t support api', () async {
final html.Screen screen = html.window.screen;
final html.Screen screen = html.window.screen!;
js_util.setProperty(screen, 'orientation', null);
final Completer<bool> completer = Completer<bool>();
final ByteData inputData = JSONMethodCodec().encodeMethodCall(MethodCall(
'SystemChrome.setPreferredOrientations',
<dynamic>[]));
<dynamic>[]))!;
window.sendPlatformMessage(
'flutter/platform',

View File

@ -2,7 +2,6 @@
// 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:async';
import 'dart:html' as html;
import 'dart:math' as math;
@ -33,7 +32,7 @@ void testMain() async {
CanvasParagraph paragraph;
// Single-line multi-span.
paragraph = rich(ParagraphStyle(fontFamily: 'Roboto'), (builder) {
paragraph = rich(EngineParagraphStyle(fontFamily: 'Roboto'), (builder) {
builder.pushStyle(EngineTextStyle.only(color: blue));
builder.addText('Lorem ');
builder.pushStyle(EngineTextStyle.only(
@ -49,7 +48,7 @@ void testMain() async {
offset = offset.translate(0, paragraph.height + 10);
// Multi-line single-span.
paragraph = rich(ParagraphStyle(fontFamily: 'Roboto'), (builder) {
paragraph = rich(EngineParagraphStyle(fontFamily: 'Roboto'), (builder) {
builder.addText('Lorem ipsum dolor sit');
})
..layout(constrain(90.0));
@ -57,7 +56,7 @@ void testMain() async {
offset = offset.translate(0, paragraph.height + 10);
// Multi-line multi-span.
paragraph = rich(ParagraphStyle(fontFamily: 'Roboto'), (builder) {
paragraph = rich(EngineParagraphStyle(fontFamily: 'Roboto'), (builder) {
builder.pushStyle(EngineTextStyle.only(color: blue));
builder.addText('Lorem ipsum ');
builder.pushStyle(EngineTextStyle.only(background: Paint()..color = red));
@ -91,21 +90,21 @@ void testMain() async {
}
paragraph = rich(
ParagraphStyle(fontFamily: 'Roboto', textAlign: TextAlign.left),
EngineParagraphStyle(fontFamily: 'Roboto', textAlign: TextAlign.left),
build,
)..layout(constrain(100.0));
canvas.drawParagraph(paragraph, offset);
offset = offset.translate(0, paragraph.height + 10);
paragraph = rich(
ParagraphStyle(fontFamily: 'Roboto', textAlign: TextAlign.center),
EngineParagraphStyle(fontFamily: 'Roboto', textAlign: TextAlign.center),
build,
)..layout(constrain(100.0));
canvas.drawParagraph(paragraph, offset);
offset = offset.translate(0, paragraph.height + 10);
paragraph = rich(
ParagraphStyle(fontFamily: 'Roboto', textAlign: TextAlign.right),
EngineParagraphStyle(fontFamily: 'Roboto', textAlign: TextAlign.right),
build,
)..layout(constrain(100.0));
canvas.drawParagraph(paragraph, offset);
@ -132,21 +131,21 @@ void testMain() async {
}
paragraph = rich(
ParagraphStyle(fontFamily: 'Roboto', textAlign: TextAlign.left),
EngineParagraphStyle(fontFamily: 'Roboto', textAlign: TextAlign.left),
build,
)..layout(constrain(100.0));
canvas.drawParagraph(paragraph, offset);
offset = offset.translate(0, paragraph.height + 10);
paragraph = rich(
ParagraphStyle(fontFamily: 'Roboto', textAlign: TextAlign.center),
EngineParagraphStyle(fontFamily: 'Roboto', textAlign: TextAlign.center),
build,
)..layout(constrain(100.0));
canvas.drawParagraph(paragraph, offset);
offset = offset.translate(0, paragraph.height + 10);
paragraph = rich(
ParagraphStyle(fontFamily: 'Roboto', textAlign: TextAlign.right),
EngineParagraphStyle(fontFamily: 'Roboto', textAlign: TextAlign.right),
build,
)..layout(constrain(100.0));
canvas.drawParagraph(paragraph, offset);
@ -169,7 +168,7 @@ void testMain() async {
void drawParagraphAt(Offset offset, TextAlign align) {
paragraph = rich(
ParagraphStyle(fontFamily: 'Roboto', fontSize: 20.0, textAlign: align),
EngineParagraphStyle(fontFamily: 'Roboto', fontSize: 20.0, textAlign: align),
build,
)..layout(constrain(150.0));
canvas.save();
@ -200,7 +199,7 @@ void testMain() async {
void testGiantParagraphStyles(EngineCanvas canvas) {
final CanvasParagraph paragraph = rich(
ParagraphStyle(fontFamily: 'Roboto', fontSize: 80.0),
EngineParagraphStyle(fontFamily: 'Roboto', fontSize: 80.0),
(CanvasParagraphBuilder builder) {
builder.pushStyle(EngineTextStyle.only(color: yellow, fontSize: 24.0));
builder.addText('Lorem ');
@ -231,14 +230,14 @@ void testMain() async {
const Rect bounds = Rect.fromLTWH(0, 0, 600, 200);
// Store the old font size value on the body, and set a gaint font size.
final String oldBodyFontSize = html.document.body.style.fontSize;
html.document.body.style.fontSize = '100px';
final String oldBodyFontSize = html.document.body!.style.fontSize;
html.document.body!.style.fontSize = '100px';
final canvas = DomCanvas(domRenderer.createElement('flt-picture'));
Offset offset = Offset(10.0, 10.0);
final CanvasParagraph paragraph = rich(
ParagraphStyle(fontFamily: 'Roboto'),
EngineParagraphStyle(fontFamily: 'Roboto'),
(CanvasParagraphBuilder builder) {
builder.pushStyle(EngineTextStyle.only(color: yellow, fontSize: 24.0));
builder.addText('Lorem ');
@ -260,7 +259,7 @@ void testMain() async {
final double placeholderWidth = paragraph.height * 2;
final CanvasParagraph paragraph2 = rich(
ParagraphStyle(),
EngineParagraphStyle(),
(CanvasParagraphBuilder builder) {
builder.addPlaceholder(placeholderWidth, placeholderHeight, PlaceholderAlignment.baseline, baseline: TextBaseline.alphabetic);
},
@ -281,14 +280,14 @@ void testMain() async {
await takeScreenshot(canvas, bounds, 'canvas_paragraph_giant_body_font_size_dom');
// Restore the old font size value.
html.document.body.style.fontSize = oldBodyFontSize;
html.document.body!.style.fontSize = oldBodyFontSize;
});
test('paints spans with varying heights/baselines', () {
final canvas = BitmapCanvas(bounds, RenderStrategy());
final CanvasParagraph paragraph = rich(
ParagraphStyle(fontFamily: 'Roboto'),
EngineParagraphStyle(fontFamily: 'Roboto'),
(builder) {
builder.pushStyle(EngineTextStyle.only(fontSize: 20.0));
builder.addText('Lorem ');
@ -323,7 +322,7 @@ void testMain() async {
final canvas = BitmapCanvas(bounds, RenderStrategy());
final CanvasParagraph paragraph = rich(
ParagraphStyle(fontFamily: 'Roboto'),
EngineParagraphStyle(fontFamily: 'Roboto'),
(builder) {
builder.pushStyle(EngineTextStyle.only(color: blue));
builder.addText('Lorem ');
@ -349,7 +348,7 @@ void testMain() async {
];
final CanvasParagraph paragraph = rich(
ParagraphStyle(fontFamily: 'Roboto'),
EngineParagraphStyle(fontFamily: 'Roboto'),
(builder) {
for (TextDecorationStyle decorationStyle in decorationStyles) {
builder.pushStyle(EngineTextStyle.only(
@ -382,7 +381,7 @@ void testMain() async {
final FontFeature disableLigatures = FontFeature('liga', 0);
final CanvasParagraph paragraph = rich(
ParagraphStyle(fontFamily: 'Roboto'),
EngineParagraphStyle(fontFamily: 'Roboto'),
(CanvasParagraphBuilder builder) {
// Small Caps
builder.pushStyle(EngineTextStyle.only(

View File

@ -2,7 +2,6 @@
// 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:html' as html;
import 'dart:math' as math;
import 'dart:typed_data';
@ -39,7 +38,7 @@ void testMain() async {
final html.Element sceneElement = html.Element.tag('flt-scene');
try {
sceneElement.append(engineCanvas.rootElement);
html.document.body.append(sceneElement);
html.document.body!.append(sceneElement);
await matchGoldenFile('$fileName.png',
region: region, maxDiffRatePercent: maxDiffRatePercent, write: write);
} finally {
@ -60,7 +59,7 @@ void testMain() async {
RecordingCanvas(const Rect.fromLTRB(0, 0, 400, 300));
canvas.save();
final Paint borderPaint = Paint()
final SurfacePaint borderPaint = SurfacePaint()
..style = PaintingStyle.stroke
..strokeWidth = 1
..color = Color(0xFF000000);
@ -74,12 +73,12 @@ void testMain() async {
Color(0xFF656D78),];
List<double> stops = <double>[0.0, 0.05, 0.4, 0.6, 0.9, 1.0];
EngineGradient sweepGradient = GradientSweep(Offset(0.5, 0.5),
GradientSweep sweepGradient = GradientSweep(Offset(0.5, 0.5),
colors, stops, TileMode.clamp,
0, 360.0 / 180.0 * math.pi,
Matrix4.rotationZ(math.pi / 6.0).storage);
EngineGradient sweepGradientRotated = GradientSweep(Offset(0.5, 0.5),
GradientSweep sweepGradientRotated = GradientSweep(Offset(0.5, 0.5),
colors, stops, TileMode.clamp,
0, 360.0 / 180.0 * math.pi,
Matrix4.rotationZ(math.pi / 6.0).storage);
@ -89,13 +88,13 @@ void testMain() async {
// Gradient with default center.
Rect rectBounds = Rect.fromLTWH(10, 20, kBoxWidth, kBoxHeight);
canvas.drawRect(rectBounds,
Paint()..shader = engineGradientToShader(sweepGradient, rectBounds));
SurfacePaint()..shader = engineGradientToShader(sweepGradient, rectBounds));
canvas.drawRect(rectBounds, borderPaint);
// Gradient with shifted center and rotation.
rectBounds = rectBounds.translate(kBoxWidth + 10, 0);
canvas.drawRect(rectBounds,
Paint()..shader = engineGradientToShader(sweepGradientRotated, Rect.fromLTWH(rectBounds.center.dx, rectBounds.top, rectBounds.width / 2, rectBounds.height)));
SurfacePaint()..shader = engineGradientToShader(sweepGradientRotated, Rect.fromLTWH(rectBounds.center.dx, rectBounds.top, rectBounds.width / 2, rectBounds.height)));
canvas.drawRect(rectBounds, borderPaint);
// Gradient with start/endangle.
@ -106,7 +105,7 @@ void testMain() async {
rectBounds = rectBounds.translate(kBoxWidth + 10, 0);
canvas.drawRect(rectBounds,
new Paint()..shader = engineGradientToShader(sweepGradient, rectBounds));
SurfacePaint()..shader = engineGradientToShader(sweepGradient, rectBounds));
canvas.drawRect(rectBounds, borderPaint);
// Tile mode repeat
@ -117,7 +116,7 @@ void testMain() async {
Matrix4.rotationZ(math.pi / 6.0).storage);
canvas.drawRect(rectBounds,
new Paint()..shader = engineGradientToShader(sweepGradient, rectBounds));
SurfacePaint()..shader = engineGradientToShader(sweepGradient, rectBounds));
canvas.drawRect(rectBounds, borderPaint);
// Tile mode mirror
@ -127,7 +126,7 @@ void testMain() async {
math.pi / 6, 3 * math.pi / 4,
Matrix4.rotationZ(math.pi / 6.0).storage);
canvas.drawRect(rectBounds,
new Paint()..shader = engineGradientToShader(sweepGradient, rectBounds));
SurfacePaint()..shader = engineGradientToShader(sweepGradient, rectBounds));
canvas.drawRect(rectBounds, borderPaint);
canvas.restore();
@ -139,7 +138,7 @@ void testMain() async {
RecordingCanvas(const Rect.fromLTRB(0, 0, 400, 300));
canvas.save();
final Paint borderPaint = Paint()
final SurfacePaint borderPaint = SurfacePaint()
..style = PaintingStyle.stroke
..strokeWidth = 1
..color = Color(0xFF000000);
@ -153,12 +152,12 @@ void testMain() async {
Color(0xFF656D78),];
List<double> stops = <double>[0.0, 0.05, 0.4, 0.6, 0.9, 1.0];
EngineGradient sweepGradient = GradientSweep(Offset(0.5, 0.5),
GradientSweep sweepGradient = GradientSweep(Offset(0.5, 0.5),
colors, stops, TileMode.clamp,
0, 360.0 / 180.0 * math.pi,
Matrix4.rotationZ(math.pi / 6.0).storage);
EngineGradient sweepGradientRotated = GradientSweep(Offset(0.5, 0.5),
GradientSweep sweepGradientRotated = GradientSweep(Offset(0.5, 0.5),
colors, stops, TileMode.clamp,
0, 360.0 / 180.0 * math.pi,
Matrix4.rotationZ(math.pi / 6.0).storage);
@ -168,13 +167,13 @@ void testMain() async {
// Gradient with default center.
Rect rectBounds = Rect.fromLTWH(10, 20, kBoxWidth, kBoxHeight);
canvas.drawOval(rectBounds,
Paint()..shader = engineGradientToShader(sweepGradient, rectBounds));
SurfacePaint()..shader = engineGradientToShader(sweepGradient, rectBounds));
canvas.drawRect(rectBounds, borderPaint);
// Gradient with shifted center and rotation.
rectBounds = rectBounds.translate(kBoxWidth + 10, 0);
canvas.drawOval(rectBounds,
Paint()..shader = engineGradientToShader(sweepGradientRotated, Rect.fromLTWH(rectBounds.center.dx, rectBounds.top, rectBounds.width / 2, rectBounds.height)));
SurfacePaint()..shader = engineGradientToShader(sweepGradientRotated, Rect.fromLTWH(rectBounds.center.dx, rectBounds.top, rectBounds.width / 2, rectBounds.height)));
canvas.drawRect(rectBounds, borderPaint);
// Gradient with start/endangle.
@ -185,7 +184,7 @@ void testMain() async {
rectBounds = rectBounds.translate(kBoxWidth + 10, 0);
canvas.drawOval(rectBounds,
new Paint()..shader = engineGradientToShader(sweepGradient, rectBounds));
SurfacePaint()..shader = engineGradientToShader(sweepGradient, rectBounds));
canvas.drawRect(rectBounds, borderPaint);
// Tile mode repeat
@ -196,7 +195,7 @@ void testMain() async {
Matrix4.rotationZ(math.pi / 6.0).storage);
canvas.drawOval(rectBounds,
new Paint()..shader = engineGradientToShader(sweepGradient, rectBounds));
SurfacePaint()..shader = engineGradientToShader(sweepGradient, rectBounds));
canvas.drawRect(rectBounds, borderPaint);
// Tile mode mirror
@ -206,7 +205,7 @@ void testMain() async {
math.pi / 6, 3 * math.pi / 4,
Matrix4.rotationZ(math.pi / 6.0).storage);
canvas.drawOval(rectBounds,
new Paint()..shader = engineGradientToShader(sweepGradient, rectBounds));
SurfacePaint()..shader = engineGradientToShader(sweepGradient, rectBounds));
canvas.drawRect(rectBounds, borderPaint);
canvas.restore();
@ -218,7 +217,7 @@ void testMain() async {
RecordingCanvas(const Rect.fromLTRB(0, 0, 400, 300));
canvas.save();
final Paint borderPaint = Paint()
final SurfacePaint borderPaint = SurfacePaint()
..style = PaintingStyle.stroke
..strokeWidth = 1
..color = Color(0xFF000000);
@ -232,12 +231,12 @@ void testMain() async {
Color(0xFF656D78),];
List<double> stops = <double>[0.0, 0.05, 0.4, 0.6, 0.9, 1.0];
EngineGradient sweepGradient = GradientSweep(Offset(0.5, 0.5),
GradientSweep sweepGradient = GradientSweep(Offset(0.5, 0.5),
colors, stops, TileMode.clamp,
0, 360.0 / 180.0 * math.pi,
Matrix4.rotationZ(math.pi / 6.0).storage);
EngineGradient sweepGradientRotated = GradientSweep(Offset(0.5, 0.5),
GradientSweep sweepGradientRotated = GradientSweep(Offset(0.5, 0.5),
colors, stops, TileMode.clamp,
0, 360.0 / 180.0 * math.pi,
Matrix4.rotationZ(math.pi / 6.0).storage);
@ -248,14 +247,14 @@ void testMain() async {
Rect rectBounds = Rect.fromLTWH(10, 20, kBoxWidth, kBoxHeight);
Path path = samplePathFromRect(rectBounds);
canvas.drawPath(path,
Paint()..shader = engineGradientToShader(sweepGradient, rectBounds));
SurfacePaint()..shader = engineGradientToShader(sweepGradient, rectBounds));
canvas.drawRect(rectBounds, borderPaint);
// Gradient with shifted center and rotation.
rectBounds = rectBounds.translate(kBoxWidth + 10, 0);
path = samplePathFromRect(rectBounds);
canvas.drawPath(path,
Paint()..shader = engineGradientToShader(sweepGradientRotated, Rect.fromLTWH(rectBounds.center.dx, rectBounds.top, rectBounds.width / 2, rectBounds.height)));
SurfacePaint()..shader = engineGradientToShader(sweepGradientRotated, Rect.fromLTWH(rectBounds.center.dx, rectBounds.top, rectBounds.width / 2, rectBounds.height)));
canvas.drawRect(rectBounds, borderPaint);
// Gradient with start/endangle.
@ -267,7 +266,7 @@ void testMain() async {
rectBounds = rectBounds.translate(kBoxWidth + 10, 0);
path = samplePathFromRect(rectBounds);
canvas.drawPath(path,
new Paint()..shader = engineGradientToShader(sweepGradient, rectBounds));
SurfacePaint()..shader = engineGradientToShader(sweepGradient, rectBounds));
canvas.drawRect(rectBounds, borderPaint);
// Tile mode repeat
@ -279,7 +278,7 @@ void testMain() async {
path = samplePathFromRect(rectBounds);
canvas.drawPath(path,
new Paint()..shader = engineGradientToShader(sweepGradient, rectBounds));
SurfacePaint()..shader = engineGradientToShader(sweepGradient, rectBounds));
canvas.drawRect(rectBounds, borderPaint);
// Tile mode mirror
@ -290,7 +289,7 @@ void testMain() async {
Matrix4.rotationZ(math.pi / 6.0).storage);
path = samplePathFromRect(rectBounds);
canvas.drawPath(path,
new Paint()..shader = engineGradientToShader(sweepGradient, rectBounds));
SurfacePaint()..shader = engineGradientToShader(sweepGradient, rectBounds));
canvas.drawRect(rectBounds, borderPaint);
canvas.restore();
@ -303,7 +302,7 @@ void testMain() async {
RecordingCanvas(const Rect.fromLTRB(0, 0, 400, 300));
canvas.save();
final Paint borderPaint = Paint()
final SurfacePaint borderPaint = SurfacePaint()
..style = PaintingStyle.stroke
..strokeWidth = 1
..color = Color(0xFF000000);
@ -317,7 +316,7 @@ void testMain() async {
Color(0xFF656D78),];
List<double> stops = <double>[0.0, 0.05, 0.4, 0.6, 0.9, 1.0];
EngineGradient linearGradient = GradientLinear(Offset(50, 50),
GradientLinear linearGradient = GradientLinear(Offset(50, 50),
Offset(200,130),
colors, stops, TileMode.clamp,
Matrix4.identity().storage);
@ -327,7 +326,7 @@ void testMain() async {
// Gradient with default center.
Rect rectBounds = Rect.fromLTWH(10, 20, kBoxWidth, kBoxHeight);
canvas.drawRect(rectBounds,
Paint()..shader = engineLinearGradientToShader(linearGradient, rectBounds));
SurfacePaint()..shader = engineLinearGradientToShader(linearGradient, rectBounds));
canvas.drawRect(rectBounds, borderPaint);
// Tile mode repeat
@ -338,7 +337,7 @@ void testMain() async {
Matrix4.identity().storage);
canvas.drawRect(rectBounds,
new Paint()..shader = engineLinearGradientToShader(linearGradient, rectBounds));
SurfacePaint()..shader = engineLinearGradientToShader(linearGradient, rectBounds));
canvas.drawRect(rectBounds, borderPaint);
canvas.restore();
@ -351,7 +350,7 @@ void testMain() async {
RecordingCanvas(const Rect.fromLTRB(0, 0, 400, 300));
canvas.save();
final Paint borderPaint = Paint()
final SurfacePaint borderPaint = SurfacePaint()
..style = PaintingStyle.stroke
..strokeWidth = 1
..color = Color(0xFF000000);
@ -361,7 +360,7 @@ void testMain() async {
Color(0xFFFF3C38)];
List<double> stops = <double>[0.0, 10.0];
EngineGradient linearGradient = GradientLinear(Offset(50, 50),
GradientLinear linearGradient = GradientLinear(Offset(50, 50),
Offset(200,130),
colors, stops, TileMode.clamp,
Matrix4.identity().storage);
@ -371,7 +370,7 @@ void testMain() async {
// Gradient with default center.
Rect rectBounds = Rect.fromLTWH(10, 20, kBoxWidth, kBoxHeight);
canvas.drawRect(rectBounds,
Paint()..shader = engineLinearGradientToShader(linearGradient, rectBounds));
SurfacePaint()..shader = engineLinearGradientToShader(linearGradient, rectBounds));
canvas.drawRect(rectBounds, borderPaint);
canvas.restore();
@ -386,7 +385,7 @@ void testMain() async {
RecordingCanvas(const Rect.fromLTRB(0, 0, 400, 300));
canvas.save();
final Paint borderPaint = Paint()
final SurfacePaint borderPaint = SurfacePaint()
..style = PaintingStyle.stroke
..strokeWidth = 1
..color = Color(0xFF000000);
@ -400,7 +399,7 @@ void testMain() async {
Color(0xFF656D78),];
List<double> stops = <double>[0.0, 0.05, 0.4, 0.6, 0.9, 1.0];
EngineGradient linearGradient = GradientLinear(Offset(50, 50),
GradientLinear linearGradient = GradientLinear(Offset(50, 50),
Offset(200,130),
colors, stops, TileMode.clamp,
Matrix4.identity().storage);
@ -410,7 +409,7 @@ void testMain() async {
// Gradient with default center.
Rect rectBounds = Rect.fromLTWH(10, 20, kBoxWidth, kBoxHeight);
canvas.drawRect(rectBounds,
Paint()..shader = engineLinearGradientToShader(linearGradient, rectBounds));
SurfacePaint()..shader = engineLinearGradientToShader(linearGradient, rectBounds));
canvas.drawRect(rectBounds, borderPaint);
// Tile mode repeat
@ -421,7 +420,7 @@ void testMain() async {
Matrix4.identity().storage);
canvas.drawRect(rectBounds,
new Paint()..shader = engineLinearGradientToShader(linearGradient, rectBounds));
SurfacePaint()..shader = engineLinearGradientToShader(linearGradient, rectBounds));
canvas.drawRect(rectBounds, borderPaint);
canvas.restore();
@ -437,7 +436,7 @@ Shader engineGradientToShader(GradientSweep gradient, Rect rect) {
gradient.startAngle,
gradient.endAngle,
gradient.matrix4 == null ? null :
Float64List.fromList(gradient.matrix4),
Float64List.fromList(gradient.matrix4!),
);
}
@ -445,7 +444,7 @@ Shader engineLinearGradientToShader(GradientLinear gradient, Rect rect) {
return Gradient.linear(gradient.from, gradient.to,
gradient.colors, gradient.colorStops, gradient.tileMode,
gradient.matrix4 == null ? null : Float64List.fromList(
gradient.matrix4.matrix),
gradient.matrix4!.matrix),
);
}

View File

@ -2,7 +2,6 @@
// 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:math' as math;
import 'package:test/bootstrap/browser.dart';
@ -107,12 +106,12 @@ const Rect testBounds = Rect.fromLTRB(50, 50, 230, 220);
void drawBackground(RecordingCanvas canvas) {
canvas.drawRect(
testBounds,
Paint()
SurfacePaint()
..style = PaintingStyle.fill
..color = const Color(0xFF9E9E9E));
canvas.drawRect(
testBounds.inflate(-40),
Paint()
SurfacePaint()
..strokeWidth = 1
..style = PaintingStyle.stroke
..color = const Color(0xFF009688));
@ -158,7 +157,7 @@ void paintTextWithClipRoundRect(RecordingCanvas canvas) {
drawBackground(canvas);
canvas.drawRRect(
roundRect,
Paint()
SurfacePaint()
..color = deepOrange
..style = PaintingStyle.fill);
canvas.clipRRect(roundRect);
@ -180,7 +179,7 @@ void paintTextWithClipPath(RecordingCanvas canvas) {
path.close();
canvas.drawPath(
path,
Paint()
SurfacePaint()
..color = deepOrange
..style = PaintingStyle.fill);
canvas.clipPath(path);
@ -196,7 +195,7 @@ void paintTextWithClipStack(RecordingCanvas canvas) {
canvas.clipRect(inflatedRect, ClipOp.intersect);
canvas.drawRect(
inflatedRect,
Paint()
SurfacePaint()
..color = deepOrange
..style = PaintingStyle.fill);
drawQuickBrownFox(canvas);

View File

@ -2,7 +2,6 @@
// 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:html' as html;
import 'package:test/bootstrap/browser.dart';
@ -28,8 +27,8 @@ void testMain() async {
Rect.fromLTWH(8, 8, 600, 400); // Compensate for old scuba tester padding
Future<void> testPath(Path path, String scubaFileName,
{Paint paint,
double maxDiffRatePercent = null,
{SurfacePaint? paint,
double? maxDiffRatePercent,
bool write = false,
PaintMode mode = PaintMode.kStrokeAndFill}) async {
const Rect canvasBounds = Rect.fromLTWH(0, 0, 600, 400);
@ -40,31 +39,31 @@ void testMain() async {
bool enableFill =
mode == PaintMode.kStrokeAndFill || mode == PaintMode.kFill;
if (enableFill) {
paint ??= Paint()
paint ??= SurfacePaint()
..color = const Color(0x807F7F7F)
..style = PaintingStyle.fill;
canvas.drawPath(path, paint);
}
if (mode == PaintMode.kStrokeAndFill || mode == PaintMode.kStroke) {
paint = Paint()
paint = SurfacePaint()
..strokeWidth = 2
..color = enableFill ? const Color(0xFFFF0000) : const Color(0xFF000000)
..style = PaintingStyle.stroke;
}
if (mode == PaintMode.kStrokeWidthOnly) {
paint = Paint()
paint = SurfacePaint()
..color = const Color(0xFF4060E0)
..strokeWidth = 10;
}
canvas.drawPath(path, paint);
canvas.drawPath(path, paint!);
final html.Element svgElement = pathToSvgElement(path, paint, enableFill);
html.document.body.append(bitmapCanvas.rootElement);
html.document.body.append(svgElement);
html.document.body!.append(bitmapCanvas.rootElement);
html.document.body!.append(svgElement);
canvas.endRecording();
canvas.apply(bitmapCanvas, canvasBounds);
@ -77,7 +76,7 @@ void testMain() async {
}
tearDown(() {
html.document.body.children.clear();
html.document.body!.children.clear();
});
test('render line strokes', () async {
@ -85,7 +84,7 @@ void testMain() async {
path.moveTo(50, 60);
path.lineTo(200, 300);
await testPath(path, 'svg_stroke_line',
paint: Paint()
paint: SurfacePaint()
..color = const Color(0xFFFF0000)
..strokeWidth = 2.0
..style = PaintingStyle.stroke);
@ -192,7 +191,7 @@ html.Element pathToSvgElement(Path path, Paint paint, bool enableFill) {
'width="${bounds.right}" height="${bounds.bottom}">');
sb.write('<path ');
if (paint.style == PaintingStyle.stroke ||
(paint.strokeWidth != null && paint.strokeWidth != 0.0)) {
paint.strokeWidth != 0.0) {
sb.write('stroke="${colorToCssString(paint.color)}" ');
sb.write('stroke-width="${paint.strokeWidth}" ');
if (!enableFill) {

View File

@ -2,7 +2,6 @@
// 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:html' as html;
import 'dart:math' as math;
import 'dart:typed_data';
@ -23,7 +22,7 @@ void testMain() async {
const double screenWidth = 600.0;
const double screenHeight = 800.0;
const Rect screenRect = Rect.fromLTWH(0, 0, screenWidth, screenHeight);
final Paint testPaint = Paint()..color = const Color(0xFFFF0000);
final SurfacePaint testPaint = SurfacePaint()..color = const Color(0xFFFF0000);
// Commit a recording canvas to a bitmap, and compare with the expected
Future<void> _checkScreenshot(RecordingCanvas rc, String fileName,
@ -37,7 +36,7 @@ void testMain() async {
engineCanvas
..save()
..drawRect(
rc.pictureBounds,
rc.pictureBounds!,
SurfacePaintData()
..color = const Color.fromRGBO(0, 0, 255, 1.0)
..style = PaintingStyle.stroke
@ -51,7 +50,7 @@ void testMain() async {
final html.Element sceneElement = html.Element.tag('flt-scene');
try {
sceneElement.append(engineCanvas.rootElement);
html.document.body.append(sceneElement);
html.document.body!.append(sceneElement);
await matchGoldenFile('paint_bounds_for_$fileName.png', region: region,
write: write);
} finally {
@ -219,7 +218,7 @@ void testMain() async {
test('drawColor should cover full size', () async {
final RecordingCanvas rc = RecordingCanvas(screenRect);
final Paint testPaint = Paint()..color = const Color(0xFF80FF00);
final SurfacePaint testPaint = SurfacePaint()..color = const Color(0xFF80FF00);
rc.drawRect(const Rect.fromLTRB(10, 20, 30, 40), testPaint);
rc.drawColor(const Color(0xFFFF0000), BlendMode.multiply);
rc.drawRect(const Rect.fromLTRB(10, 60, 30, 80), testPaint);
@ -287,7 +286,7 @@ void testMain() async {
test('Computes paint bounds for draw image', () {
final RecordingCanvas rc = RecordingCanvas(screenRect);
rc.drawImage(TestImage(), const Offset(50, 100), Paint());
rc.drawImage(TestImage(), const Offset(50, 100), SurfacePaint());
rc.endRecording();
expect(rc.pictureBounds, const Rect.fromLTRB(50.0, 100.0, 70.0, 110.0));
});
@ -295,7 +294,7 @@ void testMain() async {
test('Computes paint bounds for draw image rect', () {
final RecordingCanvas rc = RecordingCanvas(screenRect);
rc.drawImageRect(TestImage(), const Rect.fromLTRB(1, 1, 20, 10),
const Rect.fromLTRB(5, 6, 400, 500), Paint());
const Rect.fromLTRB(5, 6, 400, 500), SurfacePaint());
rc.endRecording();
expect(rc.pictureBounds, const Rect.fromLTRB(5.0, 6.0, 400.0, 500.0));
});
@ -414,7 +413,7 @@ void testMain() async {
..translate(0, 100)
..scale(1, -1)
..clipRect(const Rect.fromLTRB(0, 0, 100, 50), ClipOp.intersect)
..drawRect(const Rect.fromLTRB(0, 0, 100, 100), Paint());
..drawRect(const Rect.fromLTRB(0, 0, 100, 100), SurfacePaint());
rc.endRecording();
expect(rc.pictureBounds, const Rect.fromLTRB(0.0, 50.0, 100.0, 100.0));
@ -428,7 +427,7 @@ void testMain() async {
..translate(50, 50)
..rotate(math.pi / 4.0)
..clipRect(const Rect.fromLTWH(-20, -20, 40, 40), ClipOp.intersect)
..drawRect(const Rect.fromLTWH(-80, -80, 160, 160), Paint());
..drawRect(const Rect.fromLTWH(-80, -80, 160, 160), SurfacePaint());
rc.endRecording();
expect(
@ -447,7 +446,7 @@ void testMain() async {
rc
..translate(50, 50)
..rotate(math.pi / 4.0)
..drawLine(const Offset(0, 0), const Offset(20, 20), Paint());
..drawLine(const Offset(0, 0), const Offset(20, 20), SurfacePaint());
rc.endRecording();
expect(
@ -467,7 +466,7 @@ void testMain() async {
path.lineTo(100, 97);
rc.drawPath(
path,
Paint()
SurfacePaint()
..style = PaintingStyle.stroke
..strokeWidth = 2.0
..color = const Color(0xFFFF0000));
@ -476,7 +475,7 @@ void testMain() async {
path.lineTo(97, 100);
rc.drawPath(
path,
Paint()
SurfacePaint()
..style = PaintingStyle.stroke
..strokeWidth = 2.0
..color = const Color(0xFF00FF00));
@ -498,7 +497,7 @@ void testMain() async {
RRect.fromLTRBR(0.5, 100.5, 80.7, 150.7, const Radius.circular(10)));
rc.drawPath(
path,
Paint()
SurfacePaint()
..style = PaintingStyle.stroke
..strokeWidth = 2.0
..color = const Color(0xFF404000));
@ -522,7 +521,7 @@ void testMain() async {
path.close();
rc.drawPath(
path,
Paint()
SurfacePaint()
..style = PaintingStyle.stroke
..strokeWidth = 2.0
..color = const Color(0xFF404000));
@ -624,7 +623,7 @@ void testMain() async {
final SurfacePaint zeroSpreadPaint = SurfacePaint();
painter(canvas, zeroSpreadPaint);
sb.addPicture(Offset.zero, recorder.endRecording());
sb.addPicture(Offset.zero, drawBounds(canvas.pictureBounds));
sb.addPicture(Offset.zero, drawBounds(canvas.pictureBounds!));
sb.pop();
}
@ -638,7 +637,7 @@ void testMain() async {
..strokeWidth = 5.0;
painter(canvas, thickStrokePaint);
sb.addPicture(Offset.zero, recorder.endRecording());
sb.addPicture(Offset.zero, drawBounds(canvas.pictureBounds));
sb.addPicture(Offset.zero, drawBounds(canvas.pictureBounds!));
sb.pop();
}
@ -651,7 +650,7 @@ void testMain() async {
..maskFilter = const MaskFilter.blur(BlurStyle.normal, 5.0);
painter(canvas, maskFilterBlurPaint);
sb.addPicture(Offset.zero, recorder.endRecording());
sb.addPicture(Offset.zero, drawBounds(canvas.pictureBounds));
sb.addPicture(Offset.zero, drawBounds(canvas.pictureBounds!));
sb.pop();
}
@ -666,15 +665,15 @@ void testMain() async {
..maskFilter = const MaskFilter.blur(BlurStyle.normal, 5.0);
painter(canvas, thickStrokeAndBlurPaint);
sb.addPicture(Offset.zero, recorder.endRecording());
sb.addPicture(Offset.zero, drawBounds(canvas.pictureBounds));
sb.addPicture(Offset.zero, drawBounds(canvas.pictureBounds!));
sb.pop();
}
sb.pop();
}
final html.Element sceneElement = sb.build().webOnlyRootElement;
html.document.body.append(sceneElement);
final html.Element sceneElement = sb.build().webOnlyRootElement!;
html.document.body!.append(sceneElement);
try {
await matchGoldenFile(
'paint_spread_bounds.png',

View File

@ -138,7 +138,7 @@ final ui.TextStyle _defaultTextStyle = ui.TextStyle(
fontSize: 14,
);
ui.Paragraph paragraph(
EngineParagraph paragraph(
String text, {
ui.ParagraphStyle? paragraphStyle,
ui.TextStyle? textStyle,
@ -149,7 +149,9 @@ ui.Paragraph paragraph(
builder.pushStyle(textStyle ?? _defaultTextStyle);
builder.addText(text);
builder.pop();
return builder.build()..layout(ui.ParagraphConstraints(width: maxWidth));
final EngineParagraph paragraph = builder.build() as EngineParagraph;
paragraph.layout(ui.ParagraphConstraints(width: maxWidth));
return paragraph;
}
/// Configures the test to use bundled Roboto and Ahem fonts to avoid golden

View File

@ -2,7 +2,6 @@
// 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:async';
import 'package:test/bootstrap/browser.dart';
@ -39,13 +38,13 @@ void testMain() async {
setUpStableTestFonts();
Paragraph warning(String text) {
EngineParagraph warning(String text) {
return paragraph(text, textStyle: warningStyle);
}
testEachCanvas('maxLines clipping', (EngineCanvas canvas) {
Offset offset = Offset.zero;
Paragraph p;
EngineParagraph p;
// All three lines are rendered.
p = paragraph(threeLines);
@ -73,7 +72,7 @@ void testMain() async {
testEachCanvas('maxLines with overflow', (EngineCanvas canvas) {
Offset offset = Offset.zero;
Paragraph p;
EngineParagraph p;
// Only the first line is rendered with no ellipsis because the first line
// doesn't overflow.
@ -94,7 +93,7 @@ void testMain() async {
offset = offset.translate(0, p.height + 10);
// Only the first line is rendered with an ellipsis.
if (!WebExperiments.instance.useCanvasText) {
if (!WebExperiments.instance!.useCanvasText) {
// This is now correct with the canvas-based measurement, so we shouldn't
// print the "(wrong)" warning.
p = warning('(wrong)');
@ -111,7 +110,7 @@ void testMain() async {
// Only the first two lines are rendered and the ellipsis appears on the 2nd
// line.
if (!WebExperiments.instance.useCanvasText) {
if (!WebExperiments.instance!.useCanvasText) {
// This is now correct with the canvas-based measurement, so we shouldn't
// print the "(wrong)" warning.
p = warning('(wrong)');
@ -131,7 +130,7 @@ void testMain() async {
testEachCanvas('long unbreakable text', (EngineCanvas canvas) {
Offset offset = Offset.zero;
Paragraph p;
EngineParagraph p;
// The whole line is rendered unbroken when there are no constraints.
p = paragraph(longUnbreakable);

View File

@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.6
import 'package:test/bootstrap/browser.dart';
import 'package:ui/ui.dart';
import 'package:ui/src/engine.dart';

View File

@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.6
@TestOn('chrome || firefox')
import 'package:test/bootstrap/browser.dart';
@ -21,13 +20,13 @@ const ui.ParagraphConstraints infiniteConstraints =
ui.ParagraphConstraints(width: double.infinity);
DomParagraph build(ui.ParagraphStyle style, String text,
{ui.TextStyle textStyle}) {
final DomParagraphBuilder builder = DomParagraphBuilder(style);
{ui.TextStyle? textStyle}) {
final DomParagraphBuilder builder = DomParagraphBuilder(style as EngineParagraphStyle);
if (textStyle != null) {
builder.pushStyle(textStyle);
}
builder.addText(text);
return builder.build();
return builder.build() as DomParagraph;
}
typedef MeasurementTestBody = void Function(TextMeasurementService instance);
@ -35,17 +34,17 @@ typedef MeasurementTestBody = void Function(TextMeasurementService instance);
/// Runs the same test twice - once with dom measurement and once with canvas
/// measurement.
void testMeasurements(String description, MeasurementTestBody body, {
bool skipDom,
bool skipCanvas,
bool? skipDom,
bool? skipCanvas,
}) {
test(
'$description (dom)',
() {
try {
WebExperiments.instance.useCanvasRichText = false;
WebExperiments.instance!.useCanvasRichText = false;
return body(TextMeasurementService.domInstance);
} finally {
WebExperiments.instance.useCanvasRichText = null;
WebExperiments.instance!.useCanvasRichText = null;
}
},
skip: skipDom,
@ -54,10 +53,10 @@ void testMeasurements(String description, MeasurementTestBody body, {
'$description (canvas)',
() {
try {
WebExperiments.instance.useCanvasRichText = false;
WebExperiments.instance!.useCanvasRichText = false;
return body(TextMeasurementService.canvasInstance);
} finally {
WebExperiments.instance.useCanvasRichText = null;
WebExperiments.instance!.useCanvasRichText = null;
}
},
skip: skipCanvas,
@ -77,9 +76,9 @@ void testMain() async {
);
final ui.ParagraphStyle s3 = ui.ParagraphStyle(fontSize: 22.0);
ParagraphGeometricStyle style1, style2, style3;
DomParagraph style1Text1, style1Text2; // two paragraphs sharing style
DomParagraph style2Text1, style3Text3;
late ParagraphGeometricStyle style1, style2, style3;
late DomParagraph style1Text1, style1Text2; // two paragraphs sharing style
late DomParagraph style2Text1, style3Text3;
setUp(() {
style1Text1 = build(s1, '1');
@ -152,11 +151,11 @@ void testMain() async {
expect(ruler2.debugIsDisposed, isFalse);
expect(ruler3.debugIsDisposed, isTrue);
ruler1 = rulerManager.rulers[style1];
ruler1 = rulerManager.rulers[style1]!;
expect(ruler1.style, style1);
expect(ruler1.hitCount, 0); // hit counts are reset
ruler2 = rulerManager.rulers[style2];
ruler2 = rulerManager.rulers[style2]!;
expect(ruler2.style, style2);
expect(ruler2.hitCount, 0); // hit counts are reset
});
@ -173,12 +172,12 @@ void testMain() async {
testMeasurements(
'preserves whitespace when measuring',
(TextMeasurementService instance) {
ui.Paragraph text;
DomParagraph text;
MeasurementResult result;
// leading whitespaces
text = build(ahemStyle, ' abc');
result = instance.measure(text, infiniteConstraints);
result = instance.measure(text, infiniteConstraints)!;
expect(result.maxIntrinsicWidth, 60);
expect(result.minIntrinsicWidth, 30);
expect(result.height, 10);
@ -188,7 +187,7 @@ void testMain() async {
// trailing whitespaces
text = build(ahemStyle, 'abc ');
result = instance.measure(text, infiniteConstraints);
result = instance.measure(text, infiniteConstraints)!;
expect(result.maxIntrinsicWidth, 60);
expect(result.minIntrinsicWidth, 30);
expect(result.height, 10);
@ -206,7 +205,7 @@ void testMain() async {
// mixed whitespaces
text = build(ahemStyle, ' ab c ');
result = instance.measure(text, infiniteConstraints);
result = instance.measure(text, infiniteConstraints)!;
expect(result.maxIntrinsicWidth, 100);
expect(result.minIntrinsicWidth, 20);
expect(result.height, 10);
@ -224,7 +223,7 @@ void testMain() async {
// single whitespace
text = build(ahemStyle, ' ');
result = instance.measure(text, infiniteConstraints);
result = instance.measure(text, infiniteConstraints)!;
expect(result.maxIntrinsicWidth, 10);
expect(result.minIntrinsicWidth, 0);
expect(result.height, 10);
@ -242,7 +241,7 @@ void testMain() async {
// whitespace only
text = build(ahemStyle, ' ');
result = instance.measure(text, infiniteConstraints);
result = instance.measure(text, infiniteConstraints)!;
expect(result.maxIntrinsicWidth, 50);
expect(result.minIntrinsicWidth, 0);
expect(result.height, 10);
@ -264,7 +263,7 @@ void testMain() async {
'uses single-line when text can fit without wrapping',
(TextMeasurementService instance) {
final MeasurementResult result =
instance.measure(build(ahemStyle, '12345'), constraints);
instance.measure(build(ahemStyle, '12345'), constraints)!;
// Should fit on a single line.
expect(result.isSingleLine, isTrue);
@ -287,7 +286,7 @@ void testMain() async {
MeasurementResult result;
// The long text doesn't fit in 70px of width, so it needs to wrap.
result = instance.measure(build(ahemStyle, 'foo bar baz'), constraints);
result = instance.measure(build(ahemStyle, 'foo bar baz'), constraints)!;
expect(result.isSingleLine, isFalse);
expect(result.alphabeticBaseline, 8);
expect(result.maxIntrinsicWidth, 110);
@ -313,7 +312,7 @@ void testMain() async {
MeasurementResult result;
// The long text doesn't fit in 50px of width, so it needs to wrap.
result = instance.measure(build(ahemStyle, '1234567890'), constraints);
result = instance.measure(build(ahemStyle, '1234567890'), constraints)!;
expect(result.isSingleLine, isFalse);
expect(result.alphabeticBaseline, 8);
expect(result.maxIntrinsicWidth, 100);
@ -333,7 +332,7 @@ void testMain() async {
// The first word is force-broken twice.
result =
instance.measure(build(ahemStyle, 'abcdefghijk lm'), constraints);
instance.measure(build(ahemStyle, 'abcdefghijk lm'), constraints)!;
expect(result.isSingleLine, isFalse);
expect(result.alphabeticBaseline, 8);
expect(result.maxIntrinsicWidth, 140);
@ -356,7 +355,7 @@ void testMain() async {
// we show a minimum of one character per line.
const ui.ParagraphConstraints narrowConstraints =
ui.ParagraphConstraints(width: 8);
result = instance.measure(build(ahemStyle, 'AA'), narrowConstraints);
result = instance.measure(build(ahemStyle, 'AA'), narrowConstraints)!;
expect(result.isSingleLine, isFalse);
expect(result.alphabeticBaseline, 8);
expect(result.maxIntrinsicWidth, 20);
@ -375,7 +374,7 @@ void testMain() async {
}
// Extremely narrow constraints with new line in the middle.
result = instance.measure(build(ahemStyle, 'AA\nA'), narrowConstraints);
result = instance.measure(build(ahemStyle, 'AA\nA'), narrowConstraints)!;
expect(result.isSingleLine, isFalse);
expect(result.alphabeticBaseline, 8);
expect(result.maxIntrinsicWidth, 20);
@ -395,7 +394,7 @@ void testMain() async {
}
// Extremely narrow constraints with new line in the end.
result = instance.measure(build(ahemStyle, 'AAA\n'), narrowConstraints);
result = instance.measure(build(ahemStyle, 'AAA\n'), narrowConstraints)!;
expect(result.isSingleLine, isFalse);
expect(result.alphabeticBaseline, 8);
expect(result.maxIntrinsicWidth, 30);
@ -422,7 +421,7 @@ void testMain() async {
'uses multi-line for text that contains new-line',
(TextMeasurementService instance) {
final MeasurementResult result =
instance.measure(build(ahemStyle, '12\n34'), constraints);
instance.measure(build(ahemStyle, '12\n34'), constraints)!;
// Text containing newlines should always be drawn in multi-line mode.
expect(result.isSingleLine, isFalse);
@ -447,7 +446,7 @@ void testMain() async {
MeasurementResult result;
// Empty lines in the beginning.
result = instance.measure(build(ahemStyle, '\n\n1234'), constraints);
result = instance.measure(build(ahemStyle, '\n\n1234'), constraints)!;
expect(result.maxIntrinsicWidth, 40);
expect(result.minIntrinsicWidth, 40);
expect(result.height, 30);
@ -464,7 +463,7 @@ void testMain() async {
}
// Empty lines in the middle.
result = instance.measure(build(ahemStyle, '12\n\n345'), constraints);
result = instance.measure(build(ahemStyle, '12\n\n345'), constraints)!;
expect(result.maxIntrinsicWidth, 30);
expect(result.minIntrinsicWidth, 30);
expect(result.height, 30);
@ -481,7 +480,7 @@ void testMain() async {
}
// Empty lines in the end.
result = instance.measure(build(ahemStyle, '1234\n\n'), constraints);
result = instance.measure(build(ahemStyle, '1234\n\n'), constraints)!;
expect(result.maxIntrinsicWidth, 40);
expect(result.minIntrinsicWidth, 40);
if (instance.isCanvas) {
@ -504,7 +503,7 @@ void testMain() async {
(TextMeasurementService instance) {
final DomParagraph paragraph = build(ahemStyle, '123\n456 789');
final MeasurementResult result =
instance.measure(paragraph, infiniteConstraints);
instance.measure(paragraph, infiniteConstraints)!;
expect(result.isSingleLine, isFalse);
expect(result.maxIntrinsicWidth, 70);
@ -531,11 +530,11 @@ void testMain() async {
const ui.ParagraphConstraints constraints =
ui.ParagraphConstraints(width: 100);
final ui.TextStyle spacedTextStyle = ui.TextStyle(letterSpacing: 3);
final ui.Paragraph spacedText =
final DomParagraph spacedText =
build(ahemStyle, 'abc', textStyle: spacedTextStyle);
final MeasurementResult spacedResult =
instance.measure(spacedText, constraints);
instance.measure(spacedText, constraints)!;
expect(spacedResult.minIntrinsicWidth, 39);
expect(spacedResult.maxIntrinsicWidth, 39);
@ -556,9 +555,9 @@ void testMain() async {
expect(instance, const TypeMatcher<DomTextMeasurementService>());
final MeasurementResult normalResult =
instance.measure(normalText, constraints);
instance.measure(normalText, constraints)!;
final MeasurementResult spacedResult =
instance.measure(spacedText, constraints);
instance.measure(spacedText, constraints)!;
expect(
normalResult.maxIntrinsicWidth < spacedResult.maxIntrinsicWidth,
@ -570,7 +569,7 @@ void testMain() async {
MeasurementResult result;
// Simple case.
result = instance.measure(build(ahemStyle, 'abc de fghi'), constraints);
result = instance.measure(build(ahemStyle, 'abc de fghi'), constraints)!;
expect(result.minIntrinsicWidth, 40);
if (instance.isCanvas) {
expect(result.lines, <EngineLineMetrics>[
@ -585,7 +584,7 @@ void testMain() async {
}
// With new lines.
result = instance.measure(build(ahemStyle, 'abcd\nef\nghi'), constraints);
result = instance.measure(build(ahemStyle, 'abcd\nef\nghi'), constraints)!;
expect(result.minIntrinsicWidth, 40);
if (instance.isCanvas) {
expect(result.lines, <EngineLineMetrics>[
@ -600,7 +599,7 @@ void testMain() async {
}
// With trailing whitespace.
result = instance.measure(build(ahemStyle, 'abcd efg'), constraints);
result = instance.measure(build(ahemStyle, 'abcd efg'), constraints)!;
expect(result.minIntrinsicWidth, 40);
if (instance.isCanvas) {
expect(result.lines, <EngineLineMetrics>[
@ -614,7 +613,7 @@ void testMain() async {
}
// With trailing whitespace and new lines.
result = instance.measure(build(ahemStyle, 'abc \ndefg'), constraints);
result = instance.measure(build(ahemStyle, 'abc \ndefg'), constraints)!;
expect(result.minIntrinsicWidth, 40);
if (instance.isCanvas) {
expect(result.lines, <EngineLineMetrics>[
@ -628,7 +627,7 @@ void testMain() async {
}
// Very long text.
result = instance.measure(build(ahemStyle, 'AAAAAAAAAAAA'), constraints);
result = instance.measure(build(ahemStyle, 'AAAAAAAAAAAA'), constraints)!;
expect(result.minIntrinsicWidth, 120);
if (instance.isCanvas) {
expect(result.lines, <EngineLineMetrics>[
@ -647,7 +646,7 @@ void testMain() async {
MeasurementResult result;
// Simple case.
result = instance.measure(build(ahemStyle, 'abc de fghi'), constraints);
result = instance.measure(build(ahemStyle, 'abc de fghi'), constraints)!;
expect(result.maxIntrinsicWidth, 110);
if (instance.isCanvas) {
expect(result.lines, <EngineLineMetrics>[
@ -662,7 +661,7 @@ void testMain() async {
}
// With new lines.
result = instance.measure(build(ahemStyle, 'abcd\nef\nghi'), constraints);
result = instance.measure(build(ahemStyle, 'abcd\nef\nghi'), constraints)!;
expect(result.maxIntrinsicWidth, 40);
if (instance.isCanvas) {
expect(result.lines, <EngineLineMetrics>[
@ -677,7 +676,7 @@ void testMain() async {
}
// With long whitespace.
result = instance.measure(build(ahemStyle, 'abcd efg'), constraints);
result = instance.measure(build(ahemStyle, 'abcd efg'), constraints)!;
expect(result.maxIntrinsicWidth, 100);
if (instance.isCanvas) {
expect(result.lines, <EngineLineMetrics>[
@ -691,7 +690,7 @@ void testMain() async {
}
// With trailing whitespace.
result = instance.measure(build(ahemStyle, 'abc def '), constraints);
result = instance.measure(build(ahemStyle, 'abc def '), constraints)!;
expect(result.maxIntrinsicWidth, 100);
if (instance.isCanvas) {
expect(result.lines, <EngineLineMetrics>[
@ -705,7 +704,7 @@ void testMain() async {
}
// With trailing whitespace and new lines.
result = instance.measure(build(ahemStyle, 'abc \ndef '), constraints);
result = instance.measure(build(ahemStyle, 'abc \ndef '), constraints)!;
expect(result.maxIntrinsicWidth, 60);
if (instance.isCanvas) {
expect(result.lines, <EngineLineMetrics>[
@ -719,7 +718,7 @@ void testMain() async {
}
// Very long text.
result = instance.measure(build(ahemStyle, 'AAAAAAAAAAAA'), constraints);
result = instance.measure(build(ahemStyle, 'AAAAAAAAAAAA'), constraints)!;
expect(result.maxIntrinsicWidth, 120);
if (instance.isCanvas) {
expect(result.lines, <EngineLineMetrics>[
@ -747,11 +746,11 @@ void testMain() async {
// The text shouldn't be broken into multiple lines, so the height should
// be equal to a height of a single line.
final ui.Paragraph longText = build(
final DomParagraph longText = build(
overflowStyle,
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
);
result = instance.measure(longText, constraints);
result = instance.measure(longText, constraints)!;
expect(result.minIntrinsicWidth, 480);
expect(result.maxIntrinsicWidth, 480);
expect(result.height, 10);
@ -767,11 +766,11 @@ void testMain() async {
// The short prefix should make the text break into two lines, but the
// second line should remain unbroken.
final ui.Paragraph longTextShortPrefix = build(
final DomParagraph longTextShortPrefix = build(
overflowStyle,
'AAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
);
result = instance.measure(longTextShortPrefix, constraints);
result = instance.measure(longTextShortPrefix, constraints)!;
expect(result.minIntrinsicWidth, 450);
expect(result.maxIntrinsicWidth, 450);
expect(result.height, 20);
@ -789,8 +788,8 @@ void testMain() async {
// Tiny constraints.
const ui.ParagraphConstraints tinyConstraints =
ui.ParagraphConstraints(width: 30);
final ui.Paragraph text = build(overflowStyle, 'AAAA');
result = instance.measure(text, tinyConstraints);
final DomParagraph text = build(overflowStyle, 'AAAA');
result = instance.measure(text, tinyConstraints)!;
expect(result.minIntrinsicWidth, 40);
expect(result.maxIntrinsicWidth, 40);
expect(result.height, 10);
@ -807,7 +806,7 @@ void testMain() async {
// Tinier constraints (not enough for the ellipsis).
const ui.ParagraphConstraints tinierConstraints =
ui.ParagraphConstraints(width: 10);
result = instance.measure(text, tinierConstraints);
result = instance.measure(text, tinierConstraints)!;
expect(result.minIntrinsicWidth, 40);
expect(result.maxIntrinsicWidth, 40);
expect(result.height, 10);
@ -838,17 +837,17 @@ void testMain() async {
MeasurementResult result;
// The height should be that of a single line.
final ui.Paragraph oneline = build(maxlinesStyle, 'One line');
result = instance.measure(oneline, infiniteConstraints);
final DomParagraph oneline = build(maxlinesStyle, 'One line');
result = instance.measure(oneline, infiniteConstraints)!;
expect(result.height, 10);
expect(result.lines, <EngineLineMetrics>[
line('One line', 0, 8, hardBreak: true, width: 80.0, lineNumber: 0, left: 0.0),
]);
// The height should respect max lines and be limited to two lines here.
final ui.Paragraph threelines =
final DomParagraph threelines =
build(maxlinesStyle, 'First\nSecond\nThird');
result = instance.measure(threelines, infiniteConstraints);
result = instance.measure(threelines, infiniteConstraints)!;
expect(result.height, 20);
if (instance.isCanvas) {
expect(result.lines, <EngineLineMetrics>[
@ -862,11 +861,11 @@ void testMain() async {
}
// The height should respect max lines and be limited to two lines here.
final ui.Paragraph veryLong = build(
final DomParagraph veryLong = build(
maxlinesStyle,
'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
);
result = instance.measure(veryLong, constraints);
result = instance.measure(veryLong, constraints)!;
expect(result.height, 20);
if (instance.isCanvas) {
expect(result.lines, <EngineLineMetrics>[
@ -880,11 +879,11 @@ void testMain() async {
}
// Case when last line is a long unbreakable word.
final ui.Paragraph veryLongLastLine = build(
final DomParagraph veryLongLastLine = build(
maxlinesStyle,
'AAA AAAAAAAAAAAAAAAAAAA',
);
result = instance.measure(veryLongLastLine, constraints);
result = instance.measure(veryLongLastLine, constraints)!;
expect(result.height, 20);
if (instance.isCanvas) {
expect(result.lines, <EngineLineMetrics>[
@ -916,12 +915,12 @@ void testMain() async {
ellipsis: '...',
);
ui.Paragraph p;
DomParagraph p;
MeasurementResult result;
// Simple no overflow case.
p = build(onelineStyle, 'abcdef');
result = instance.measure(p, constraints);
result = instance.measure(p, constraints)!;
expect(result.height, 10);
expect(result.lines, <EngineLineMetrics>[
line('abcdef', 0, 6, hardBreak: true, width: 60.0, lineNumber: 0, left: 0.0),
@ -929,7 +928,7 @@ void testMain() async {
// Simple overflow case.
p = build(onelineStyle, 'abcd efg');
result = instance.measure(p, constraints);
result = instance.measure(p, constraints)!;
expect(result.height, 10);
if (instance.isCanvas) {
expect(result.lines, <EngineLineMetrics>[
@ -943,7 +942,7 @@ void testMain() async {
// Another simple overflow case.
p = build(onelineStyle, 'a bcde fgh');
result = instance.measure(p, constraints);
result = instance.measure(p, constraints)!;
expect(result.height, 10);
if (instance.isCanvas) {
expect(result.lines, <EngineLineMetrics>[
@ -958,7 +957,7 @@ void testMain() async {
// The ellipsis is supposed to go on the second line, but because the
// 2nd line doesn't overflow, no ellipsis is shown.
p = build(multilineStyle, 'abcdef ghijkl');
result = instance.measure(p, constraints);
result = instance.measure(p, constraints)!;
// This can only be done correctly in the canvas-based implementation.
if (instance.isCanvas) {
expect(result.height, 20);
@ -975,7 +974,7 @@ void testMain() async {
// But when the 2nd line is long enough, the ellipsis is shown.
p = build(multilineStyle, 'abcd efghijkl');
result = instance.measure(p, constraints);
result = instance.measure(p, constraints)!;
// This can only be done correctly in the canvas-based implementation.
if (instance.isCanvas) {
expect(result.height, 20);
@ -993,7 +992,7 @@ void testMain() async {
// Even if the second line can be broken, we don't break it, we just
// insert the ellipsis.
p = build(multilineStyle, 'abcde f gh ijk');
result = instance.measure(p, constraints);
result = instance.measure(p, constraints)!;
// This can only be done correctly in the canvas-based implementation.
if (instance.isCanvas) {
expect(result.height, 20);
@ -1010,7 +1009,7 @@ void testMain() async {
// First line overflows but second line doesn't.
p = build(multilineStyle, 'abcdefg hijk');
result = instance.measure(p, constraints);
result = instance.measure(p, constraints)!;
// This can only be done correctly in the canvas-based implementation.
if (instance.isCanvas) {
expect(result.height, 20);
@ -1027,7 +1026,7 @@ void testMain() async {
// Both first and second lines overflow.
p = build(multilineStyle, 'abcdefg hijklmnop');
result = instance.measure(p, constraints);
result = instance.measure(p, constraints)!;
// This can only be done correctly in the canvas-based implementation.
if (instance.isCanvas) {
expect(result.height, 20);
@ -1046,7 +1045,7 @@ void testMain() async {
test('handles textAlign', () {
TextMeasurementService instance = TextMeasurementService.canvasInstance;
ui.Paragraph p;
DomParagraph p;
MeasurementResult result;
ui.ParagraphStyle createStyle(ui.TextAlign textAlign) {
@ -1059,7 +1058,7 @@ void testMain() async {
}
p = build(createStyle(ui.TextAlign.start), 'abc\ndefghi');
result = instance.measure(p, constraints);
result = instance.measure(p, constraints)!;
expect(result.lines, <EngineLineMetrics>[
line('abc', 0, 4, hardBreak: true, width: 30.0, lineNumber: 0, left: 0.0),
line('defgh', 4, 9, hardBreak: false, width: 50.0, lineNumber: 1, left: 0.0),
@ -1067,7 +1066,7 @@ void testMain() async {
]);
p = build(createStyle(ui.TextAlign.end), 'abc\ndefghi');
result = instance.measure(p, constraints);
result = instance.measure(p, constraints)!;
expect(result.lines, <EngineLineMetrics>[
line('abc', 0, 4, hardBreak: true, width: 30.0, lineNumber: 0, left: 20.0),
line('defgh', 4, 9, hardBreak: false, width: 50.0, lineNumber: 1, left: 0.0),
@ -1075,7 +1074,7 @@ void testMain() async {
]);
p = build(createStyle(ui.TextAlign.center), 'abc\ndefghi');
result = instance.measure(p, constraints);
result = instance.measure(p, constraints)!;
expect(result.lines, <EngineLineMetrics>[
line('abc', 0, 4, hardBreak: true, width: 30.0, lineNumber: 0, left: 10.0),
line('defgh', 4, 9, hardBreak: false, width: 50.0, lineNumber: 1, left: 0.0),
@ -1083,7 +1082,7 @@ void testMain() async {
]);
p = build(createStyle(ui.TextAlign.left), 'abc\ndefghi');
result = instance.measure(p, constraints);
result = instance.measure(p, constraints)!;
expect(result.lines, <EngineLineMetrics>[
line('abc', 0, 4, hardBreak: true, width: 30.0, lineNumber: 0, left: 0.0),
line('defgh', 4, 9, hardBreak: false, width: 50.0, lineNumber: 1, left: 0.0),
@ -1091,7 +1090,7 @@ void testMain() async {
]);
p = build(createStyle(ui.TextAlign.right), 'abc\ndefghi');
result = instance.measure(p, constraints);
result = instance.measure(p, constraints)!;
expect(result.lines, <EngineLineMetrics>[
line('abc', 0, 4, hardBreak: true, width: 30.0, lineNumber: 0, left: 20.0),
line('defgh', 4, 9, hardBreak: false, width: 50.0, lineNumber: 1, left: 0.0),
@ -1103,7 +1102,7 @@ void testMain() async {
'handles rtl with textAlign',
(TextMeasurementService instance) {
TextMeasurementService instance = TextMeasurementService.canvasInstance;
ui.Paragraph p;
DomParagraph p;
MeasurementResult result;
ui.ParagraphStyle createStyle(ui.TextAlign textAlign) {
@ -1116,7 +1115,7 @@ void testMain() async {
}
p = build(createStyle(ui.TextAlign.start), 'abc\ndefghi');
result = instance.measure(p, constraints);
result = instance.measure(p, constraints)!;
expect(result.lines, <EngineLineMetrics>[
line('abc', 0, 4, hardBreak: true, width: 30.0, lineNumber: 0, left: 20.0),
line('defgh', 4, 9, hardBreak: false, width: 50.0, lineNumber: 1, left: 0.0),
@ -1124,7 +1123,7 @@ void testMain() async {
]);
p = build(createStyle(ui.TextAlign.end), 'abc\ndefghi');
result = instance.measure(p, constraints);
result = instance.measure(p, constraints)!;
expect(result.lines, <EngineLineMetrics>[
line('abc', 0, 4, hardBreak: true, width: 30.0, lineNumber: 0, left: 0.0),
line('defgh', 4, 9, hardBreak: false, width: 50.0, lineNumber: 1, left: 0.0),
@ -1132,7 +1131,7 @@ void testMain() async {
]);
p = build(createStyle(ui.TextAlign.center), 'abc\ndefghi');
result = instance.measure(p, constraints);
result = instance.measure(p, constraints)!;
expect(result.lines, <EngineLineMetrics>[
line('abc', 0, 4, hardBreak: true, width: 30.0, lineNumber: 0, left: 10.0),
line('defgh', 4, 9, hardBreak: false, width: 50.0, lineNumber: 1, left: 0.0),
@ -1140,7 +1139,7 @@ void testMain() async {
]);
p = build(createStyle(ui.TextAlign.left), 'abc\ndefghi');
result = instance.measure(p, constraints);
result = instance.measure(p, constraints)!;
expect(result.lines, <EngineLineMetrics>[
line('abc', 0, 4, hardBreak: true, width: 30.0, lineNumber: 0, left: 0.0),
line('defgh', 4, 9, hardBreak: false, width: 50.0, lineNumber: 1, left: 0.0),
@ -1148,7 +1147,7 @@ void testMain() async {
]);
p = build(createStyle(ui.TextAlign.right), 'abc\ndefghi');
result = instance.measure(p, constraints);
result = instance.measure(p, constraints)!;
expect(result.lines, <EngineLineMetrics>[
line('abc', 0, 4, hardBreak: true, width: 30.0, lineNumber: 0, left: 20.0),
line('defgh', 4, 9, hardBreak: false, width: 50.0, lineNumber: 1, left: 0.0),
@ -1164,10 +1163,10 @@ EngineLineMetrics line(
String displayText,
int startIndex,
int endIndex, {
double width,
int lineNumber,
bool hardBreak,
double left,
required double width,
required int lineNumber,
required bool hardBreak,
required double left,
}) {
return EngineLineMetrics.withText(
displayText,

View File

@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.6
import 'package:test/bootstrap/browser.dart';
import 'package:test/test.dart';

View File

@ -2,7 +2,6 @@
// 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:html';
import 'package:test/bootstrap/browser.dart';
@ -22,7 +21,7 @@ void testMain() async {
await webOnlyInitializeTestDomRenderer();
String fallback;
late String fallback;
setUp(() {
if (operatingSystem == OperatingSystem.macOs ||
operatingSystem == OperatingSystem.iOs) {
@ -89,14 +88,14 @@ void testMain() async {
});
test('lay out unattached paragraph', () {
final DomParagraphBuilder builder = DomParagraphBuilder(ParagraphStyle(
final DomParagraphBuilder builder = DomParagraphBuilder(EngineParagraphStyle(
fontFamily: 'sans-serif',
fontStyle: FontStyle.normal,
fontWeight: FontWeight.normal,
fontSize: 14.0,
));
builder.addText('How do you do this fine morning?');
final DomParagraph paragraph = builder.build();
final DomParagraph paragraph = builder.build() as DomParagraph;
expect(paragraph.paragraphElement.parent, isNull);
expect(paragraph.height, 0.0);
@ -155,18 +154,18 @@ void testMain() async {
});
test('$ParagraphBuilder detects plain text', () {
DomParagraphBuilder builder = DomParagraphBuilder(ParagraphStyle(
DomParagraphBuilder builder = DomParagraphBuilder(EngineParagraphStyle(
fontFamily: 'sans-serif',
fontStyle: FontStyle.normal,
fontWeight: FontWeight.normal,
fontSize: 15.0,
));
builder.addText('hi');
DomParagraph paragraph = builder.build();
DomParagraph paragraph = builder.build() as DomParagraph;
expect(paragraph.plainText, isNotNull);
expect(paragraph.geometricStyle.fontWeight, FontWeight.normal);
builder = DomParagraphBuilder(ParagraphStyle(
builder = DomParagraphBuilder(EngineParagraphStyle(
fontFamily: 'sans-serif',
fontStyle: FontStyle.normal,
fontWeight: FontWeight.normal,
@ -174,13 +173,13 @@ void testMain() async {
));
builder.pushStyle(TextStyle(fontWeight: FontWeight.bold));
builder.addText('hi');
paragraph = builder.build();
paragraph = builder.build() as DomParagraph;
expect(paragraph.plainText, isNotNull);
expect(paragraph.geometricStyle.fontWeight, FontWeight.bold);
});
test('$ParagraphBuilder detects rich text', () {
final DomParagraphBuilder builder = DomParagraphBuilder(ParagraphStyle(
final DomParagraphBuilder builder = DomParagraphBuilder(EngineParagraphStyle(
fontFamily: 'sans-serif',
fontStyle: FontStyle.normal,
fontWeight: FontWeight.normal,
@ -189,27 +188,27 @@ void testMain() async {
builder.addText('h');
builder.pushStyle(TextStyle(fontWeight: FontWeight.bold));
builder.addText('i');
final DomParagraph paragraph = builder.build();
final DomParagraph paragraph = builder.build() as DomParagraph;
expect(paragraph.plainText, isNull);
expect(paragraph.geometricStyle.fontWeight, FontWeight.normal);
});
test('$ParagraphBuilder treats empty text as plain', () {
final DomParagraphBuilder builder = DomParagraphBuilder(ParagraphStyle(
final DomParagraphBuilder builder = DomParagraphBuilder(EngineParagraphStyle(
fontFamily: 'sans-serif',
fontStyle: FontStyle.normal,
fontWeight: FontWeight.normal,
fontSize: 15.0,
));
builder.pushStyle(TextStyle(fontWeight: FontWeight.bold));
final DomParagraph paragraph = builder.build();
final DomParagraph paragraph = builder.build() as DomParagraph;
expect(paragraph.plainText, '');
expect(paragraph.geometricStyle.fontWeight, FontWeight.bold);
});
// Regression test for https://github.com/flutter/flutter/issues/34931.
test('hit test on styled text returns correct span offset', () {
final DomParagraphBuilder builder = DomParagraphBuilder(ParagraphStyle(
final DomParagraphBuilder builder = DomParagraphBuilder(EngineParagraphStyle(
fontFamily: 'sans-serif',
fontStyle: FontStyle.normal,
fontWeight: FontWeight.normal,
@ -223,7 +222,7 @@ void testMain() async {
builder.addText(secondSpanText);
builder.pushStyle(TextStyle(fontStyle: FontStyle.italic));
builder.addText('followed by a link');
final DomParagraph paragraph = builder.build();
final DomParagraph paragraph = builder.build() as DomParagraph;
paragraph.layout(const ParagraphConstraints(width: 800.0));
expect(paragraph.plainText, isNull);
const int secondSpanStartPosition = firstSpanText.length;
@ -239,7 +238,7 @@ void testMain() async {
const fontFamily = 'sans-serif';
const fontSize = 20.0;
final style = TextStyle(fontFamily: fontFamily, fontSize: fontSize);
final DomParagraphBuilder builder = DomParagraphBuilder(ParagraphStyle(
final DomParagraphBuilder builder = DomParagraphBuilder(EngineParagraphStyle(
fontFamily: fontFamily,
fontSize: fontSize,
));
@ -326,7 +325,7 @@ void testMain() async {
'test te04 test050 '
*/
final DomParagraph paragraph = builder.build();
final DomParagraph paragraph = builder.build() as DomParagraph;
paragraph.layout(ParagraphConstraints(width: 800));
// Reference the offsets with the output of `Display arrangement`.
@ -358,7 +357,7 @@ void testMain() async {
test(
'should not set fontFamily to effectiveFontFamily for spans in rich text',
() {
final DomParagraphBuilder builder = DomParagraphBuilder(ParagraphStyle(
final DomParagraphBuilder builder = DomParagraphBuilder(EngineParagraphStyle(
fontFamily: 'Roboto',
fontStyle: FontStyle.normal,
fontWeight: FontWeight.normal,
@ -371,7 +370,7 @@ void testMain() async {
builder.pushStyle(TextStyle(fontSize: 30.0, fontWeight: FontWeight.normal));
const String secondSpanText = 'def';
builder.addText(secondSpanText);
final DomParagraph paragraph = builder.build();
final DomParagraph paragraph = builder.build() as DomParagraph;
paragraph.layout(const ParagraphConstraints(width: 800.0));
expect(paragraph.plainText, isNull);
final List<SpanElement> spans =
@ -389,14 +388,14 @@ void testMain() async {
// Set this to false so it doesn't default to 'Ahem' font.
debugEmulateFlutterTesterEnvironment = false;
final DomParagraphBuilder builder = DomParagraphBuilder(ParagraphStyle(
final DomParagraphBuilder builder = DomParagraphBuilder(EngineParagraphStyle(
fontFamily: 'SomeFont',
fontSize: 12.0,
));
builder.addText('Hello');
final DomParagraph paragraph = builder.build();
final DomParagraph paragraph = builder.build() as DomParagraph;
expect(paragraph.paragraphElement.style.fontFamily,
'SomeFont, $fallback, sans-serif');
@ -411,14 +410,14 @@ void testMain() async {
// Set this to false so it doesn't default to 'Ahem' font.
debugEmulateFlutterTesterEnvironment = false;
final DomParagraphBuilder builder = DomParagraphBuilder(ParagraphStyle(
final DomParagraphBuilder builder = DomParagraphBuilder(EngineParagraphStyle(
fontFamily: 'serif',
fontSize: 12.0,
));
builder.addText('Hello');
final DomParagraph paragraph = builder.build();
final DomParagraph paragraph = builder.build() as DomParagraph;
expect(paragraph.paragraphElement.style.fontFamily, 'serif');
debugEmulateFlutterTesterEnvironment = true;
@ -428,14 +427,14 @@ void testMain() async {
// Set this to false so it doesn't default to 'Ahem' font.
debugEmulateFlutterTesterEnvironment = false;
final DomParagraphBuilder builder = DomParagraphBuilder(ParagraphStyle(
final DomParagraphBuilder builder = DomParagraphBuilder(EngineParagraphStyle(
fontFamily: 'MyFont 2000',
fontSize: 12.0,
));
builder.addText('Hello');
final DomParagraph paragraph = builder.build();
final DomParagraph paragraph = builder.build() as DomParagraph;
expect(paragraph.paragraphElement.style.fontFamily,
'"MyFont 2000", $fallback, sans-serif');

View File

@ -2,7 +2,6 @@
// 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:io';
import 'package:args/args.dart';
@ -129,8 +128,8 @@ void main(List<String> arguments) async {
}
PropertiesSyncer getSyncer(
String wordBreakProperties,
String lineBreakProperties,
String? wordBreakProperties,
String? lineBreakProperties,
bool dry,
) {
if (wordBreakProperties == null && lineBreakProperties == null) {
@ -151,8 +150,8 @@ PropertiesSyncer getSyncer(
: WordBreakPropertiesSyncer(wordBreakProperties, '$wordBreakCodegen');
} else {
return dry
? LineBreakPropertiesSyncer.dry(lineBreakProperties)
: LineBreakPropertiesSyncer(lineBreakProperties, '$lineBreakCodegen');
? LineBreakPropertiesSyncer.dry(lineBreakProperties!)
: LineBreakPropertiesSyncer(lineBreakProperties!, '$lineBreakCodegen');
}
}
@ -168,7 +167,7 @@ abstract class PropertiesSyncer {
_dryRun = true;
final String _src;
final String _dest;
final String? _dest;
final bool _dryRun;
String get prefix;
@ -189,7 +188,7 @@ abstract class PropertiesSyncer {
if (_dryRun) {
print(output);
} else {
final IOSink sink = File(_dest).openWrite();
final IOSink sink = File(_dest!).openWrite();
sink.write(output);
}
}
@ -305,17 +304,17 @@ class PropertyCollection {
.map(parseLineIntoUnicodeRange)
.toList();
// Insert the default property if it doesn't exist.
final EnumValue found = enumCollection.values.firstWhere(
(property) => property.name == defaultProperty,
final EnumValue? found = enumCollection.values.cast<EnumValue?>().firstWhere(
(property) => property!.name == defaultProperty,
orElse: () => null,
);
if (found == null) {
enumCollection.add(defaultProperty);
}
ranges = processRanges(unprocessedRanges, defaultProperty);
ranges = processRanges(unprocessedRanges, defaultProperty).toList();
}
List<UnicodeRange> ranges;
late List<UnicodeRange> ranges;
final EnumCollection enumCollection = EnumCollection();
@ -336,7 +335,7 @@ class PropertyCollection {
final String propertyStr = split[1].trim();
final EnumValue property = normalizationTable.containsKey(propertyStr)
? enumCollection.add(normalizationTable[propertyStr], propertyStr)
? enumCollection.add(normalizationTable[propertyStr]!, propertyStr)
: enumCollection.add(propertyStr);
return UnicodeRange(
@ -351,7 +350,7 @@ class PropertyCollection {
class EnumCollection {
final List<EnumValue> values = <EnumValue>[];
EnumValue add(String name, [String normalizedFrom]) {
EnumValue add(String name, [String? normalizedFrom]) {
final int index =
values.indexWhere((EnumValue value) => value.name == name);
EnumValue value;