mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
[web] last batch of test null safety (flutter/engine#26719)
This commit is contained in:
parent
09f69b628b
commit
347bd4f98d
@ -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.
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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',
|
||||
|
||||
@ -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(
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -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),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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',
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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';
|
||||
|
||||
|
||||
@ -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');
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user