diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 809ebb4c30865..1ce2fc4a14c7f 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -2061,7 +2061,6 @@ ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/text_editing/input_action.dar ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/text_editing/input_type.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/text_editing/text_capitalization.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/text_editing/text_editing.dart + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/ulps.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/util.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/validators.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/vector_math.dart + ../../../flutter/LICENSE @@ -4543,7 +4542,6 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/text_editing/input_action.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/text_editing/input_type.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/text_editing/text_capitalization.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/text_editing/text_editing.dart -FILE: ../../../flutter/lib/web_ui/lib/src/engine/ulps.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/util.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/validators.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/vector_math.dart diff --git a/lib/web_ui/dev/browser_lock.yaml b/lib/web_ui/dev/browser_lock.yaml index f5be6b4352c12..4fcdc81b654c1 100644 --- a/lib/web_ui/dev/browser_lock.yaml +++ b/lib/web_ui/dev/browser_lock.yaml @@ -13,11 +13,11 @@ chrome: # `self.m.platform.name.capitalize()` evaluates to. See: # # recipe_modules/web_util/api.py - Linux: 1047731 - Mac: 1047732 - Mac_Arm: 1047734 - Win: 1047731 - version: '107.0' # CIPD tag for the above Build IDs. Normally "ChromeMajorVersion.UploadAttempt". ;) + Linux: 1084013 + Mac: 1084013 + Mac_Arm: 1084001 + Win: 1084062 + version: '110.0' # CIPD tag for the above Build IDs. Normally "ChromeMajorVersion.UploadAttempt". ;) firefox: version: '106.0' diff --git a/lib/web_ui/dev/chrome.dart b/lib/web_ui/dev/chrome.dart index 8bae9250d4ccf..1167ce2bff0d8 100644 --- a/lib/web_ui/dev/chrome.dart +++ b/lib/web_ui/dev/chrome.dart @@ -101,6 +101,8 @@ class Chrome extends Browser { '--start-maximized', if (debug) '--auto-open-devtools-for-tabs', + // Always run unit tests at a 1x scale factor + '--force-device-scale-factor=1', '--disable-extensions', '--disable-popup-blocking', // Indicates that the browser is in "browse without sign-in" (Guest session) mode. diff --git a/lib/web_ui/dev/felt b/lib/web_ui/dev/felt index a798640673a7d..3d4dc7080f3f8 100755 --- a/lib/web_ui/dev/felt +++ b/lib/web_ui/dev/felt @@ -30,7 +30,7 @@ ENGINE_SRC_DIR="$(dirname $(dirname $(dirname $(dirname ${FELT_DIR}))))" FLUTTER_DIR="${ENGINE_SRC_DIR}/flutter" SDK_PREBUILTS_DIR="${FLUTTER_DIR}/prebuilts" -if [ -z "${DART_SDK_DIR}"] +if [ -z "${DART_SDK_DIR}" ] then if [[ $KERNEL_NAME == *"Darwin"* ]] then diff --git a/lib/web_ui/dev/steps/compile_tests_step.dart b/lib/web_ui/dev/steps/compile_tests_step.dart index 540a6379a4041..7ef4ce5884f4d 100644 --- a/lib/web_ui/dev/steps/compile_tests_step.dart +++ b/lib/web_ui/dev/steps/compile_tests_step.dart @@ -345,6 +345,7 @@ Future compileUnitTestToWasm(FilePath input, {required Renderer renderer}) environment.dart2wasmSnapshotPath, '--dart-sdk=${environment.dartSdkDir.path}', + '--enable-asserts', // We do not want to auto-select a renderer in tests. As of today, tests // are designed to run in one specific mode. So instead, we specify the diff --git a/lib/web_ui/dev/steps/run_tests_step.dart b/lib/web_ui/dev/steps/run_tests_step.dart index b6d51154c7f27..a30f1fce51ab2 100644 --- a/lib/web_ui/dev/steps/run_tests_step.dart +++ b/lib/web_ui/dev/steps/run_tests_step.dart @@ -132,7 +132,10 @@ class RunTestsStep implements PipelineStep { Future _createSkiaClient() async { final SkiaGoldClient skiaClient = SkiaGoldClient( environment.webUiSkiaGoldDirectory, - dimensions: {'Browser': browserName}, + dimensions: { + 'Browser': browserName, + if (isWasm) 'Wasm': 'true', + }, ); if (await _checkSkiaClient(skiaClient)) { diff --git a/lib/web_ui/lib/src/engine/browser_detection.dart b/lib/web_ui/lib/src/engine/browser_detection.dart index dffd8bf23fce0..6cafa6e387e0a 100644 --- a/lib/web_ui/lib/src/engine/browser_detection.dart +++ b/lib/web_ui/lib/src/engine/browser_detection.dart @@ -226,6 +226,11 @@ bool get isFirefox => browserEngine == BrowserEngine.firefox; /// Whether the current browser is Edge. bool get isEdge => domWindow.navigator.userAgent.contains('Edg/'); +/// Whether we are running from a wasm module compiled with dart2wasm. +/// Note: Currently the ffi library is available from dart2wasm but not dart2js +/// or dartdevc. +bool get isWasm => const bool.fromEnvironment('dart.library.ffi'); + /// Use in tests to simulate the detection of iOS 15. bool? debugIsIOS15; diff --git a/lib/web_ui/lib/src/engine/canvaskit/canvas.dart b/lib/web_ui/lib/src/engine/canvaskit/canvas.dart index e3c358e45f044..3d35df90b4c41 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/canvas.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/canvas.dart @@ -118,7 +118,7 @@ class CkCanvas { void drawColor(ui.Color color, ui.BlendMode blendMode) { skCanvas.drawColorInt( - color.value, + color.value.toDouble(), toSkBlendMode(blendMode), ); } @@ -266,7 +266,7 @@ class CkCanvas { } void restoreToCount(int count) { - skCanvas.restoreToCount(count); + skCanvas.restoreToCount(count.toDouble()); } void rotate(double radians) { @@ -654,7 +654,7 @@ class CkRestoreToCountCommand extends CkPaintCommand { @override void apply(SkCanvas canvas) { - canvas.restoreToCount(count); + canvas.restoreToCount(count.toDouble()); } } @@ -821,7 +821,7 @@ class CkDrawColorCommand extends CkPaintCommand { @override void apply(SkCanvas canvas) { canvas.drawColorInt( - color.value, + color.value.toDouble(), toSkBlendMode(blendMode), ); } diff --git a/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart b/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart index cb429bc7c512f..4ceb777104114 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart @@ -88,8 +88,8 @@ extension CanvasKitExtension on CanvasKit { external SkTextStyle TextStyle(SkTextStyleProperties properties); external SkSurface MakeWebGLCanvasSurface(DomCanvasElement canvas); external SkSurface MakeSurface( - int width, - int height, + double width, + double height, ); external Uint8List getDataBytes( SkData skData, @@ -111,11 +111,11 @@ extension CanvasKitExtension on CanvasKit { external SkTypefaceFactory get Typeface; external double GetWebGLContext( DomCanvasElement canvas, SkWebGLContextOptions options); - external SkGrContext MakeGrContext(int glContext); + external SkGrContext MakeGrContext(double glContext); external SkSurface? MakeOnScreenGLSurface( SkGrContext grContext, - int width, - int height, + double width, + double height, ColorSpace colorSpace, int sampleCount, int stencil, @@ -132,7 +132,7 @@ extension CanvasKitExtension on CanvasKit { external SkImage? MakeImage( SkImageInfo info, Uint8List pixels, - int bytesPerRow, + double bytesPerRow, ); external SkImage? MakeLazyImageFromTextureSource( Object src, @@ -194,7 +194,7 @@ extension SkSurfaceExtension on SkSurface { class SkGrContext {} extension SkGrContextExtension on SkGrContext { - external void setResourceCacheLimitBytes(int limit); + external void setResourceCacheLimitBytes(double limit); external void releaseResourcesAndAbandonContext(); external void delete(); } @@ -952,7 +952,7 @@ extension SkImageExtension on SkImage { SkMipmapMode mipmapMode, Float32List? matrix, // 3x3 matrix ); - external Uint8List readPixels(int srcX, int srcY, SkImageInfo imageInfo); + external Uint8List readPixels(double srcX, double srcY, SkImageInfo imageInfo); external Uint8List? encodeToBytes(); external bool isAliasOf(SkImage other); external bool isDeleted(); @@ -979,7 +979,7 @@ extension SkShaderNamespaceExtension on SkShaderNamespace { Float32List colorStops, SkTileMode tileMode, Float32List? matrix, // 3x3 matrix - int flags, + double flags, ); external SkShader MakeTwoPointConicalGradient( @@ -991,7 +991,7 @@ extension SkShaderNamespaceExtension on SkShaderNamespace { Float32List colorStops, SkTileMode tileMode, Float32List? matrix, // 3x3 matrix - int flags, + double flags, ); external SkShader MakeSweepGradient( @@ -1001,7 +1001,7 @@ extension SkShaderNamespaceExtension on SkShaderNamespace { Float32List colorStops, SkTileMode tileMode, Float32List? matrix, // 3x3 matrix - int flags, + double flags, double startAngle, double endAngle, ); @@ -1045,7 +1045,7 @@ extension SkPaintExtension on SkPaint { external void setStrokeCap(SkStrokeCap cap); external void setStrokeJoin(SkStrokeJoin join); external void setAntiAlias(bool isAntiAlias); - external void setColorInt(int color); + external void setColorInt(double color); external void setShader(SkShader? shader); external void setMaskFilter(SkMaskFilter? maskFilter); external void setColorFilter(SkColorFilter? colorFilter); @@ -1272,14 +1272,14 @@ external _NativeType get _nativeFloat32ArrayType; external _NativeType get _nativeUint32ArrayType; @JS('window.flutterCanvasKit.Malloc') -external Object _malloc(_NativeType nativeType, int length); +external Object _malloc(_NativeType nativeType, double length); /// Allocates a [Float32List] of [length] elements, backed by WASM memory, /// managed by a [SkFloat32List]. /// /// To free the allocated array use [free]. SkFloat32List mallocFloat32List(int length) { - return _malloc(_nativeFloat32ArrayType, length) as SkFloat32List; + return _malloc(_nativeFloat32ArrayType, length.toDouble()) as SkFloat32List; } /// Allocates a [Uint32List] of [length] elements, backed by WASM memory, @@ -1287,7 +1287,7 @@ SkFloat32List mallocFloat32List(int length) { /// /// To free the allocated array use [free]. SkUint32List mallocUint32List(int length) { - return _malloc(_nativeUint32ArrayType, length) as SkUint32List; + return _malloc(_nativeUint32ArrayType, length.toDouble()) as SkUint32List; } /// Frees the WASM memory occupied by a [SkFloat32List] or [SkUint32List]. @@ -1313,7 +1313,7 @@ class SkFloat32List extends MallocObj {} extension SkFloat32ListExtension on SkFloat32List { /// The number of objects this pointer refers to. - external int length; + external double length; /// Returns the [Float32List] object backed by WASM memory. /// @@ -1336,7 +1336,7 @@ class SkUint32List extends MallocObj {} extension SkUint32ListExtension on SkUint32List { /// The number of objects this pointer refers to. - external int length; + external double length; /// Returns the [Uint32List] object backed by WASM memory. /// @@ -1408,7 +1408,7 @@ extension SkPathExtension on SkPath { external void addOval( Float32List oval, bool counterClockWise, - int startIndex, + double startIndex, ); external void addPath( SkPath other, @@ -1721,7 +1721,7 @@ extension SkCanvasExtension on SkCanvas { SkPaint paint, ); external void drawColorInt( - int color, + double color, SkBlendMode blendMode, ); external void drawDRRect( @@ -1806,7 +1806,7 @@ extension SkCanvasExtension on SkCanvas { double lightRadius, Float32List ambientColor, Float32List spotColor, - int flags, + double flags, ); external void drawVertices( SkVertices vertices, @@ -1822,7 +1822,7 @@ extension SkCanvasExtension on SkCanvas { int? flags, ); external void restore(); - external void restoreToCount(int count); + external void restoreToCount(double count); external void rotate( double angleDegrees, double px, @@ -2126,7 +2126,7 @@ extension SkFontExtension on SkFont { class SkFontMgr {} extension SkFontMgrExtension on SkFontMgr { - external String? getFamilyName(int fontId); + external String? getFamilyName(double fontId); external void delete(); external SkTypeface? MakeTypefaceFromData(Uint8List font); } @@ -2187,8 +2187,8 @@ extension SkParagraphExtension on SkParagraph { external double getMinIntrinsicWidth(); external double getMaxWidth(); external /* List */ List getRectsForRange( - int start, - int end, + double start, + double end, SkRectHeightStyle heightStyle, SkRectWidthStyle widthStyle, ); @@ -2197,7 +2197,7 @@ extension SkParagraphExtension on SkParagraph { double x, double y, ); - external SkTextRange getWordBoundary(int position); + external SkTextRange getWordBoundary(double position); external void layout(double width); external void delete(); } @@ -2523,8 +2523,8 @@ extension SkDataExtension on SkData { @staticInterop class SkImageInfo { external factory SkImageInfo({ - required int width, - required int height, + required double width, + required double height, required SkColorType colorType, required SkAlphaType alphaType, required ColorSpace colorSpace, @@ -2543,7 +2543,7 @@ extension SkImageInfoExtension on SkImageInfo { external SkImageInfo makeAlphaType(SkAlphaType alphaType); external SkImageInfo makeColorSpace(ColorSpace colorSpace); external SkImageInfo makeColorType(SkColorType colorType); - external SkImageInfo makeWH(int width, int height); + external SkImageInfo makeWH(double width, double height); } @JS() @@ -2551,8 +2551,8 @@ extension SkImageInfoExtension on SkImageInfo { @staticInterop class SkPartialImageInfo { external factory SkPartialImageInfo({ - required int width, - required int height, + required double width, + required double height, required SkColorType colorType, required SkAlphaType alphaType, required ColorSpace colorSpace, diff --git a/lib/web_ui/lib/src/engine/canvaskit/image.dart b/lib/web_ui/lib/src/engine/canvaskit/image.dart index 0aec743b3ae86..45007a3e4ce85 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/image.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/image.dart @@ -57,14 +57,14 @@ void skiaDecodeImageFromPixels( Timer.run(() { final SkImage? skImage = canvasKit.MakeImage( SkImageInfo( - width: width, - height: height, + width: width.toDouble(), + height: height.toDouble(), colorType: format == ui.PixelFormat.rgba8888 ? canvasKit.ColorType.RGBA_8888 : canvasKit.ColorType.BGRA_8888, alphaType: canvasKit.AlphaType.Premul, colorSpace: SkColorSpaceSRGB, ), pixels, - rowBytes ?? 4 * width, + (rowBytes ?? 4 * width).toDouble(), ); if (skImage == null) { @@ -266,11 +266,11 @@ class CkImage implements ui.Image, StackTraceDebugger { alphaType: canvasKit.AlphaType.Premul, colorType: canvasKit.ColorType.RGBA_8888, colorSpace: SkColorSpaceSRGB, - width: originalWidth, - height: originalHeight, + width: originalWidth.toDouble(), + height: originalHeight.toDouble(), ), originalBytes.buffer.asUint8List(), - 4 * originalWidth, + (4 * originalWidth).toDouble(), ); if (skImage == null) { throw ImageCodecException( @@ -415,8 +415,8 @@ class CkImage implements ui.Image, StackTraceDebugger { alphaType: alphaType, colorType: colorType, colorSpace: colorSpace, - width: skImage.width().toInt(), - height: skImage.height().toInt(), + width: skImage.width(), + height: skImage.height(), ); bytes = skImage.readPixels(0, 0, imageInfo); } else { diff --git a/lib/web_ui/lib/src/engine/canvaskit/image_web_codecs.dart b/lib/web_ui/lib/src/engine/canvaskit/image_web_codecs.dart index 89d954900e7eb..1783f624f4713 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/image_web_codecs.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/image_web_codecs.dart @@ -217,7 +217,7 @@ class CkBrowserImageDecoder implements ui.Codec { _debugCheckNotDisposed(); final ImageDecoder webDecoder = await _getOrCreateWebDecoder(); final DecodeResult result = await promiseToFuture( - webDecoder.decode(DecodeOptions(frameIndex: _nextFrameIndex)), + webDecoder.decode(DecodeOptions(frameIndex: _nextFrameIndex.toDouble())), ); final VideoFrame frame = result.image; _nextFrameIndex = (_nextFrameIndex + 1) % frameCount; @@ -228,8 +228,8 @@ class CkBrowserImageDecoder implements ui.Codec { alphaType: canvasKit.AlphaType.Premul, colorType: canvasKit.ColorType.RGBA_8888, colorSpace: SkColorSpaceSRGB, - width: frame.displayWidth.toInt(), - height: frame.displayHeight.toInt(), + width: frame.displayWidth, + height: frame.displayHeight, ), ); diff --git a/lib/web_ui/lib/src/engine/canvaskit/interval_tree.dart b/lib/web_ui/lib/src/engine/canvaskit/interval_tree.dart index 7f10373c51527..59657e7032ee3 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/interval_tree.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/interval_tree.dart @@ -101,14 +101,10 @@ class IntervalTreeNode { IntervalTreeNode? left; IntervalTreeNode? right; - Iterable enumerateAllElements() sync* { - if (left != null) { - yield* left!.enumerateAllElements(); - } - yield value; - if (right != null) { - yield* right!.enumerateAllElements(); - } + Iterable enumerateAllElements() { + final Iterable leftElements = left?.enumerateAllElements() ?? Iterable.empty(); + final Iterable rightElements = right?.enumerateAllElements() ?? Iterable.empty(); + return leftElements.followedBy([value]).followedBy(rightElements); } /// Whether this node contains [x]. diff --git a/lib/web_ui/lib/src/engine/canvaskit/painting.dart b/lib/web_ui/lib/src/engine/canvaskit/painting.dart index 3f7e536ac4fb8..91e808f0c32cb 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/painting.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/painting.dart @@ -112,7 +112,7 @@ class CkPaint extends ManagedSkiaObject implements ui.Paint { return; } _color = value.value; - skiaObject.setColorInt(value.value); + skiaObject.setColorInt(value.value.toDouble()); } int _color = _defaultPaintColor; @@ -279,7 +279,7 @@ class CkPaint extends ManagedSkiaObject implements ui.Paint { SkPaint createDefault() { final SkPaint paint = SkPaint(); paint.setAntiAlias(_isAntiAlias); - paint.setColorInt(_color); + paint.setColorInt(_color.toDouble()); return paint; } @@ -292,7 +292,7 @@ class CkPaint extends ManagedSkiaObject implements ui.Paint { paint.setStyle(toSkPaintStyle(_style)); paint.setStrokeWidth(_strokeWidth); paint.setAntiAlias(_isAntiAlias); - paint.setColorInt(_color); + paint.setColorInt(_color.toDouble()); paint.setShader(_shader?.withQuality(_filterQuality)); paint.setMaskFilter(_ckMaskFilter?.skiaObject); paint.setColorFilter(_effectiveColorFilter?.skiaObject); diff --git a/lib/web_ui/lib/src/engine/canvaskit/picture.dart b/lib/web_ui/lib/src/engine/canvaskit/picture.dart index 87a94db734c97..d877fd1124bb9 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/picture.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/picture.dart @@ -113,11 +113,11 @@ class CkPicture extends ManagedSkiaObject implements ui.Picture { alphaType: canvasKit.AlphaType.Premul, colorType: canvasKit.ColorType.RGBA_8888, colorSpace: SkColorSpaceSRGB, - width: width, - height: height, + width: width.toDouble(), + height: height.toDouble(), ); final Uint8List pixels = skImage.readPixels(0, 0, imageInfo); - final SkImage? rasterImage = canvasKit.MakeImage(imageInfo, pixels, 4 * width); + final SkImage? rasterImage = canvasKit.MakeImage(imageInfo, pixels, (4 * width).toDouble()); if (rasterImage == null) { throw StateError('Unable to convert image pixels into SkImage.'); } diff --git a/lib/web_ui/lib/src/engine/canvaskit/surface.dart b/lib/web_ui/lib/src/engine/canvaskit/surface.dart index 5fcabace0f7b6..99e0e4dc17c81 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/surface.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/surface.dart @@ -109,7 +109,7 @@ class Surface { void _syncCacheBytes() { if (_skiaCacheBytes != null) { - _grContext?.setResourceCacheLimitBytes(_skiaCacheBytes!); + _grContext?.setResourceCacheLimitBytes(_skiaCacheBytes!.toDouble()); } } @@ -343,7 +343,7 @@ class Surface { _glContext = glContext; if (_glContext != 0) { - _grContext = canvasKit.MakeGrContext(glContext); + _grContext = canvasKit.MakeGrContext(glContext.toDouble()); if (_grContext == null) { throw CanvasKitError('Failed to initialize CanvasKit. ' 'CanvasKit.MakeGrContext returned null.'); @@ -377,8 +377,8 @@ class Surface { } else { final SkSurface? skSurface = canvasKit.MakeOnScreenGLSurface( _grContext!, - size.width.ceil(), - size.height.ceil(), + size.width.roundToDouble(), + size.height.roundToDouble(), SkColorSpaceSRGB, _sampleCount, _stencilBits @@ -448,8 +448,8 @@ class CkSurface { int? get context => _glContext; - int width() => surface.width().toInt(); - int height() => surface.height().toInt(); + int width() => surface.width().round(); + int height() => surface.height().round(); void dispose() { if (_isDisposed) { diff --git a/lib/web_ui/lib/src/engine/canvaskit/text.dart b/lib/web_ui/lib/src/engine/canvaskit/text.dart index 11096a8fd2782..6caa579e050da 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/text.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/text.dart @@ -732,8 +732,8 @@ class CkParagraph extends SkiaObject implements ui.Paragraph { final SkParagraph paragraph = _ensureInitialized(_lastLayoutConstraints!); final List skRects = paragraph.getRectsForRange( - start, - end, + start.toDouble(), + end.toDouble(), toSkRectHeightStyle(boxHeightStyle), toSkRectWidthStyle(boxWidthStyle), ).cast(); @@ -783,7 +783,7 @@ class CkParagraph extends SkiaObject implements ui.Paragraph { characterPosition = position.offset; break; } - final SkTextRange skRange = paragraph.getWordBoundary(characterPosition); + final SkTextRange skRange = paragraph.getWordBoundary(characterPosition.toDouble()); return ui.TextRange(start: skRange.start.toInt(), end: skRange.end.toInt()); } @@ -1031,7 +1031,7 @@ class CkParagraphBuilder implements ui.ParagraphBuilder { SkPaint? foreground = skStyle.foreground?.skiaObject; if (foreground == null) { _defaultTextForeground.setColorInt( - skStyle.color?.value ?? 0xFF000000, + (skStyle.color?.value ?? 0xFF000000).toDouble(), ); foreground = _defaultTextForeground; } diff --git a/lib/web_ui/lib/src/engine/canvaskit/util.dart b/lib/web_ui/lib/src/engine/canvaskit/util.dart index b1906dac741e9..21ef123487c75 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/util.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/util.dart @@ -187,6 +187,6 @@ void drawSkShadow( devicePixelRatio * ckShadowLightRadius, tonalColors.ambient, tonalColors.spot, - flags, + flags.toDouble(), ); } diff --git a/lib/web_ui/lib/src/engine/dom.dart b/lib/web_ui/lib/src/engine/dom.dart index 4e18599a55e0e..47adc523919fb 100644 --- a/lib/web_ui/lib/src/engine/dom.dart +++ b/lib/web_ui/lib/src/engine/dom.dart @@ -287,12 +287,12 @@ extension DomElementExtension on DomElement { external set className(String value); external String get className; external void blur(); - List getElementsByTagName(String tag) => - js_util.callMethod>( - this, 'getElementsByTagName', [tag]).cast(); - List getElementsByClassName(String className) => - js_util.callMethod>( - this, 'getElementsByClassName', [className]).cast(); + Iterable getElementsByTagName(String tag) => + createDomListWrapper(js_util.callMethod<_DomList>( + this, 'getElementsByTagName', [tag])); + Iterable getElementsByClassName(String className) => + createDomListWrapper(js_util.callMethod<_DomList>( + this, 'getElementsByClassName', [className])); external void click(); external bool hasAttribute(String name); Iterable get childNodes => createDomListWrapper( @@ -973,15 +973,20 @@ extension DomKeyboardEventExtension on DomKeyboardEvent { external bool getModifierState(String keyArg); } +DomKeyboardEvent createDomKeyboardEvent(String type, + [Map? init]) => + js_util.callConstructor(domGetConstructor('KeyboardEvent')!, + [type, if (init != null) js_util.jsify(init)]); + @JS() @staticInterop class DomHistory {} extension DomHistoryExtension on DomHistory { dynamic get state => js_util.dartify(js_util.getProperty(this, 'state')); - void go([int? delta]) => + void go([double? delta]) => js_util.callMethod(this, 'go', - [if (delta != null) delta.toDouble()]); + [if (delta != null) delta]); void pushState(dynamic data, String title, String? url) => js_util.callMethod(this, 'pushState', [ if (data is Map || data is Iterable) js_util.jsify(data as Object) else data, @@ -1170,6 +1175,11 @@ extension DomWheelEventExtension on DomWheelEvent { external double get deltaMode; } +DomWheelEvent createDomWheelEvent(String type, + [Map? init]) => + js_util.callConstructor(domGetConstructor('WheelEvent')!, + [type, if (init != null) js_util.jsify(init)]); + @JS() @staticInterop class DomTouchEvent extends DomUIEvent {} @@ -1179,9 +1189,9 @@ extension DomTouchEventExtension on DomTouchEvent { external bool get ctrlKey; external bool get metaKey; external bool get shiftKey; - List? get changedTouches => js_util - .getProperty?>(this, 'changedTouches') - ?.cast(); + Iterable get changedTouches => + createDomTouchListWrapper( + js_util.getProperty<_DomTouchList>(this, 'changedTouches')); } @JS() @@ -1734,6 +1744,52 @@ class _DomListWrapper extends Iterable { Iterable createDomListWrapper(_DomList list) => _DomListWrapper._(list).cast(); +// https://developer.mozilla.org/en-US/docs/Web/API/TouchList +@JS() +@staticInterop +class _DomTouchList {} + +extension DomTouchListExtension on _DomTouchList { + external double get length; + DomTouch item(int index) => + js_util.callMethod(this, 'item', [index.toDouble()]); +} + +class _DomTouchListIterator extends Iterator { + _DomTouchListIterator(this.list); + + final _DomTouchList list; + int index = -1; + + @override + bool moveNext() { + index++; + if (index > list.length) { + throw StateError('Iterator out of bounds'); + } + return index < list.length; + } + + @override + T get current => list.item(index) as T; +} + +class _DomTouchListWrapper extends Iterable { + _DomTouchListWrapper._(this.list); + + final _DomTouchList list; + + @override + Iterator get iterator => _DomTouchListIterator(list); + + /// Override the length to avoid iterating through the whole collection. + @override + int get length => list.length.toInt(); +} + +Iterable createDomTouchListWrapper(_DomTouchList list) => + _DomTouchListWrapper._(list).cast(); + @JS() @staticInterop class DomIntl {} @@ -1767,7 +1823,7 @@ DomV8BreakIterator createV8BreakIterator() { return js_util.callConstructor( v8BreakIterator, [ - js_util.getProperty(domWindow, 'undefined'), + [], js_util.jsify(const {'type': 'line'}), ], ); diff --git a/lib/web_ui/lib/src/engine/keyboard_binding.dart b/lib/web_ui/lib/src/engine/keyboard_binding.dart index 97b1a9dcbf0e6..862a30f7bc8db 100644 --- a/lib/web_ui/lib/src/engine/keyboard_binding.dart +++ b/lib/web_ui/lib/src/engine/keyboard_binding.dart @@ -286,6 +286,9 @@ class KeyboardConverter { static const Duration _kKeydownCancelDurationMac = Duration(milliseconds: 2000); static int _getPhysicalCode(String code) { + if (code.isEmpty) { + return _kWebKeyIdPlane; + } return kWebToPhysicalKey[code] ?? (code.hashCode + _kWebKeyIdPlane); } diff --git a/lib/web_ui/lib/src/engine/navigation/history.dart b/lib/web_ui/lib/src/engine/navigation/history.dart index 0cc335cfd0243..4f1a3c43e4bc3 100644 --- a/lib/web_ui/lib/src/engine/navigation/history.dart +++ b/lib/web_ui/lib/src/engine/navigation/history.dart @@ -152,7 +152,7 @@ class MultiEntriesBrowserHistory extends BrowserHistory { Object _tagWithSerialCount(Object? originialState, int count) { return { - 'serialCount': count, + 'serialCount': count.toDouble(), 'state': originialState, }; } @@ -220,7 +220,7 @@ class MultiEntriesBrowserHistory extends BrowserHistory { assert(_hasSerialCount(currentState)); final int backCount = _currentSerialCount; if (backCount > 0) { - await urlStrategy!.go(-backCount); + await urlStrategy!.go(-backCount.toDouble()); } // Unwrap state. assert(_hasSerialCount(currentState) && _currentSerialCount == 0); diff --git a/lib/web_ui/lib/src/engine/navigation/js_url_strategy.dart b/lib/web_ui/lib/src/engine/navigation/js_url_strategy.dart index 9fbf52ed103fa..ee1e7c017bd70 100644 --- a/lib/web_ui/lib/src/engine/navigation/js_url_strategy.dart +++ b/lib/web_ui/lib/src/engine/navigation/js_url_strategy.dart @@ -21,7 +21,7 @@ typedef _StringToString = String Function(String); typedef _StateOperation = void Function( Object? state, String title, String url); -typedef _HistoryMove = Future Function(int count); +typedef _HistoryMove = Future Function(double count); /// The JavaScript representation of a URL strategy. /// @@ -82,5 +82,5 @@ extension JsUrlStrategyExtension on JsUrlStrategy { /// * `go(3)` moves forward 3 steps in hisotry. /// /// See: https://developer.mozilla.org/en-US/docs/Web/API/History/go - external Future go(int count); + external Future go(double count); } diff --git a/lib/web_ui/lib/src/engine/navigation/url_strategy.dart b/lib/web_ui/lib/src/engine/navigation/url_strategy.dart index c57bc39512725..c9b01b0372414 100644 --- a/lib/web_ui/lib/src/engine/navigation/url_strategy.dart +++ b/lib/web_ui/lib/src/engine/navigation/url_strategy.dart @@ -56,7 +56,7 @@ abstract class UrlStrategy { /// * `go(3)` moves forward 3 steps in hisotry. /// /// See: https://developer.mozilla.org/en-US/docs/Web/API/History/go - Future go(int count); + Future go(double count); } /// This is an implementation of [UrlStrategy] that uses the browser URL's @@ -128,7 +128,7 @@ class HashUrlStrategy extends UrlStrategy { } @override - Future go(int count) { + Future go(double count) { _platformLocation.go(count); return _waitForPopState(); } @@ -179,7 +179,7 @@ class CustomUrlStrategy extends UrlStrategy { delegate.replaceState(state, title, url); @override - Future go(int count) => delegate.go(count); + Future go(double count) => delegate.go(count); } /// Encapsulates all calls to DOM apis, which allows the [UrlStrategy] classes @@ -244,7 +244,7 @@ abstract class PlatformLocation { /// * `go(3)` moves forward 3 steps in hisotry. /// /// See: https://developer.mozilla.org/en-US/docs/Web/API/History/go - void go(int count); + void go(double count); /// The base href where the Flutter app is being served. /// @@ -293,7 +293,7 @@ class BrowserPlatformLocation extends PlatformLocation { } @override - void go(int count) { + void go(double count) { _history.go(count); } diff --git a/lib/web_ui/lib/src/engine/pointer_binding.dart b/lib/web_ui/lib/src/engine/pointer_binding.dart index d53a5c8cefd75..fc717f52b6ac1 100644 --- a/lib/web_ui/lib/src/engine/pointer_binding.dart +++ b/lib/web_ui/lib/src/engine/pointer_binding.dart @@ -930,7 +930,7 @@ class _TouchAdapter extends _BaseAdapter { _addTouchEventListener(glassPaneElement, 'touchstart', (DomTouchEvent event) { final Duration timeStamp = _BaseAdapter._eventTimeStampToDuration(event.timeStamp!); final List pointerData = []; - for (final DomTouch touch in event.changedTouches!.cast()) { + for (final DomTouch touch in event.changedTouches.cast()) { final bool nowPressed = _isTouchPressed(touch.identifier!.toInt()); if (!nowPressed) { _pressTouch(touch.identifier!.toInt()); @@ -950,7 +950,7 @@ class _TouchAdapter extends _BaseAdapter { event.preventDefault(); // Prevents standard overscroll on iOS/Webkit. final Duration timeStamp = _BaseAdapter._eventTimeStampToDuration(event.timeStamp!); final List pointerData = []; - for (final DomTouch touch in event.changedTouches!.cast()) { + for (final DomTouch touch in event.changedTouches.cast()) { final bool nowPressed = _isTouchPressed(touch.identifier!.toInt()); if (nowPressed) { _convertEventToPointerData( @@ -971,7 +971,7 @@ class _TouchAdapter extends _BaseAdapter { event.preventDefault(); final Duration timeStamp = _BaseAdapter._eventTimeStampToDuration(event.timeStamp!); final List pointerData = []; - for (final DomTouch touch in event.changedTouches!.cast()) { + for (final DomTouch touch in event.changedTouches.cast()) { final bool nowPressed = _isTouchPressed(touch.identifier!.toInt()); if (nowPressed) { _unpressTouch(touch.identifier!.toInt()); @@ -990,7 +990,7 @@ class _TouchAdapter extends _BaseAdapter { _addTouchEventListener(glassPaneElement, 'touchcancel', (DomTouchEvent event) { final Duration timeStamp = _BaseAdapter._eventTimeStampToDuration(event.timeStamp!); final List pointerData = []; - for (final DomTouch touch in event.changedTouches!.cast()) { + for (final DomTouch touch in event.changedTouches.cast()) { final bool nowPressed = _isTouchPressed(touch.identifier!.toInt()); if (nowPressed) { _unpressTouch(touch.identifier!.toInt()); diff --git a/lib/web_ui/lib/src/engine/profiler.dart b/lib/web_ui/lib/src/engine/profiler.dart index 9601f1c0e429b..8ea415f76788b 100644 --- a/lib/web_ui/lib/src/engine/profiler.dart +++ b/lib/web_ui/lib/src/engine/profiler.dart @@ -4,12 +4,16 @@ import 'dart:async'; +import 'package:js/js.dart'; import 'package:ui/ui.dart' as ui; import 'dom.dart'; import 'platform_dispatcher.dart'; import 'safe_browser_api.dart'; +@JS('window._flutter_internal_on_benchmark') +external Object? get onBenchmark; + /// A function that computes a value of type [R]. /// /// Functions of this signature can be passed to [timeAction] for performance @@ -101,16 +105,10 @@ class Profiler { void benchmark(String name, double value) { _checkBenchmarkMode(); - // First get the value as `Object?` then use `as` cast to check the type. - // This is because the type cast in `getJsProperty` is optimized - // out at certain optimization levels in dart2js, leading to obscure errors - // later on. - final Object? onBenchmark = getJsProperty( - domWindow, - '_flutter_internal_on_benchmark', - ); - onBenchmark as OnBenchmark?; - onBenchmark?.call(name, value); + final OnBenchmark? callback = onBenchmark as OnBenchmark?; + if (callback != null) { + callback(name, value); + } } } diff --git a/lib/web_ui/lib/src/engine/safe_browser_api.dart b/lib/web_ui/lib/src/engine/safe_browser_api.dart index b9e900180615a..185a0e6c79cc7 100644 --- a/lib/web_ui/lib/src/engine/safe_browser_api.dart +++ b/lib/web_ui/lib/src/engine/safe_browser_api.dart @@ -110,13 +110,6 @@ void removeJsEventListener(Object target, String type, Function listener, Object ); } -/// The signature of the `parseFloat` JavaScript function. -typedef _JsParseFloat = num? Function(String source); - -/// The JavaScript-side `parseFloat` function. -@JS('parseFloat') -external _JsParseFloat get _jsParseFloat; - /// Parses a string [source] into a double. /// /// Uses the JavaScript `parseFloat` function instead of Dart's [double.parse] @@ -126,7 +119,7 @@ external _JsParseFloat get _jsParseFloat; num? parseFloat(String source) { // Using JavaScript's `parseFloat` here because it can parse values // like "20px", while Dart's `double.tryParse` fails. - final num? result = _jsParseFloat(source); + final num? result = js_util.callMethod(domWindow, 'parseFloat', [source]); if (result == null || result.isNaN) { return null; @@ -312,7 +305,7 @@ extension DecodeResultExtension on DecodeResult { @staticInterop class DecodeOptions { external factory DecodeOptions({ - required int frameIndex, + required double frameIndex, }); } @@ -330,7 +323,7 @@ class VideoFrame implements DomCanvasImageSource {} extension VideoFrameExtension on VideoFrame { external double allocationSize(); - external JsPromise copyTo(Uint8List destination); + external JsPromise copyTo(Object destination); external String? get format; external double get codedWidth; external double get codedHeight; @@ -453,7 +446,7 @@ class GlContext { Object? _kRGBA; Object? _kLinear; Object? _kTextureMinFilter; - int? _kTexture0; + double? _kTexture0; Object? _canvas; int? _widthInPixels; @@ -569,7 +562,7 @@ class GlContext { js_util.callMethod(glContext, 'bindTexture', [target, buffer]); } - void activeTexture(int textureUnit) { + void activeTexture(double textureUnit) { js_util.callMethod(glContext, 'activeTexture', [textureUnit]); } @@ -710,8 +703,8 @@ class GlContext { Object? get kTexture2D => _kTexture2D ??= js_util.getProperty(glContext, 'TEXTURE_2D'); - int get kTexture0 => - _kTexture0 ??= js_util.getProperty(glContext, 'TEXTURE0'); + double get kTexture0 => + _kTexture0 ??= js_util.getProperty(glContext, 'TEXTURE0'); Object? get kTextureWrapS => _kTextureWrapS ??= js_util.getProperty(glContext, 'TEXTURE_WRAP_S'); diff --git a/lib/web_ui/lib/src/engine/semantics/semantics_helper.dart b/lib/web_ui/lib/src/engine/semantics/semantics_helper.dart index 7741a8384da31..f3bdbdddc4f01 100644 --- a/lib/web_ui/lib/src/engine/semantics/semantics_helper.dart +++ b/lib/web_ui/lib/src/engine/semantics/semantics_helper.dart @@ -331,7 +331,7 @@ class MobileSemanticsEnabler extends SemanticsEnabler { case 'touchstart': case 'touchend': final DomTouchEvent touchEvent = event as DomTouchEvent; - activationPoint = touchEvent.changedTouches!.first.client; + activationPoint = touchEvent.changedTouches.first.client; break; case 'pointerdown': case 'pointerup': diff --git a/lib/web_ui/lib/src/engine/test_embedding.dart b/lib/web_ui/lib/src/engine/test_embedding.dart index 8f28532a50539..05ccd86466758 100644 --- a/lib/web_ui/lib/src/engine/test_embedding.dart +++ b/lib/web_ui/lib/src/engine/test_embedding.dart @@ -132,12 +132,12 @@ class TestUrlStrategy extends UrlStrategy { } @override - Future go(int count) { + Future go(double count) { assert(withinAppHistory); // Browsers don't move in history immediately. They do it at the next // event loop. So let's simulate that. return _nextEventLoop(() { - _currentEntryIndex = _currentEntryIndex + count; + _currentEntryIndex = _currentEntryIndex + count.round(); if (withinAppHistory) { _firePopStateEvent(); } diff --git a/lib/web_ui/lib/src/engine/text_editing/text_editing.dart b/lib/web_ui/lib/src/engine/text_editing/text_editing.dart index b2cf2ba6f3a2c..ac995a6359c4e 100644 --- a/lib/web_ui/lib/src/engine/text_editing/text_editing.dart +++ b/lib/web_ui/lib/src/engine/text_editing/text_editing.dart @@ -2358,7 +2358,9 @@ class EditableTextGeometry { assert(encodedGeometry.containsKey('transform')); final List transformList = - List.from(encodedGeometry.readList('transform')); + List.from(encodedGeometry.readList('transform').map( + (final dynamic e) => (e as num).toDouble() + )); return EditableTextGeometry( width: encodedGeometry.readDouble('width'), height: encodedGeometry.readDouble('height'), diff --git a/lib/web_ui/lib/src/engine/ulps.dart b/lib/web_ui/lib/src/engine/ulps.dart deleted file mode 100644 index 65db11f5e7018..0000000000000 --- a/lib/web_ui/lib/src/engine/ulps.dart +++ /dev/null @@ -1,216 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'dart:math' as math; -import 'dart:typed_data'; - -// This is a small library to handle stability for floating point operations. -// -// Since we are representing an infinite number of real numbers in finite -// number of bits, when we perform comparisons of coordinates for paths for -// example, we want to make sure that line and curve sections that are too -// close to each other (number of floating point numbers -// representable in bits between two numbers) are handled correctly and -// don't cause algorithms to fail when we perform operations such as -// subtraction or between checks. -// -// Small introduction into floating point comparison: -// -// For some good articles on the topic, see -// https://randomascii.wordpress.com/category/floating-point/page/2/ -// Port based on: -// https://github.com/google/skia/blob/main/include/private/SkFloatBits.h -// -// Here is the 32 bit IEEE representation: -// uint32_t mantissa : 23; -// uint32_t exponent : 8; -// uint32_t sign : 1; -// As you can see it was carefully designed to be reinterpreted as an integer. -// -// Ulps stands for unit in the last place. ulp(x) is the gap between two -// floating point numbers nearest x. - -/// Converts a sign-bit int (float interpreted as int) into a 2s complement -/// int. Also converts 0x80000000 to 0. Allows result to be compared using -/// int comparison. -int signBitTo2sCompliment(int x) => - (x & 0x80000000) != 0 ? (-(x & 0x7fffffff)) : x; - -/// Convert a 2s complement int to a sign-bit (i.e. int interpreted as float). -int twosComplimentToSignBit(int x) { - if ((x & 0x80000000) == 0) { - return x; - } - x = ~x + 1; - x |= 0x80000000; - return x; -} - -class _FloatBitConverter { - factory _FloatBitConverter() { - final Float32List float32List = Float32List(1); - return _FloatBitConverter._( - float32List, float32List.buffer.asInt32List(0, 1)); - } - - _FloatBitConverter._(this.float32List, this.int32List); - - final Float32List float32List; - final Int32List int32List; - - int toInt(Float32List source, int index) { - float32List[0] = source[index]; - return int32List[0]; - } - - int toBits(double x) { - float32List[0] = x; - return int32List[0]; - } - - double toDouble(int bits) { - int32List[0] = bits; - return float32List[0]; - } -} - -// Singleton bit converter to prevent typed array allocations. -final _FloatBitConverter _floatBitConverter = _FloatBitConverter(); - -// Converts float to bits. -int float2Bits(Float32List source, int index) { - return _floatBitConverter.toInt(source, index); -} - -// Converts bits to float. -double bitsToFloat(int bits) { - return _floatBitConverter.toDouble(bits); -} - -const int floatBitsExponentMask = 0x7F800000; -const int floatBitsMatissaMask = 0x007FFFFF; - -/// Returns a float as 2s complement int to be able to compare floats to each -/// other. -int floatFromListAs2sCompliment(Float32List source, int index) => - signBitTo2sCompliment(float2Bits(source, index)); - -int floatAs2sCompliment(double x) => - signBitTo2sCompliment(_floatBitConverter.toBits(x)); - -double twosComplimentAsFloat(int x) => bitsToFloat(twosComplimentToSignBit(x)); - -bool _argumentsDenormalized(double a, double b, int epsilon) { - final double denormalizedCheck = kFltEpsilon * epsilon / 2; - return a.abs() <= denormalizedCheck && b.abs() <= denormalizedCheck; -} - -bool equalUlps(double a, double b, int epsilon, int depsilon) { - if (_argumentsDenormalized(a, b, depsilon)) { - return true; - } - final int aBits = floatAs2sCompliment(a); - final int bBits = floatAs2sCompliment(b); - // Find the difference in ULPs. - return aBits < bBits + epsilon && bBits < aBits + epsilon; -} - -/// General equality check that covers between, product and division by using -/// ulps epsilon 16. -bool almostEqualUlps(double a, double b) { - const int kUlpsEpsilon = 16; - return equalUlps(a, b, kUlpsEpsilon, kUlpsEpsilon); -} - -/// Equality using the same error term for between comparison. -bool almostBequalUlps(double a, double b) { - const int kUlpsEpsilon = 2; - return equalUlps(a, b, kUlpsEpsilon, kUlpsEpsilon); -} - -/// Equality check for product. -bool almostPequalUlps(double a, double b) { - const int kUlpsEpsilon = 8; - return equalUlps(a, b, kUlpsEpsilon, kUlpsEpsilon); -} - -/// Equality check for division. -bool almostDequalUlps(double a, double b) { - const int kUlpsEpsilon = 16; - return equalUlps(a, b, kUlpsEpsilon, kUlpsEpsilon); -} - -/// Checks if 2 points are roughly equal (ulp 256) to each other. -bool approximatelyEqual(double ax, double ay, double bx, double by) { - if (approximatelyEqualT(ax, bx) && approximatelyEqualT(ay, by)) { - return true; - } - if (!roughlyEqualUlps(ax, bx) || !roughlyEqualUlps(ay, by)) { - return false; - } - final double dx = ax - bx; - final double dy = ay - by; - final double dist = math.sqrt(dx * dx + dy * dy); - final double tiniest = math.min(math.min(math.min(ax, bx), ay), by); - double largest = math.max(math.max(math.max(ax, bx), ay), by); - largest = math.max(largest, -tiniest); - return almostDequalUlps(largest, largest + dist); -} - -/// Equality check for comparing curve T values in the range of 0 to 1. -/// -/// For general numbers (larger and smaller) use -/// AlmostEqualUlps instead. -bool approximatelyEqualT(double t1, double t2) { - return approximatelyZero(t1 - t2); -} - -bool approximatelyZero(double value) => value.abs() < kFltEpsilon; - -bool roughlyEqualUlps(double a, double b) { - const int kUlpsEpsilon = 256; - const int kDUlpsEpsilon = 1024; - return equalUlps(a, b, kUlpsEpsilon, kDUlpsEpsilon); -} - -bool dEqualUlpsEpsilon(double a, double b, int epsilon) { - final int aBits = floatAs2sCompliment(a); - final int bBits = floatAs2sCompliment(b); - // Find the difference in ULPs. - return aBits < bBits + epsilon && bBits < aBits + epsilon; -} - -// Checks equality for division. -bool almostDequalUlpsDouble(double a, double b) { - final double absA = a.abs(); - final double absB = b.abs(); - if (absA < kScalarMax && absB < kScalarMax) { - return almostDequalUlps(a, b); - } - return (a - b).abs() / math.max(absA, absB) < kDblEpsilonSubdivideErr; -} - -const double kFltEpsilon = 1.19209290E-07; // == 1 / (2 ^ 23) -const double kDblEpsilon = 2.22045e-16; -const double kFltEpsilonCubed = kFltEpsilon * kFltEpsilon * kFltEpsilon; -const double kFltEpsilonHalf = kFltEpsilon / 2; -const double kFltEpsilonDouble = kFltEpsilon * 2; -// Epsilon to use when ordering vectors. -const double kFltEpsilonOrderableErr = kFltEpsilon * 16; -const double kFltEpsilonSquared = kFltEpsilon * kFltEpsilon; -// Use a compile-time constant for FLT_EPSILON_SQRT to avoid initializers. -// A 17 digit constant guarantees exact results. -const double kFltEpsilonSqrt = 0.00034526697709225118; // sqrt(kFltEpsilon); -const double kFltEpsilonInverse = 1 / kFltEpsilon; -const double kDblEpsilonErr = kDblEpsilon * 4; -const double kDblEpsilonSubdivideErr = kDblEpsilon * 16; -const double kRoughEpsilon = kFltEpsilon * 64; -const double kMoreRoughEpsilon = kFltEpsilon * 256; -const double kWayRoughEpsilon = kFltEpsilon * 2048; -const double kBumpEpsilon = kFltEpsilon * 4096; - -// Scalar max is based on 32 bit float since [PathRef] stores values in -// Float32List. -const double kScalarMax = 3.402823466e+38; -const double kScalarMin = -kScalarMax; diff --git a/lib/web_ui/lib/src/engine/util.dart b/lib/web_ui/lib/src/engine/util.dart index 3f78e859e8286..a96bffef73f50 100644 --- a/lib/web_ui/lib/src/engine/util.dart +++ b/lib/web_ui/lib/src/engine/util.dart @@ -627,19 +627,19 @@ extension JsonExtensions on Map { } int readInt(String propertyName) { - return this[propertyName] as int; + return (this[propertyName] as num).toInt(); } int? tryInt(String propertyName) { - return this[propertyName] as int?; + return (this[propertyName] as num?)?.toInt(); } double readDouble(String propertyName) { - return this[propertyName] as double; + return (this[propertyName] as num).toDouble(); } double? tryDouble(String propertyName) { - return this[propertyName] as double?; + return (this[propertyName] as num?)?.toDouble(); } } diff --git a/lib/web_ui/lib/src/engine/view_embedder/hot_restart_cache_handler.dart b/lib/web_ui/lib/src/engine/view_embedder/hot_restart_cache_handler.dart index 876972141b890..ba1c914320f04 100644 --- a/lib/web_ui/lib/src/engine/view_embedder/hot_restart_cache_handler.dart +++ b/lib/web_ui/lib/src/engine/view_embedder/hot_restart_cache_handler.dart @@ -2,10 +2,19 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:meta/meta.dart'; +import 'package:js/js.dart'; +import 'package:ui/src/engine.dart'; import '../dom.dart'; -import '../safe_browser_api.dart'; + +/// This is state persistent across hot restarts that indicates what +/// to clear. Delay removal of old visible state to make the +/// transition appear smooth. +@JS('window.__flutterState') +external List? get hotRestartStore; + +@JS('window.__flutterState') +external set hotRestartStore(List? nodes); /// Handles [DomElement]s that need to be removed after a hot-restart. /// @@ -22,36 +31,35 @@ class HotRestartCacheHandler { } } - /// The name for the JS global variable backing this cache. - @visibleForTesting - static const String defaultCacheName = '__flutter_state'; - /// The js-interop layer backing [_elements]. /// /// Elements are stored in a JS global array named [defaultCacheName]. - late List? _jsElements; + late List? _jsElements; /// The elements that need to be cleaned up after hot-restart. - List get _elements { - _jsElements = - getJsProperty?>(domWindow, defaultCacheName); + List get _elements { + _jsElements = hotRestartStore; if (_jsElements == null) { - _jsElements = []; - setJsProperty(domWindow, defaultCacheName, _jsElements); + _jsElements = []; + hotRestartStore = _jsElements; } return _jsElements!; } /// Removes every element from [_elements] and empties the list. void _clearAllElements() { - for (final DomElement? element in _elements) { - element?.remove(); + for (final Object? element in _elements) { + if (element is DomElement) { + element.remove(); + } } - _elements.clear(); + hotRestartStore = []; } /// Registers a [DomElement] to be removed after hot-restart. void registerElement(DomElement element) { - _elements.add(element); + final List elements = _elements; + elements.add(element); + hotRestartStore = elements; } } diff --git a/lib/web_ui/test/canvaskit/canvaskit_api_test.dart b/lib/web_ui/test/canvaskit/canvaskit_api_test.dart index 94add854d0fe5..a0c00347a51a5 100644 --- a/lib/web_ui/test/canvaskit/canvaskit_api_test.dart +++ b/lib/web_ui/test/canvaskit/canvaskit_api_test.dart @@ -1311,7 +1311,7 @@ void _canvasTests() { devicePixelRatio * kLightRadius, tonalColors.ambient, tonalColors.spot, - flags, + flags.toDouble(), ); } }); @@ -1697,16 +1697,16 @@ void _paragraphTests() { // "Hello" for (int i = 0; i < 5; i++) { - expect(paragraph.getWordBoundary(i).start, 0); - expect(paragraph.getWordBoundary(i).end, 5); + expect(paragraph.getWordBoundary(i.toDouble()).start, 0); + expect(paragraph.getWordBoundary(i.toDouble()).end, 5); } // Placeholder expect(paragraph.getWordBoundary(5).start, 5); expect(paragraph.getWordBoundary(5).end, 6); // "World" for (int i = 6; i < 11; i++) { - expect(paragraph.getWordBoundary(i).start, 6); - expect(paragraph.getWordBoundary(i).end, 11); + expect(paragraph.getWordBoundary(i.toDouble()).start, 6); + expect(paragraph.getWordBoundary(i.toDouble()).end, 11); } // "!" expect(paragraph.getWordBoundary(11).start, 11); @@ -1788,13 +1788,13 @@ void _paragraphTests() { final int sampleCount = gl.getParameter(gl.samples); final int stencilBits = gl.getParameter(gl.stencilBits); - final int glContext = canvasKit.GetWebGLContext( + final double glContext = canvasKit.GetWebGLContext( canvas, SkWebGLContextOptions( antialias: 0, majorVersion: webGLVersion.toDouble(), ), - ).toInt(); + ); final SkGrContext grContext = canvasKit.MakeGrContext(glContext); final SkSurface? skSurface = canvasKit.MakeOnScreenGLSurface( grContext, diff --git a/lib/web_ui/test/canvaskit/fallback_fonts_golden_test.dart b/lib/web_ui/test/canvaskit/fallback_fonts_golden_test.dart index 84c05602b8d69..ead96ded8d712 100644 --- a/lib/web_ui/test/canvaskit/fallback_fonts_golden_test.dart +++ b/lib/web_ui/test/canvaskit/fallback_fonts_golden_test.dart @@ -428,7 +428,7 @@ void testMain() { rethrow; } } - }); + }, timeout: const Timeout.factor(50)); // This test is very slow. }, skip: isSafari); } diff --git a/lib/web_ui/test/canvaskit/image_golden_test.dart b/lib/web_ui/test/canvaskit/image_golden_test.dart index 44ea1c74560b0..343b439ed1e2d 100644 --- a/lib/web_ui/test/canvaskit/image_golden_test.dart +++ b/lib/web_ui/test/canvaskit/image_golden_test.dart @@ -241,7 +241,9 @@ void _testForImageCodecs({required bool useBrowserImageDecoder}) { codec.dispose(); } // TODO(hterkelsen): Firefox and Safari do not currently support ImageDecoder. - }, skip: isFirefox || isSafari); + // TODO(jacksongardner): enable on wasm + // see https://github.com/flutter/flutter/issues/118334 + }, skip: isFirefox || isSafari || isWasm); test('CkImage.clone also clones the VideoFrame', () async { final CkBrowserImageDecoder image = await CkBrowserImageDecoder.create( @@ -835,7 +837,7 @@ void _testForImageCodecs({required bool useBrowserImageDecoder}) { Uint8List.fromList([0xff, 0xd8, 0xff, 0xe2, 0x0c, 0x58, 0x49, 0x43, 0x43, 0x5f])), 'image/jpeg'); }); - }); + }, timeout: const Timeout.factor(10)); // These tests can take a while. Allow for a longer timeout. } /// Tests specific to WASM codecs bundled with CanvasKit. @@ -905,7 +907,9 @@ void _testCkBrowserImageDecoder() { expect(rgba!.buffer.asUint8List(), expectedColors[i]); } testCollector.collectNow(); - }); + // TODO(jacksongardner): enable on wasm + // see https://github.com/flutter/flutter/issues/118334 + }, skip: isWasm); test('ImageDecoder expires after inactivity', () async { const Duration testExpireDuration = Duration(milliseconds: 100); @@ -950,7 +954,9 @@ void _testCkBrowserImageDecoder() { testCollector.collectNow(); debugRestoreWebDecoderExpireDuration(); - }); + // TODO(jacksongardner): enable on wasm + // see https://github.com/flutter/flutter/issues/118334 + }, skip: isWasm); } class TestHttpRequestMock { @@ -978,10 +984,10 @@ class TestHttpRequest implements DomXMLHttpRequest { factory TestHttpRequest(TestHttpRequestMock mock) { return TestHttpRequest._( responseType: mock.responseType, - timeout: mock.timeout, + timeout: mock.timeout.toDouble(), withCredentials: mock.withCredentials, response: mock.response, - status: mock.status, + status: mock.status.toDouble(), open: allowInterop((String method, String url, [bool? async]) => mock.open(method, url, async)), send: allowInterop(() => mock.send()), @@ -992,10 +998,10 @@ class TestHttpRequest implements DomXMLHttpRequest { external factory TestHttpRequest._({ String responseType, - int timeout, + double timeout, bool withCredentials, dynamic response, - int status, + double status, void Function(String method, String url, [bool? async]) open, void Function() send, void Function(String eventType, DomEventListener listener) addEventListener diff --git a/lib/web_ui/test/canvaskit/initialization/initialization_stores_config_test.dart b/lib/web_ui/test/canvaskit/initialization/initialization_stores_config_test.dart index 317164059be44..faf49af11e923 100644 --- a/lib/web_ui/test/canvaskit/initialization/initialization_stores_config_test.dart +++ b/lib/web_ui/test/canvaskit/initialization/initialization_stores_config_test.dart @@ -18,7 +18,7 @@ void testMain() { // fetch that, override one of its properties (under test), then delete it // from window (so our configuration asserts don't fire!) final JsFlutterConfiguration config = js_util.getProperty(domWindow, 'flutterConfiguration'); - js_util.setProperty(config, 'canvasKitMaximumSurfaces', 32); + js_util.setProperty(config, 'canvasKitMaximumSurfaces', 32.0); js_util.setProperty(domWindow, 'flutterConfiguration', null); await initializeEngineServices(jsConfiguration: config); diff --git a/lib/web_ui/test/canvaskit/picture_test.dart b/lib/web_ui/test/canvaskit/picture_test.dart index 922581e08429d..52de680ee8b41 100644 --- a/lib/web_ui/test/canvaskit/picture_test.dart +++ b/lib/web_ui/test/canvaskit/picture_test.dart @@ -45,13 +45,10 @@ void testMain() { expect(actualError, isNotNull); // TODO(yjbanov): cannot test precise message due to https://github.com/flutter/flutter/issues/96298 - expect('$actualError', allOf( - startsWith( + expect('$actualError', startsWith( 'Bad state: Test.\n' 'The picture has been disposed. ' 'When the picture was disposed the stack trace was:\n' - ), - contains('StackTrace_current'), )); // Emulate SkiaObjectCache deleting the picture diff --git a/lib/web_ui/test/canvaskit/surface_test.dart b/lib/web_ui/test/canvaskit/surface_test.dart index f593c37e20a29..e31ca43bf8079 100644 --- a/lib/web_ui/test/canvaskit/surface_test.dart +++ b/lib/web_ui/test/canvaskit/surface_test.dart @@ -33,7 +33,7 @@ void testMain() { expect(original.height, 19); expect(original.style.width, '9px'); expect(original.style.height, '19px'); - expect(original.style.transform, _isTranslate(0, 0)); + expect(original.style.transform, _isTranslate('0', '0')); expect(originalSurface.width(), 9); expect(originalSurface.height(), 19); @@ -45,7 +45,7 @@ void testMain() { expect(shrunk, same(original)); expect(shrunk.style.width, '9px'); expect(shrunk.style.height, '19px'); - expect(shrunk.style.transform, _isTranslate(0, -4)); + expect(shrunk.style.transform, _isTranslate('0', '-4')); expect(shrunkSurface, isNot(same(originalSurface))); expect(shrunkSurface.width(), 5); expect(shrunkSurface.height(), 15); @@ -63,7 +63,7 @@ void testMain() { expect(firstIncrease.height, 28); expect(firstIncrease.style.width, '14px'); expect(firstIncrease.style.height, '28px'); - expect(firstIncrease.style.transform, _isTranslate(0, -8)); + expect(firstIncrease.style.transform, _isTranslate('0', '-8')); expect(firstIncreaseSurface.width(), 10); expect(firstIncreaseSurface.height(), 20); @@ -72,7 +72,7 @@ void testMain() { surface.acquireFrame(const ui.Size(11, 22)).skiaSurface; final DomCanvasElement secondIncrease = surface.htmlCanvas!; expect(secondIncrease, same(firstIncrease)); - expect(secondIncrease.style.transform, _isTranslate(0, -6)); + expect(secondIncrease.style.transform, _isTranslate('0', '-6')); expect(secondIncreaseSurface, isNot(same(firstIncreaseSurface))); expect(secondIncreaseSurface.width(), 11); expect(secondIncreaseSurface.height(), 22); @@ -88,7 +88,7 @@ void testMain() { expect(huge.height, 56); expect(huge.style.width, '28px'); expect(huge.style.height, '56px'); - expect(huge.style.transform, _isTranslate(0, -16)); + expect(huge.style.transform, _isTranslate('0', '-16')); expect(hugeSurface.width(), 20); expect(hugeSurface.height(), 40); @@ -99,7 +99,7 @@ void testMain() { expect(shrunk2, same(huge)); expect(shrunk2.style.width, '28px'); expect(shrunk2.style.height, '56px'); - expect(shrunk2.style.transform, _isTranslate(0, -41)); + expect(shrunk2.style.transform, _isTranslate('0', '-41')); expect(shrunkSurface2, isNot(same(hugeSurface))); expect(shrunkSurface2.width(), 5); expect(shrunkSurface2.height(), 15); @@ -113,7 +113,7 @@ void testMain() { expect(dpr2Canvas, same(huge)); expect(dpr2Canvas.style.width, '14px'); expect(dpr2Canvas.style.height, '28px'); - expect(dpr2Canvas.style.transform, _isTranslate(0, -20.5)); + expect(dpr2Canvas.style.transform, _isTranslate('0', '-20.5')); expect(dpr2Surface2, isNot(same(hugeSurface))); expect(dpr2Surface2.width(), 5); expect(dpr2Surface2.height(), 15); @@ -185,7 +185,7 @@ void testMain() { expect(original.height(), 16); expect(surface.htmlCanvas!.style.width, '10px'); expect(surface.htmlCanvas!.style.height, '16px'); - expect(surface.htmlCanvas!.style.transform, _isTranslate(0, 0)); + expect(surface.htmlCanvas!.style.transform, _isTranslate('0', '0')); // Increase device-pixel ratio: this makes CSS pixels bigger, so we need // fewer of them to cover the browser window. @@ -196,7 +196,7 @@ void testMain() { expect(highDpr.height(), 16); expect(surface.htmlCanvas!.style.width, '5px'); expect(surface.htmlCanvas!.style.height, '8px'); - expect(surface.htmlCanvas!.style.transform, _isTranslate(0, 0)); + expect(surface.htmlCanvas!.style.transform, _isTranslate('0', '0')); // Decrease device-pixel ratio: this makes CSS pixels smaller, so we need // more of them to cover the browser window. @@ -207,7 +207,7 @@ void testMain() { expect(lowDpr.height(), 16); expect(surface.htmlCanvas!.style.width, '20px'); expect(surface.htmlCanvas!.style.height, '32px'); - expect(surface.htmlCanvas!.style.transform, _isTranslate(0, 0)); + expect(surface.htmlCanvas!.style.transform, _isTranslate('0', '0')); // See https://github.com/flutter/flutter/issues/77084#issuecomment-1120151172 window.debugOverrideDevicePixelRatio(2.0); @@ -217,21 +217,21 @@ void testMain() { expect(changeRatioAndSize.height(), 16); expect(surface.htmlCanvas!.style.width, '5px'); expect(surface.htmlCanvas!.style.height, '8px'); - expect(surface.htmlCanvas!.style.transform, _isTranslate(0, 0)); + expect(surface.htmlCanvas!.style.transform, _isTranslate('0', '0')); }); }); } /// Checks that the CSS 'transform' property is a translation in a cross-browser way. /// -/// Assumes that the `x` and `y` values are round enough for their `toString` values -/// to match the stringified CSS length value. -Matcher _isTranslate(double x, double y) { +/// Takes strings directly to avoid issues with floating point or differences +/// in stringification of numeric values across JS and Wasm targets. +Matcher _isTranslate(String x, String y) { // When the y coordinate is zero, Firefox omits it, e.g.: // Chrome/Safari/Edge: translate(0px, 0px) // Firefox: translate(0px) final String fullFormat = 'translate(${x}px, ${y}px)'; - if (y != 0) { + if (y != '0') { return equals(fullFormat); } else { return anyOf( diff --git a/lib/web_ui/test/channel_buffers_test.dart b/lib/web_ui/test/channel_buffers_test.dart index 924d545aeccc7..b88af28d3ab43 100644 --- a/lib/web_ui/test/channel_buffers_test.dart +++ b/lib/web_ui/test/channel_buffers_test.dart @@ -15,6 +15,7 @@ import 'dart:typed_data'; import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; +import 'package:ui/src/engine/browser_detection.dart'; import 'package:ui/ui.dart' as ui; void main() { @@ -273,7 +274,7 @@ void testMain() { 'b: seven', '-9', ]); - }); + }, skip: isWasm); // https://github.com/dart-lang/sdk/issues/50778 test('ChannelBuffers.clearListener', () async { final List log = []; @@ -320,7 +321,7 @@ void testMain() { 'a2: four', '-7', ]); - }); + }, skip: isWasm); // https://github.com/dart-lang/sdk/issues/50778 test('ChannelBuffers.handleMessage for resize', () async { final List log = []; @@ -367,7 +368,7 @@ void testMain() { 'callback1: true', 'callback2: true', ]); - }); + }, skip: isWasm); // https://github.com/dart-lang/sdk/issues/50778 } class _TestChannelBuffers extends ui.ChannelBuffers { diff --git a/lib/web_ui/test/engine/history_test.dart b/lib/web_ui/test/engine/history_test.dart index ccad2e44d5c84..2995efe8d09ab 100644 --- a/lib/web_ui/test/engine/history_test.dart +++ b/lib/web_ui/test/engine/history_test.dart @@ -50,7 +50,7 @@ void testMain() { // Random history state. strategy = TestUrlStrategy.fromEntry( - const TestHistoryEntry({'foo': 123}, null, '/'), + const TestHistoryEntry({'foo': 123.0}, null, '/'), ); history = createHistoryForExistingState(strategy); expect(history, isA()); @@ -58,8 +58,8 @@ void testMain() { // Multi-entry history state. final Map state = { - 'serialCount': 1, - 'state': {'foo': 123}, + 'serialCount': 1.0, + 'state': {'foo': 123.0}, }; strategy = TestUrlStrategy.fromEntry(TestHistoryEntry(state, null, '/')); history = createHistoryForExistingState(strategy); @@ -720,7 +720,7 @@ class TestPlatformLocation extends PlatformLocation { } @override - void go(int count) { + void go(double count) { throw UnimplementedError(); } diff --git a/lib/web_ui/test/engine/host_node_test.dart b/lib/web_ui/test/engine/host_node_test.dart index 8c01b6a840dc9..e882d49042ccc 100644 --- a/lib/web_ui/test/engine/host_node_test.dart +++ b/lib/web_ui/test/engine/host_node_test.dart @@ -149,7 +149,7 @@ void _runDomTests(HostNode hostNode) { test('querySelector', () { final DomElement? found = hostNode.querySelector('#yep'); - expect(identical(found, target), isTrue); + expect(found, target); }); test('.contains and .append', () { diff --git a/lib/web_ui/test/engine/platform_dispatcher_test.dart b/lib/web_ui/test/engine/platform_dispatcher_test.dart index e304394e7e30a..e197db5c8ba4e 100644 --- a/lib/web_ui/test/engine/platform_dispatcher_test.dart +++ b/lib/web_ui/test/engine/platform_dispatcher_test.dart @@ -3,7 +3,6 @@ // found in the LICENSE file. import 'dart:async'; -import 'dart:js_util' as js_util; import 'dart:typed_data'; import 'package:test/bootstrap/browser.dart'; @@ -73,32 +72,6 @@ void testMain() { ); }); - test('responds correctly to flutter/platform Clipboard.getData failure', - () async { - // Patch browser so that clipboard api is not available. - final Object? originalClipboard = - js_util.getProperty(domWindow.navigator, 'clipboard'); - js_util.setProperty(domWindow.navigator, 'clipboard', null); - const MethodCodec codec = JSONMethodCodec(); - final Completer completer = Completer(); - ui.PlatformDispatcher.instance.sendPlatformMessage( - 'flutter/platform', - codec.encodeMethodCall(const MethodCall( - 'Clipboard.getData', - )), - completer.complete, - ); - final ByteData? response = await completer.future; - if (response != null) { - expect( - () => codec.decodeEnvelope(response), - throwsA(isA()), - ); - } - js_util.setProperty( - domWindow.navigator, 'clipboard', originalClipboard); - }); - test('can find text scale factor', () async { const double deltaTolerance = 1e-5; diff --git a/lib/web_ui/test/engine/pointer_binding_test.dart b/lib/web_ui/test/engine/pointer_binding_test.dart index d94b34d10e816..6bba0cf5ce080 100644 --- a/lib/web_ui/test/engine/pointer_binding_test.dart +++ b/lib/web_ui/test/engine/pointer_binding_test.dart @@ -282,10 +282,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.first.identifier, equals(1)); + expect(event.changedTouches.first.client.x, equals(100)); + expect(event.changedTouches.first.client.y, equals(101)); events = expectCorrectTypes(context.multiTouchDown(const <_TouchDetails>[ _TouchDetails(pointer: 100, clientX: 120, clientY: 121), @@ -293,20 +293,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.first.identifier, equals(100)); + expect(events[0].changedTouches.first.client.x, equals(120)); + expect(events[0].changedTouches.first.client.y, equals(121)); + expect(events[0].changedTouches.elementAt(1).identifier, equals(101)); + expect(events[0].changedTouches.elementAt(1).client.x, equals(122)); + expect(events[0].changedTouches.elementAt(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.first.identifier, equals(1)); + expect(event.changedTouches.first.client.x, equals(200)); + expect(event.changedTouches.first.client.y, equals(201)); events = expectCorrectTypes(context.multiTouchMove(const <_TouchDetails>[ _TouchDetails(pointer: 102, clientX: 220, clientY: 221), @@ -314,20 +314,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.first.identifier, equals(102)); + expect(events[0].changedTouches.first.client.x, equals(220)); + expect(events[0].changedTouches.first.client.y, equals(221)); + expect(events[0].changedTouches.elementAt(1).identifier, equals(103)); + expect(events[0].changedTouches.elementAt(1).client.x, equals(222)); + expect(events[0].changedTouches.elementAt(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.first.identifier, equals(1)); + expect(event.changedTouches.first.client.x, equals(300)); + expect(event.changedTouches.first.client.y, equals(301)); events = expectCorrectTypes(context.multiTouchUp(const <_TouchDetails>[ _TouchDetails(pointer: 104, clientX: 320, clientY: 321), @@ -335,13 +335,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.first.identifier, equals(104)); + expect(events[0].changedTouches.first.client.x, equals(320)); + expect(events[0].changedTouches.first.client.y, equals(321)); + expect(events[0].changedTouches.elementAt(1).identifier, equals(105)); + expect(events[0].changedTouches.elementAt(1).client.x, equals(322)); + expect(events[0].changedTouches.elementAt(1).client.y, equals(323)); events = expectCorrectTypes(context.multiTouchCancel(const <_TouchDetails>[ _TouchDetails(pointer: 104, clientX: 320, clientY: 321), @@ -349,13 +349,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.first.identifier, equals(104)); + expect(events[0].changedTouches.first.client.x, equals(320)); + expect(events[0].changedTouches.first.client.y, equals(321)); + expect(events[0].changedTouches.elementAt(1).identifier, equals(105)); + expect(events[0].changedTouches.elementAt(1).client.x, equals(322)); + expect(events[0].changedTouches.elementAt(1).client.y, equals(323)); context.pressAllModifiers(); event = expectCorrectType(context.primaryDown(clientX: 100, clientY: 101)); @@ -3086,23 +3086,15 @@ mixin _ButtonedEventMixin on _BasicEventContext { double? wheelDeltaY, int? timeStamp, }) { - final Function jsWheelEvent = js_util.getProperty(domWindow, 'WheelEvent'); - final List eventArgs = [ - 'wheel', - { - 'buttons': buttons, - 'clientX': clientX, - 'clientY': clientY, - 'deltaX': deltaX, - 'deltaY': deltaY, - 'wheelDeltaX': wheelDeltaX, - 'wheelDeltaY': wheelDeltaY, - } - ]; - final DomEvent event = js_util.callConstructor( - jsWheelEvent, - js_util.jsify(eventArgs) as List, - ); + final DomEvent event = createDomWheelEvent('wheel', { + if (buttons != null) 'buttons': buttons, + if (clientX != null) 'clientX': clientX, + if (clientY != null) 'clientY': clientY, + if (deltaX != null) 'deltaX': deltaX, + if (deltaY != null) 'deltaY': deltaY, + if (wheelDeltaX != null) 'wheelDeltaX': wheelDeltaX, + if (wheelDeltaY != null) 'wheelDeltaY': wheelDeltaY, + }); // timeStamp can't be set in the constructor, need to override the getter. if (timeStamp != null) { js_util.callMethod( @@ -3351,26 +3343,17 @@ class _MouseEventContext extends _BasicEventContext double? clientX, double? clientY, }) { - final Function jsMouseEvent = - js_util.getProperty(domWindow, 'MouseEvent'); - final List eventArgs = [ - type, - { - 'bubbles': true, - 'buttons': buttons, - 'button': button, - 'clientX': clientX, - 'clientY': clientY, - 'altKey': altPressed, - 'ctrlKey': ctrlPressed, - 'metaKey': metaPressed, - 'shiftKey': shiftPressed, - } - ]; - return js_util.callConstructor( - jsMouseEvent, - js_util.jsify(eventArgs) as List, - ); + return createDomMouseEvent(type, { + if (buttons != null) 'buttons': buttons, + if (button != null) 'button': button, + if (clientX != null) 'clientX': clientX, + if (clientY != null) 'clientY': clientY, + 'bubbles': true, + 'altKey': altPressed, + 'ctrlKey': ctrlPressed, + 'metaKey': metaPressed, + 'shiftKey': shiftPressed, + }); } } diff --git a/lib/web_ui/test/engine/profiler_test.dart b/lib/web_ui/test/engine/profiler_test.dart index 16299147480e1..13b439d03dc2b 100644 --- a/lib/web_ui/test/engine/profiler_test.dart +++ b/lib/web_ui/test/engine/profiler_test.dart @@ -2,14 +2,16 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:js_util' as js_util; - +import 'package:js/js.dart'; import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import '../spy.dart'; +@JS('window._flutter_internal_on_benchmark') +external set onBenchmark (Object? object); + void main() { internalBootstrapBrowserTest(() => testMain); } @@ -31,7 +33,7 @@ void _profilerTests() { }); tearDown(() { - jsOnBenchmark(null); + onBenchmark = null; Profiler.isBenchmarkMode = false; }); @@ -41,9 +43,9 @@ void _profilerTests() { test('can listen to benchmarks', () { final List data = []; - jsOnBenchmark(allowInterop((String name, num value) { + onBenchmark = allowInterop((String name, num value) { data.add(BenchmarkDatapoint(name, value)); - })); + }); Profiler.instance.benchmark('foo', 123); expect(data, [BenchmarkDatapoint('foo', 123)]); @@ -55,7 +57,7 @@ void _profilerTests() { // Remove listener and make sure nothing breaks and the data isn't being // sent to the old callback anymore. - jsOnBenchmark(null); + onBenchmark = null; expect(() => Profiler.instance.benchmark('baz', 99.999), returnsNormally); expect(data, isEmpty); }); @@ -64,17 +66,20 @@ void _profilerTests() { final List data = []; // Wrong callback signature. - jsOnBenchmark(allowInterop((num value) { + onBenchmark = allowInterop((num value) { data.add(BenchmarkDatapoint('bad', value)); - })); + }); expect( () => Profiler.instance.benchmark('foo', 123), - throwsA(isA()), + + // dart2js throws a NoSuchMethodError, dart2wasm throws a TypeError here. + // Just make make sure it throws an error in this case. + throwsA(isA()), ); expect(data, isEmpty); // Not even a callback. - jsOnBenchmark('string'); + onBenchmark = 'string'; expect( () => Profiler.instance.benchmark('foo', 123), throwsA(isA()), @@ -155,11 +160,3 @@ class BenchmarkDatapoint { return '$runtimeType("$name", $value)'; } } - -void jsOnBenchmark(dynamic listener) { - js_util.setProperty( - domWindow, - '_flutter_internal_on_benchmark', - listener - ); -} diff --git a/lib/web_ui/test/engine/recording_canvas_test.dart b/lib/web_ui/test/engine/recording_canvas_test.dart index e5ae2c462afe0..46dab440bcef2 100644 --- a/lib/web_ui/test/engine/recording_canvas_test.dart +++ b/lib/web_ui/test/engine/recording_canvas_test.dart @@ -88,7 +88,28 @@ void testMain() { _expectDrawDRRectCall(mockCanvas, { 'path': - 'Path(MoveTo(10, 47) LineTo(10, 13) Conic(10, 10, 10, 13, w = 0.7071067690849304) LineTo(47, 10) Conic(50, 10, 10, 50, w = 0.7071067690849304) LineTo(50, 47) Conic(50, 50, 50, 47, w = 0.7071067690849304) LineTo(13, 50) Conic(10, 50, 50, 10, w = 0.7071067690849304) Close() MoveTo(11, 47) LineTo(11, 13) Conic(11, 11, 11, 13, w = 0.7071067690849304) LineTo(47, 11) Conic(49, 11, 11, 49, w = 0.7071067690849304) LineTo(49, 47) Conic(49, 49, 49, 47, w = 0.7071067690849304) LineTo(13, 49) Conic(11, 49, 49, 11, w = 0.7071067690849304) Close())', + 'Path(' + 'MoveTo(${10.0}, ${47.0}) ' + 'LineTo(${10.0}, ${13.0}) ' + 'Conic(${10.0}, ${10.0}, ${10.0}, ${13.0}, w = ${0.7071067690849304}) ' + 'LineTo(${47.0}, ${10.0}) ' + 'Conic(${50.0}, ${10.0}, ${10.0}, ${50.0}, w = ${0.7071067690849304}) ' + 'LineTo(${50.0}, ${47.0}) ' + 'Conic(${50.0}, ${50.0}, ${50.0}, ${47.0}, w = ${0.7071067690849304}) ' + 'LineTo(${13.0}, ${50.0}) ' + 'Conic(${10.0}, ${50.0}, ${50.0}, ${10.0}, w = ${0.7071067690849304}) ' + 'Close() ' + 'MoveTo(${11.0}, ${47.0}) ' + 'LineTo(${11.0}, ${13.0}) ' + 'Conic(${11.0}, ${11.0}, ${11.0}, ${13.0}, w = ${0.7071067690849304}) ' + 'LineTo(${47.0}, ${11.0}) ' + 'Conic(${49.0}, ${11.0}, ${11.0}, ${49.0}, w = ${0.7071067690849304}) ' + 'LineTo(${49.0}, ${47.0}) ' + 'Conic(${49.0}, ${49.0}, ${49.0}, ${47.0}, w = ${0.7071067690849304}) ' + 'LineTo(${13.0}, ${49.0}) ' + 'Conic(${11.0}, ${49.0}, ${49.0}, ${11.0}, w = ${0.7071067690849304}) ' + 'Close()' + ')', 'paint': somePaint.paintData, }); }); @@ -139,7 +160,28 @@ void testMain() { // Expect to draw, even when inner has negative radii (which get ignored by canvas) _expectDrawDRRectCall(mockCanvas, { 'path': - 'Path(MoveTo(0, 42) LineTo(0, 6) Conic(0, 0, 0, 6, w = 0.7071067690849304) LineTo(88, 0) Conic(88, 0, 0, 88, w = 0.7071067690849304) LineTo(88, 48) Conic(88, 48, 48, 88, w = 0.7071067690849304) LineTo(6, 48) Conic(0, 48, 48, 0, w = 0.7071067690849304) Close() MoveTo(1, 42) LineTo(1, 6) Conic(1, 1, 1, 6, w = 0.7071067690849304) LineTo(87, 1) Conic(87, 1, 1, 87, w = 0.7071067690849304) LineTo(87, 47) Conic(87, 47, 47, 87, w = 0.7071067690849304) LineTo(6, 47) Conic(1, 47, 47, 1, w = 0.7071067690849304) Close())', + 'Path(' + 'MoveTo(${0.0}, ${42.0}) ' + 'LineTo(${0.0}, ${6.0}) ' + 'Conic(${0.0}, ${0.0}, ${0.0}, ${6.0}, w = ${0.7071067690849304}) ' + 'LineTo(${88.0}, ${0.0}) ' + 'Conic(${88.0}, ${0.0}, ${0.0}, ${88.0}, w = ${0.7071067690849304}) ' + 'LineTo(${88.0}, ${48.0}) ' + 'Conic(${88.0}, ${48.0}, ${48.0}, ${88.0}, w = ${0.7071067690849304}) ' + 'LineTo(${6.0}, ${48.0}) ' + 'Conic(${0.0}, ${48.0}, ${48.0}, ${0.0}, w = ${0.7071067690849304}) ' + 'Close() ' + 'MoveTo(${1.0}, ${42.0}) ' + 'LineTo(${1.0}, ${6.0}) ' + 'Conic(${1.0}, ${1.0}, ${1.0}, ${6.0}, w = ${0.7071067690849304}) ' + 'LineTo(${87.0}, ${1.0}) ' + 'Conic(${87.0}, ${1.0}, ${1.0}, ${87.0}, w = ${0.7071067690849304}) ' + 'LineTo(${87.0}, ${47.0}) ' + 'Conic(${87.0}, ${47.0}, ${47.0}, ${87.0}, w = ${0.7071067690849304}) ' + 'LineTo(${6.0}, ${47.0}) ' + 'Conic(${1.0}, ${47.0}, ${47.0}, ${1.0}, w = ${0.7071067690849304}) ' + 'Close()' + ')', 'paint': somePaint.paintData, }); }); @@ -156,7 +198,18 @@ void testMain() { _expectDrawDRRectCall(mockCanvas, { 'path': - 'Path(MoveTo(10, 20) LineTo(30, 20) LineTo(30, 40) LineTo(10, 40) Close() MoveTo(12, 22) LineTo(28, 22) LineTo(28, 38) LineTo(12, 38) Close())', + 'Path(' + 'MoveTo(${10.0}, ${20.0}) ' + 'LineTo(${30.0}, ${20.0}) ' + 'LineTo(${30.0}, ${40.0}) ' + 'LineTo(${10.0}, ${40.0}) ' + 'Close() ' + 'MoveTo(${12.0}, ${22.0}) ' + 'LineTo(${28.0}, ${22.0}) ' + 'LineTo(${28.0}, ${38.0}) ' + 'LineTo(${12.0}, ${38.0}) ' + 'Close()' + ')', 'paint': somePaint.paintData, }); }); diff --git a/lib/web_ui/test/engine/semantics/semantics_test.dart b/lib/web_ui/test/engine/semantics/semantics_test.dart index e35d5f6e40dc1..76708d98ad187 100644 --- a/lib/web_ui/test/engine/semantics/semantics_test.dart +++ b/lib/web_ui/test/engine/semantics/semantics_test.dart @@ -996,7 +996,7 @@ void _testVerticalScrolling() { expect(scrollable.scrollTop >= (10 - browserMaxScrollDiff), isTrue); semantics().semanticsEnabled = false; - }); + }, skip: isWasm); // https://github.com/dart-lang/sdk/issues/50778 } void _testHorizontalScrolling() { @@ -1129,7 +1129,7 @@ void _testHorizontalScrolling() { expect(scrollable.scrollLeft >= (10 - browserMaxScrollDiff), isTrue); semantics().semanticsEnabled = false; - }); + }, skip: isWasm); // https://github.com/dart-lang/sdk/issues/50778 } void _testIncrementables() { diff --git a/lib/web_ui/test/engine/semantics/text_field_test.dart b/lib/web_ui/test/engine/semantics/text_field_test.dart index 183520433724c..c7dd2805cbdfa 100644 --- a/lib/web_ui/test/engine/semantics/text_field_test.dart +++ b/lib/web_ui/test/engine/semantics/text_field_test.dart @@ -7,7 +7,6 @@ import 'dart:typed_data'; import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; - import 'package:ui/src/engine.dart' hide window; import 'package:ui/ui.dart' as ui; @@ -367,7 +366,6 @@ void testMain() { width: 13, globalTransform: Matrix4.translationValues(14, 15, 0).storage, ); - const ui.Rect semanticsRect = ui.Rect.fromLTRB(0, 0, 100, 50); testTextEditing.acceptCommand( TextInputSetEditableSizeAndTransform(geometry: geometry), @@ -383,8 +381,8 @@ void testMain() { // EditableTextGeometry. void checkPlacementIsSetBySemantics() { expect(strategy.activeDomElement.style.transform, ''); - expect(strategy.activeDomElement.style.width, '${semanticsRect.width}px'); - expect(strategy.activeDomElement.style.height, '${semanticsRect.height}px'); + expect(strategy.activeDomElement.style.width, '100px'); + expect(strategy.activeDomElement.style.height, '50px'); } checkPlacementIsSetBySemantics(); diff --git a/lib/web_ui/test/engine/ulps_test.dart b/lib/web_ui/test/engine/ulps_test.dart deleted file mode 100644 index 8970225ddb6b6..0000000000000 --- a/lib/web_ui/test/engine/ulps_test.dart +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'dart:typed_data'; -import 'package:test/bootstrap/browser.dart'; -import 'package:test/test.dart'; -import 'package:ui/src/engine/ulps.dart'; - -void main() { - internalBootstrapBrowserTest(() => testMain); -} - -void testMain() { - group('Float Int conversions', (){ - test("Should convert signbit to 2's compliment", () { - expect(signBitTo2sCompliment(0), 0); - expect(signBitTo2sCompliment(0x7fffffff).toUnsigned(32), 0x7fffffff); - expect(signBitTo2sCompliment(0x80000000), 0); - expect(signBitTo2sCompliment(0x8f000000).toUnsigned(32), 0xf1000000); - expect(signBitTo2sCompliment(0x8fffffff).toUnsigned(32), 0xf0000001); - expect(signBitTo2sCompliment(0xffffffff).toUnsigned(32), 0x80000001); - expect(signBitTo2sCompliment(0x8f000000), -251658240); - expect(signBitTo2sCompliment(0x8fffffff), -268435455); - expect(signBitTo2sCompliment(0xffffffff), -2147483647); - }); - - test('Should convert 2s compliment to signbit', () { - expect(twosComplimentToSignBit(0), 0); - expect(twosComplimentToSignBit(0x7fffffff), 0x7fffffff); - expect(twosComplimentToSignBit(0), 0); - expect(twosComplimentToSignBit(0xf1000000).toRadixString(16), 0x8f000000.toRadixString(16)); - expect(twosComplimentToSignBit(0xf0000001), 0x8fffffff); - expect(twosComplimentToSignBit(0x80000001), 0xffffffff); - expect(twosComplimentToSignBit(0x81234561), 0xfedcba9f); - expect(twosComplimentToSignBit(-5), 0x80000005); - }); - - test('Should convert float to bits', () { - final Float32List floatList = Float32List(1); - floatList[0] = 0; - expect(float2Bits(floatList, 0), 0); - floatList[0] = 0.1; - expect(float2Bits(floatList, 0).toUnsigned(32).toRadixString(16), 0x3dcccccd.toRadixString(16)); - floatList[0] = 123456.0; - expect(float2Bits(floatList, 0).toUnsigned(32).toRadixString(16), 0x47f12000.toRadixString(16)); - floatList[0] = -0.1; - expect(float2Bits(floatList, 0).toUnsigned(32).toRadixString(16), 0xbdcccccd.toRadixString(16)); - floatList[0] = -123456.0; - expect(float2Bits(floatList, 0).toUnsigned(32).toRadixString(16), 0xc7f12000.toRadixString(16)); - }); - }); - group('Comparison', () { - test('Should compare equality based on ulps', () { - // If number of floats between a=1.1 and b are below 16, equals should - // return true. - const double a = 1.1; - final int aBits = floatAs2sCompliment(a); - double b = twosComplimentAsFloat(aBits + 1); - expect(almostEqualUlps(a, b), isTrue); - b = twosComplimentAsFloat(aBits + 15); - expect(almostEqualUlps(a, b), isTrue); - b = twosComplimentAsFloat(aBits + 16); - expect(almostEqualUlps(a, b), isFalse); - - // Test between variant of equalUlps. - b = twosComplimentAsFloat(aBits + 1); - expect(almostBequalUlps(a, b), isTrue); - b = twosComplimentAsFloat(aBits + 1); - expect(almostBequalUlps(a, b), isTrue); - b = twosComplimentAsFloat(aBits + 2); - expect(almostBequalUlps(a, b), isFalse); - }); - - test('Should compare 2 coordinates based on ulps', () { - double a = 1.1; - int aBits = floatAs2sCompliment(a); - double b = twosComplimentAsFloat(aBits + 1); - expect(approximatelyEqual(5.0, a, 5.0, b), isTrue); - b = twosComplimentAsFloat(aBits + 16); - expect(approximatelyEqual(5.0, a, 5.0, b), isTrue); - - // Increase magnitude which should start checking with ulps rather than - // fltEpsilon. - a = 3000000.1; - aBits = floatAs2sCompliment(a); - b = twosComplimentAsFloat(aBits + 1); - expect(approximatelyEqual(5.0, a, 5.0, b), isTrue); - b = twosComplimentAsFloat(aBits + 16); - expect(approximatelyEqual(5.0, a, 5.0, b), isFalse); - }); - }); -} diff --git a/lib/web_ui/test/engine/view_embedder/embedding_strategy/embedding_strategy_test.dart b/lib/web_ui/test/engine/view_embedder/embedding_strategy/embedding_strategy_test.dart index d17c1e54c48cb..4aaab90e44615 100644 --- a/lib/web_ui/test/engine/view_embedder/embedding_strategy/embedding_strategy_test.dart +++ b/lib/web_ui/test/engine/view_embedder/embedding_strategy/embedding_strategy_test.dart @@ -10,8 +10,7 @@ import 'package:ui/src/engine/dom.dart'; import 'package:ui/src/engine/view_embedder/embedding_strategy/custom_element_embedding_strategy.dart'; import 'package:ui/src/engine/view_embedder/embedding_strategy/embedding_strategy.dart'; import 'package:ui/src/engine/view_embedder/embedding_strategy/full_page_embedding_strategy.dart'; - -import '../hot_restart_cache_handler_test.dart' show getDomCache; +import 'package:ui/src/engine/view_embedder/hot_restart_cache_handler.dart'; void main() { internalBootstrapBrowserTest(() => doTests); @@ -48,7 +47,7 @@ void doTests() { strategy.registerElementForCleanup(other); strategy.registerElementForCleanup(another); - final List cache = getDomCache()!; + final List cache = hotRestartStore!; expect(cache, hasLength(3)); expect(cache.first, toBeCached); diff --git a/lib/web_ui/test/engine/view_embedder/hot_restart_cache_handler_test.dart b/lib/web_ui/test/engine/view_embedder/hot_restart_cache_handler_test.dart index 6ebc7134087a7..939c8027510cd 100644 --- a/lib/web_ui/test/engine/view_embedder/hot_restart_cache_handler_test.dart +++ b/lib/web_ui/test/engine/view_embedder/hot_restart_cache_handler_test.dart @@ -4,8 +4,6 @@ @TestOn('browser') -import 'package:js/js_util.dart'; - import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/src/engine/dom.dart'; @@ -22,7 +20,7 @@ void doTests() { expect(cache, isNotNull); - final List? domCache = getDomCache(); + final List? domCache = hotRestartStore; expect(domCache, isNotNull); expect(domCache, isEmpty); @@ -31,17 +29,16 @@ void doTests() { group('registerElement', () { HotRestartCacheHandler? cache; - List? domCache; setUp(() { cache = HotRestartCacheHandler(); - domCache = getDomCache(); }); test('Registers an element in the DOM cache', () async { final DomElement element = createDomElement('for-test'); cache!.registerElement(element); + final List? domCache = hotRestartStore; expect(domCache, hasLength(1)); expect(domCache!.last, element); }); @@ -52,6 +49,7 @@ void doTests() { cache!.registerElement(element); + final List? domCache = hotRestartStore; expect(domCache, hasLength(1)); expect(domCache!.last, element); }); @@ -71,12 +69,10 @@ void doTests() { // Simulate a hot restart... cache = HotRestartCacheHandler(); + final List? domCache = hotRestartStore; expect(domCache, hasLength(0)); expect(element.isConnected, isFalse); // Removed expect(element2.isConnected, isTrue); }); }); } - -List? getDomCache() => getProperty?>( - domWindow, HotRestartCacheHandler.defaultCacheName); diff --git a/lib/web_ui/test/engine/window_test.dart b/lib/web_ui/test/engine/window_test.dart index a696fd6c33ba8..623f141510352 100644 --- a/lib/web_ui/test/engine/window_test.dart +++ b/lib/web_ui/test/engine/window_test.dart @@ -332,11 +332,11 @@ Future testMain() async { 'orientation': { 'lock': allowInterop((String lockType) { lockCalls.add(lockType); - return JsPromise(allowInterop((Function(Object? value) resolve, Function reject) { + return Promise(allowInterop((PromiseResolver resolve, PromiseRejecter reject) { if (!simulateError) { - resolve(null); + resolve.resolve(null); } else { - reject('Simulating error'); + reject.reject('Simulating error'); } })); }), diff --git a/lib/web_ui/test/gesture_settings_test.dart b/lib/web_ui/test/gesture_settings_test.dart index 21e896edb2df3..c86414e13c066 100644 --- a/lib/web_ui/test/gesture_settings_test.dart +++ b/lib/web_ui/test/gesture_settings_test.dart @@ -13,10 +13,10 @@ void main() { void testMain() { test('GestureSettings has a reasonable toString', () { const GestureSettings gestureSettings = - GestureSettings(physicalDoubleTapSlop: 2.0, physicalTouchSlop: 1.0); + GestureSettings(physicalDoubleTapSlop: 2.5, physicalTouchSlop: 1.5); expect(gestureSettings.toString(), - 'GestureSettings(physicalTouchSlop: 1, physicalDoubleTapSlop: 2)'); + 'GestureSettings(physicalTouchSlop: 1.5, physicalDoubleTapSlop: 2.5)'); }); test('GestureSettings has a correct equality', () { diff --git a/lib/web_ui/test/hash_codes_test.dart b/lib/web_ui/test/hash_codes_test.dart index 7f56a727b6811..7e34ed20db30d 100644 --- a/lib/web_ui/test/hash_codes_test.dart +++ b/lib/web_ui/test/hash_codes_test.dart @@ -17,63 +17,32 @@ void main() { } void testMain() { - test('hashValues can hash lots of huge values effectively', () { - expect( - hashValues( - _kBiggestExactJavaScriptInt, - _kBiggestExactJavaScriptInt, - _kBiggestExactJavaScriptInt, - _kBiggestExactJavaScriptInt, - _kBiggestExactJavaScriptInt, - _kBiggestExactJavaScriptInt, - _kBiggestExactJavaScriptInt, - _kBiggestExactJavaScriptInt, - _kBiggestExactJavaScriptInt, - _kBiggestExactJavaScriptInt, - _kBiggestExactJavaScriptInt, - _kBiggestExactJavaScriptInt, - _kBiggestExactJavaScriptInt, - _kBiggestExactJavaScriptInt, - _kBiggestExactJavaScriptInt, - _kBiggestExactJavaScriptInt, - _kBiggestExactJavaScriptInt, - _kBiggestExactJavaScriptInt, - _kBiggestExactJavaScriptInt, - _kBiggestExactJavaScriptInt, - ), - 496984395, + test('hashValues and hashList can hash lots of huge values effectively', () { + final int hashValueFromArgs = hashValues( + _kBiggestExactJavaScriptInt, + _kBiggestExactJavaScriptInt, + _kBiggestExactJavaScriptInt, + _kBiggestExactJavaScriptInt, + _kBiggestExactJavaScriptInt, + _kBiggestExactJavaScriptInt, + _kBiggestExactJavaScriptInt, + _kBiggestExactJavaScriptInt, + _kBiggestExactJavaScriptInt, + _kBiggestExactJavaScriptInt, + _kBiggestExactJavaScriptInt, + _kBiggestExactJavaScriptInt, + _kBiggestExactJavaScriptInt, + _kBiggestExactJavaScriptInt, + _kBiggestExactJavaScriptInt, + _kBiggestExactJavaScriptInt, + _kBiggestExactJavaScriptInt, + _kBiggestExactJavaScriptInt, + _kBiggestExactJavaScriptInt, + _kBiggestExactJavaScriptInt, ); - // Hash a slightly smaller number to verify that the hash code is different. - expect( - hashValues( - _kBiggestExactJavaScriptInt, - _kBiggestExactJavaScriptInt, - _kBiggestExactJavaScriptInt, - _kBiggestExactJavaScriptInt, - _kBiggestExactJavaScriptInt, - _kBiggestExactJavaScriptInt, - _kBiggestExactJavaScriptInt, - _kBiggestExactJavaScriptInt, - _kBiggestExactJavaScriptInt, - _kBiggestExactJavaScriptInt, - _kBiggestExactJavaScriptInt, - _kBiggestExactJavaScriptInt, - _kBiggestExactJavaScriptInt, - _kBiggestExactJavaScriptInt, - _kBiggestExactJavaScriptInt, - _kBiggestExactJavaScriptInt, - _kBiggestExactJavaScriptInt, - _kBiggestExactJavaScriptInt, - _kBiggestExactJavaScriptInt, - _kBiggestExactJavaScriptInt - 1, - ), - 455584273, - ); - }); - test('hashList can hash lots of huge values effectively', () { - expect( - hashList([ + // Hash the same values via a list + final int hashValueFromList = hashList([ _kBiggestExactJavaScriptInt, _kBiggestExactJavaScriptInt, _kBiggestExactJavaScriptInt, @@ -94,12 +63,33 @@ void testMain() { _kBiggestExactJavaScriptInt, _kBiggestExactJavaScriptInt, _kBiggestExactJavaScriptInt, - ]), - 496984395, - ); + ]); + // Hash a slightly smaller number to verify that the hash code is different. - expect( - hashList([ + final int slightlyDifferentHashValueFromArgs = hashValues( + _kBiggestExactJavaScriptInt, + _kBiggestExactJavaScriptInt, + _kBiggestExactJavaScriptInt, + _kBiggestExactJavaScriptInt, + _kBiggestExactJavaScriptInt, + _kBiggestExactJavaScriptInt, + _kBiggestExactJavaScriptInt, + _kBiggestExactJavaScriptInt, + _kBiggestExactJavaScriptInt, + _kBiggestExactJavaScriptInt, + _kBiggestExactJavaScriptInt, + _kBiggestExactJavaScriptInt, + _kBiggestExactJavaScriptInt, + _kBiggestExactJavaScriptInt, + _kBiggestExactJavaScriptInt, + _kBiggestExactJavaScriptInt, + _kBiggestExactJavaScriptInt, + _kBiggestExactJavaScriptInt, + _kBiggestExactJavaScriptInt, + _kBiggestExactJavaScriptInt - 1, + ); + + final int slightlyDifferentHashValueFromList = hashList([ _kBiggestExactJavaScriptInt, _kBiggestExactJavaScriptInt, _kBiggestExactJavaScriptInt, @@ -120,8 +110,10 @@ void testMain() { _kBiggestExactJavaScriptInt, _kBiggestExactJavaScriptInt, _kBiggestExactJavaScriptInt - 1, - ]), - 455584273, - ); + ]); + + expect(hashValueFromArgs, equals(hashValueFromList)); + expect(slightlyDifferentHashValueFromArgs, equals(slightlyDifferentHashValueFromList)); + expect(hashValueFromArgs, isNot(equals(slightlyDifferentHashValueFromArgs))); }); } diff --git a/lib/web_ui/test/html/image_test.dart b/lib/web_ui/test/html/image_test.dart index c7c7049987889..bd8883fc4e398 100644 --- a/lib/web_ui/test/html/image_test.dart +++ b/lib/web_ui/test/html/image_test.dart @@ -35,14 +35,15 @@ Matcher listEqual(List source, {int tolerance = 0}) { // Each element of `rawPixels` represents a bytes in order 0xRRGGBBAA, with // pixel order Left to right, then top to bottom. Uint8List _pixelsToBytes(List rawPixels) { - return Uint8List.fromList((() sync* { - for (final int pixel in rawPixels) { - yield (pixel >> 24) & 0xff; // r - yield (pixel >> 16) & 0xff; // g - yield (pixel >> 8) & 0xff; // b - yield (pixel >> 0) & 0xff; // a - } - })().toList()); + return Uint8List.fromList([ + for (final int pixel in rawPixels) + ...[ + (pixel >> 24) & 0xff, // r + (pixel >> 16) & 0xff, // g + (pixel >> 8) & 0xff, // b + (pixel >> 0) & 0xff, // a + ] + ]); } Future _encodeToHtmlThenDecode( diff --git a/lib/web_ui/test/raw_keyboard_test.dart b/lib/web_ui/test/raw_keyboard_test.dart index 0f137ff42df95..1cfae7fe706f0 100644 --- a/lib/web_ui/test/raw_keyboard_test.dart +++ b/lib/web_ui/test/raw_keyboard_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. -import 'dart:js_util' as js_util; import 'dart:typed_data'; import 'package:quiver/testing/async.dart'; @@ -748,29 +747,20 @@ DomKeyboardEvent dispatchKeyboardEvent( }) { target ??= domWindow; - final Function jsKeyboardEvent = - js_util.getProperty(domWindow, 'KeyboardEvent'); - final List eventArgs = [ - type, - { - 'key': key, - 'code': code, - 'location': location, - 'repeat': repeat, - 'shiftKey': isShiftPressed, - 'altKey': isAltPressed, - 'ctrlKey': isControlPressed, - 'metaKey': isMetaPressed, - 'isComposing': isComposing, - 'keyCode': keyCode, - 'bubbles': true, - 'cancelable': true, - } - ]; - final DomKeyboardEvent event = js_util.callConstructor( - jsKeyboardEvent, - js_util.jsify(eventArgs) as List, - ); + final DomKeyboardEvent event = createDomKeyboardEvent(type, { + if (key != null) 'key': key, + if (code != null) 'code': code, + 'location': location, + 'repeat': repeat, + 'shiftKey': isShiftPressed, + 'altKey': isAltPressed, + 'ctrlKey': isControlPressed, + 'metaKey': isMetaPressed, + 'isComposing': isComposing, + 'keyCode': keyCode, + 'bubbles': true, + 'cancelable': true, + }); target.dispatchEvent(event); return event; diff --git a/lib/web_ui/test/skwasm/smoke_test.dart b/lib/web_ui/test/skwasm/smoke_test.dart index 74c5a30ad7ab9..103af64316d40 100644 --- a/lib/web_ui/test/skwasm/smoke_test.dart +++ b/lib/web_ui/test/skwasm/smoke_test.dart @@ -8,6 +8,7 @@ import 'dart:async'; import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; +import 'package:ui/src/engine/browser_detection.dart'; import 'package:ui/src/engine/renderer.dart'; import 'package:ui/src/engine/skwasm/skwasm_stub/renderer.dart'; @@ -22,6 +23,8 @@ Future testMain() async { expect(() { renderer.initialize(); }, throwsUnimplementedError); - }); + }, skip: isWasm); + // This test is specifically designed for the JS case, to make sure we + // compile to the skwasm stub renderer. }); } diff --git a/lib/web_ui/test/text_editing_test.dart b/lib/web_ui/test/text_editing_test.dart index 5a174483ad9a2..30d669bf5801c 100644 --- a/lib/web_ui/test/text_editing_test.dart +++ b/lib/web_ui/test/text_editing_test.dart @@ -1343,10 +1343,11 @@ Future testMain() async { checkInputEditingState(domElement, 'abcd', 2, 3); // Check if the location and styling is correct. - expect( - domElement.getBoundingClientRect(), - createDomRectFromPoints(DomPoint(10.0, 20.0), - DomPoint(160.0, 70.0))); + final DomRect boundingRect = domElement.getBoundingClientRect(); + expect(boundingRect.left, 10.0); + expect(boundingRect.top, 20.0); + expect(boundingRect.right, 160.0); + expect(boundingRect.bottom, 70.0); expect(domElement.style.transform, 'matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 10, 20, 30, 1)'); expect(textEditing!.strategy.domElement!.style.font, @@ -1403,11 +1404,11 @@ Future testMain() async { checkInputEditingState(domElement, 'abcd', 2, 3); // Check if the position is correct. - expect( - domElement.getBoundingClientRect(), - createDomRectFromPoints( - DomPoint(10.0, 20.0), DomPoint(160.0, 70.0)), - ); + final DomRect boundingRect = domElement.getBoundingClientRect(); + expect(boundingRect.left, 10.0); + expect(boundingRect.top, 20.0); + expect(boundingRect.right, 160.0); + expect(boundingRect.bottom, 70.0); expect( domElement.style.transform, 'matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 10, 20, 30, 1)', @@ -1464,10 +1465,11 @@ Future testMain() async { checkInputEditingState(domElement, 'abcd', 2, 3); // Check if the location and styling is correct. - expect( - domElement.getBoundingClientRect(), - createDomRectFromPoints(DomPoint(10.0, 20.0), - DomPoint(160.0, 70.0))); + final DomRect boundingRect = domElement.getBoundingClientRect(); + expect(boundingRect.left, 10.0); + expect(boundingRect.top, 20.0); + expect(boundingRect.right, 160.0); + expect(boundingRect.bottom, 70.0); expect(domElement.style.transform, 'matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 10, 20, 30, 1)'); expect( @@ -2589,17 +2591,17 @@ DomKeyboardEvent dispatchKeyboardEvent( String type, { required int keyCode, }) { - final Function jsKeyboardEvent = js_util.getProperty(domWindow, 'KeyboardEvent'); + final Object jsKeyboardEvent = js_util.getProperty(domWindow, 'KeyboardEvent'); final List eventArgs = [ type, - { + js_util.jsify({ 'keyCode': keyCode, 'cancelable': true, - } + }), ]; final DomKeyboardEvent event = js_util.callConstructor( jsKeyboardEvent, - js_util.jsify(eventArgs) as List?, + eventArgs, ); target.dispatchEvent(event); diff --git a/lib/web_ui/test/window_test.dart b/lib/web_ui/test/window_test.dart index 775fa994f6887..01c4eaae7a377 100644 --- a/lib/web_ui/test/window_test.dart +++ b/lib/web_ui/test/window_test.dart @@ -46,7 +46,7 @@ void testMain() { final JsUrlStrategy jsUrlStrategy = JsUrlStrategy( getPath: allowInterop(() => '/initial'), getState: allowInterop(() => state), - addPopStateListener: allowInterop((DomEventListener listener) => () {}), + addPopStateListener: allowInterop((DomEventListener listener) => allowInterop(() {})), prepareExternalUrl: allowInterop((String value) => ''), pushState: allowInterop((Object? newState, String title, String url) { expect(newState is Map, true); @@ -55,7 +55,7 @@ void testMain() { expect(newState is Map, true); state = newState; }), - go: allowInterop(([int? delta]) async { + go: allowInterop(([double? delta]) async { expect(delta, -1); })); final CustomUrlStrategy strategy =