From 4e7c927e07008950c5864ad6281d9e4ca5880efe Mon Sep 17 00:00:00 2001 From: Jackson Gardner Date: Fri, 14 Apr 2023 17:32:15 -0700 Subject: [PATCH 01/30] Started skwasm fonts implementation. --- .../lib/src/engine/canvaskit/fonts.dart | 27 ++----- lib/web_ui/lib/src/engine/fonts.dart | 71 ++++++++++++++++++- .../lib/src/engine/skwasm/skwasm_impl.dart | 3 + .../skwasm/skwasm_impl/font_collection.dart | 27 ++++++- .../skwasm/skwasm_impl/raw/raw_fonts.dart | 30 ++++++++ .../skwasm/skwasm_impl/raw/raw_shaders.dart | 24 ------- .../skwasm/skwasm_impl/raw/raw_skdata.dart | 20 ++++++ .../skwasm/skwasm_impl/raw/raw_skstring.dart | 20 ++++++ .../engine/skwasm/skwasm_impl/shaders.dart | 12 ++-- .../lib/src/engine/text/font_collection.dart | 40 ++--------- lib/web_ui/skwasm/BUILD.gn | 8 ++- lib/web_ui/skwasm/canvas.cpp | 1 - lib/web_ui/skwasm/contour_measure.cpp | 1 - lib/web_ui/skwasm/data.cpp | 19 +++++ lib/web_ui/skwasm/export.h | 2 + lib/web_ui/skwasm/fonts.cpp | 44 ++++++++++++ lib/web_ui/skwasm/paint.cpp | 1 - lib/web_ui/skwasm/path.cpp | 1 - lib/web_ui/skwasm/picture.cpp | 1 - lib/web_ui/skwasm/shaders.cpp | 25 ------- lib/web_ui/skwasm/string.cpp | 19 +++++ third_party/canvaskit/BUILD.gn | 10 ++- 22 files changed, 285 insertions(+), 121 deletions(-) create mode 100644 lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_fonts.dart create mode 100644 lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_skdata.dart create mode 100644 lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_skstring.dart create mode 100644 lib/web_ui/skwasm/data.cpp create mode 100644 lib/web_ui/skwasm/fonts.cpp create mode 100644 lib/web_ui/skwasm/string.cpp diff --git a/lib/web_ui/lib/src/engine/canvaskit/fonts.dart b/lib/web_ui/lib/src/engine/canvaskit/fonts.dart index 86c5ab5e2edf7..646ff207fe06b 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/fonts.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/fonts.dart @@ -3,7 +3,6 @@ // found in the LICENSE file. import 'dart:async'; -import 'dart:convert'; import 'dart:typed_data'; import 'package:web_test_fonts/web_test_fonts.dart'; @@ -100,30 +99,12 @@ class SkiaFontCollection implements FlutterFontCollection { /// Loads fonts from `FontManifest.json`. @override Future downloadAssetFonts(AssetManager assetManager) async { - final HttpFetchResponse response = await assetManager.loadAsset('FontManifest.json'); - - if (!response.hasPayload) { - printWarning('Font manifest does not exist at `${response.url}` - ignoring.'); - return; - } - - final Uint8List data = await response.asUint8List(); - final List? fontManifest = json.decode(utf8.decode(data)) as List?; - if (fontManifest == null) { - throw AssertionError( - 'There was a problem trying to load FontManifest.json'); - } - + final FontManifest manifest = await fetchFontManifest(); final List> pendingFonts = >[]; - for (final Map fontFamily - in fontManifest.cast>()) { - final String family = fontFamily.readString('family'); - final List fontAssets = fontFamily.readList('fonts'); - for (final dynamic fontAssetItem in fontAssets) { - final Map fontAsset = fontAssetItem as Map; - final String asset = fontAsset.readString('asset'); - _downloadFont(pendingFonts, assetManager.getAssetUrl(asset), family); + for (final FontFamily family in manifest.families) { + for (final FontAsset fontAsset in family.fontAssets) { + _downloadFont(pendingFonts, assetManager.getAssetUrl(fontAsset.asset), family.name); } } diff --git a/lib/web_ui/lib/src/engine/fonts.dart b/lib/web_ui/lib/src/engine/fonts.dart index cf3b60f6e9319..b45d816fcb5a0 100644 --- a/lib/web_ui/lib/src/engine/fonts.dart +++ b/lib/web_ui/lib/src/engine/fonts.dart @@ -3,9 +3,78 @@ // found in the LICENSE file. import 'dart:async'; +import 'dart:convert'; +import 'dart:js_interop'; import 'dart:typed_data'; -import 'assets.dart'; +import 'package:ui/src/engine.dart'; + +class FontAsset { + FontAsset(this.asset, this.descriptors); + + String asset; + Map descriptors; +} + +class FontFamily { + FontFamily(this.name, this.fontAssets); + + String name; + List fontAssets; +} + +class FontManifest { + FontManifest(this.families); + + List families; +} + +Future fetchFontManifest() async { + final HttpFetchResponse response = await assetManager.loadAsset('FontManifest.json'); + if (!response.hasPayload) { + printWarning('Font manifest does not exist at `${response.url}` - ignoring.'); + return FontManifest([]); + } + + final Converter, Object?> decoder = const Utf8Decoder().fuse(const JsonDecoder()); + Object? fontManifestJson; + final Sink> inputSink = decoder.startChunkedConversion( + ChunkedConversionSink.withCallback( + (List accumulated) { + if (accumulated.length != 1) { + throw AssertionError('There was a problem trying to load FontManifest.json'); + } + fontManifestJson = accumulated.first; + } + )); + await response.read((JSUint8Array chunk) => inputSink.add(chunk.toDart)); + inputSink.close(); + if (fontManifestJson == null) { + throw AssertionError('There was a problem trying to load FontManifest.json'); + } + final List families = (fontManifestJson! as List).map( + (dynamic fontFamilyJson) { + final Map fontFamily = fontFamilyJson as Map; + final String familyName = fontFamily.readString('family'); + final List fontAssets = fontFamily.readList('fonts'); + return FontFamily(familyName, fontAssets.map((dynamic fontAssetJson) { + String? asset; + final Map descriptors = {}; + for (final MapEntry descriptor in (fontAssetJson as Map).entries) { + if (descriptor.key == 'asset') { + asset = descriptor.value as String; + } else { + descriptors[descriptor.key] = descriptor.value as String; + } + } + if (asset == null) { + throw AssertionError("Invalid Font manifest, missing 'asset' key on font."); + } + return FontAsset(asset, descriptors); + }).toList()); + }).toList(); + return FontManifest(families); +} abstract class FlutterFontCollection { diff --git a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl.dart b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl.dart index 9d489df3ab489..535144f44a9a0 100644 --- a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl.dart +++ b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl.dart @@ -20,6 +20,7 @@ export 'skwasm_impl/path_metrics.dart'; export 'skwasm_impl/picture.dart'; export 'skwasm_impl/raw/js_functions.dart'; export 'skwasm_impl/raw/raw_canvas.dart'; +export 'skwasm_impl/raw/raw_fonts.dart'; export 'skwasm_impl/raw/raw_geometry.dart'; export 'skwasm_impl/raw/raw_memory.dart'; export 'skwasm_impl/raw/raw_paint.dart'; @@ -27,6 +28,8 @@ export 'skwasm_impl/raw/raw_path.dart'; export 'skwasm_impl/raw/raw_path_metrics.dart'; export 'skwasm_impl/raw/raw_picture.dart'; export 'skwasm_impl/raw/raw_shaders.dart'; +export 'skwasm_impl/raw/raw_skdata.dart'; +export 'skwasm_impl/raw/raw_skstring.dart'; export 'skwasm_impl/raw/raw_surface.dart'; export 'skwasm_impl/renderer.dart'; export 'skwasm_impl/scene_builder.dart'; diff --git a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/font_collection.dart b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/font_collection.dart index 0d3a2612988ff..3a77da54176cf 100644 --- a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/font_collection.dart +++ b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/font_collection.dart @@ -3,12 +3,19 @@ // found in the LICENSE file. import 'dart:async'; +import 'dart:convert'; +import 'dart:ffi'; import 'dart:typed_data'; import 'package:ui/src/engine.dart'; +import 'package:ui/src/engine/skwasm/skwasm_impl.dart'; class SkwasmFontCollection implements FlutterFontCollection { + SkwasmFontCollection() : _handle = fontCollectionCreate(); + + final FontCollectionHandle _handle; + @override void clear() { // TODO(jacksongardner): implement clear @@ -21,12 +28,28 @@ class SkwasmFontCollection implements FlutterFontCollection { @override Future downloadAssetFonts(AssetManager assetManager) async { - // TODO(jacksongardner): implement downloadAssetFonts } @override Future loadFontFromList(Uint8List list, {String? fontFamily}) async { - // TODO(jacksongardner): implement loadFontFromList + final SkDataHandle dataHandle = skDataCreate(list.length); + final Pointer dataPointer = skDataGetPointer(dataHandle).cast(); + for (int i = 0; i < list.length; i++) { + dataPointer[i] = list[i]; + } + if (fontFamily != null) { + final List rawUtf8Bytes = utf8.encode(fontFamily); + final SkStringHandle stringHandle = skStringAllocate(rawUtf8Bytes.length); + final Pointer stringDataPointer = skStringGetData(stringHandle); + for (int i = 0; i < rawUtf8Bytes.length; i++) { + stringDataPointer[i] = rawUtf8Bytes[i]; + } + fontCollectionRegisterFont(_handle, dataHandle, stringHandle); + skStringFree(stringHandle); + } else { + fontCollectionRegisterFont(_handle, dataHandle, nullptr); + } + skDataDispose(dataHandle); } @override diff --git a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_fonts.dart b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_fonts.dart new file mode 100644 index 0000000000000..40b03450a5188 --- /dev/null +++ b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_fonts.dart @@ -0,0 +1,30 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@DefaultAsset('skwasm') +library skwasm_impl; + +import 'dart:ffi'; + +import 'package:ui/src/engine/skwasm/skwasm_impl.dart'; + +final class RawFontCollection extends Opaque {} +typedef FontCollectionHandle = Pointer; + +@Native(symbol: 'fontCollection_create', isLeaf: true) +external FontCollectionHandle fontCollectionCreate(); + +@Native(symbol: 'fontCollection_dispose', isLeaf: true) +external void fontCollectionDispose(FontCollectionHandle handle); + +@Native(symbol: 'fontCollection_registerFont', isLeaf: true) +external void fontCollectionRegisterFont( + FontCollectionHandle handle, + SkDataHandle fontData, + SkStringHandle fontName, +); diff --git a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_shaders.dart b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_shaders.dart index beadca256a28d..a999ddad28b30 100644 --- a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_shaders.dart +++ b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_shaders.dart @@ -12,12 +12,6 @@ import 'package:ui/src/engine/skwasm/skwasm_impl.dart'; final class RawShader extends Opaque {} typedef ShaderHandle = Pointer; -final class RawSkString extends Opaque {} -typedef SkStringHandle = Pointer; - -final class RawSkData extends Opaque {} -typedef SkDataHandle = Pointer; - final class RawRuntimeEffect extends Opaque {} typedef RuntimeEffectHandle = Pointer; @@ -106,15 +100,6 @@ external ShaderHandle shaderCreateSweepGradient( @Native(symbol: 'shader_dispose', isLeaf: true) external void shaderDispose(ShaderHandle handle); -@Native(symbol: 'shaderSource_allocate', isLeaf: true) -external SkStringHandle shaderSourceAllocate(int size); - -@Native Function(SkStringHandle)>(symbol: 'shaderSource_getData', isLeaf: true) -external Pointer shaderSourceGetData(SkStringHandle handle); - -@Native(symbol: 'shaderSource_free', isLeaf: true) -external void shaderSourceFree(SkStringHandle handle); - @Native(symbol: 'runtimeEffect_create', isLeaf: true) external RuntimeEffectHandle runtimeEffectCreate(SkStringHandle source); @@ -124,15 +109,6 @@ external void runtimeEffectDispose(RuntimeEffectHandle handle); @Native(symbol: 'runtimeEffect_getUniformSize', isLeaf: true) external int runtimeEffectGetUniformSize(RuntimeEffectHandle handle); -@Native(symbol: 'data_create', isLeaf: true) -external SkDataHandle dataCreate(int size); - -@Native Function(SkDataHandle)>(symbol: 'data_getPointer', isLeaf: true) -external Pointer dataGetPointer(SkDataHandle handle); - -@Native(symbol: 'data_dispose', isLeaf: true) -external void dataDispose(SkDataHandle handle); - @Native; + +@Native(symbol: 'skData_create', isLeaf: true) +external SkDataHandle skDataCreate(int size); + +@Native Function(SkDataHandle)>(symbol: 'skData_getPointer', isLeaf: true) +external Pointer skDataGetPointer(SkDataHandle handle); + +@Native(symbol: 'skData_dispose', isLeaf: true) +external void skDataDispose(SkDataHandle handle); diff --git a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_skstring.dart b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_skstring.dart new file mode 100644 index 0000000000000..1b5af811542ad --- /dev/null +++ b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_skstring.dart @@ -0,0 +1,20 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@DefaultAsset('skwasm') +library skwasm_impl; + +import 'dart:ffi'; + +final class RawSkString extends Opaque {} +typedef SkStringHandle = Pointer; + +@Native(symbol: 'skString_allocate', isLeaf: true) +external SkStringHandle skStringAllocate(int size); + +@Native Function(SkStringHandle)>(symbol: 'skString_getData', isLeaf: true) +external Pointer skStringGetData(SkStringHandle handle); + +@Native(symbol: 'skString_free', isLeaf: true) +external void skStringFree(SkStringHandle handle); diff --git a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/shaders.dart b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/shaders.dart index dc37b92666143..ef2bf5ce2f1c5 100644 --- a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/shaders.dart +++ b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/shaders.dart @@ -162,15 +162,15 @@ class SkwasmFragmentProgram implements ui.FragmentProgram { // TODO(jacksongardner): Can we avoid this copy? final List sourceData = utf8.encode(shaderData.source); - final SkStringHandle sourceString = shaderSourceAllocate(sourceData.length); - final Pointer sourceBuffer = shaderSourceGetData(sourceString); + final SkStringHandle sourceString = skStringAllocate(sourceData.length); + final Pointer sourceBuffer = skStringGetData(sourceString); int i = 0; for (final int byte in sourceData) { sourceBuffer[i] = byte; i++; } final RuntimeEffectHandle handle = runtimeEffectCreate(sourceString); - shaderSourceFree(sourceString); + skStringFree(sourceString); return SkwasmFragmentProgram._(name, handle); } @@ -193,7 +193,7 @@ class SkwasmFragmentShader extends SkwasmShader implements ui.FragmentShader { SkwasmFragmentProgram program, { List? childShaders, }) : _program = program, - _uniformData = dataCreate(program.uniformSize), + _uniformData = skDataCreate(program.uniformSize), _childShaders = childShaders; @override @@ -234,7 +234,7 @@ class SkwasmFragmentShader extends SkwasmShader implements ui.FragmentShader { shaderDispose(_handle); _handle = nullptr; } - final Pointer dataPointer = dataGetPointer(_uniformData).cast(); + final Pointer dataPointer = skDataGetPointer(_uniformData).cast(); dataPointer[index] = value; } @@ -247,7 +247,7 @@ class SkwasmFragmentShader extends SkwasmShader implements ui.FragmentShader { void dispose() { super.dispose(); if (_uniformData != nullptr) { - dataDispose(_uniformData); + skDataDispose(_uniformData); _uniformData = nullptr; } } diff --git a/lib/web_ui/lib/src/engine/text/font_collection.dart b/lib/web_ui/lib/src/engine/text/font_collection.dart index 398e05057578a..ad8031b32c999 100644 --- a/lib/web_ui/lib/src/engine/text/font_collection.dart +++ b/lib/web_ui/lib/src/engine/text/font_collection.dart @@ -3,7 +3,6 @@ // found in the LICENSE file. import 'dart:async'; -import 'dart:convert'; import 'dart:typed_data'; import 'package:ui/src/engine/fonts.dart'; @@ -28,40 +27,15 @@ class HtmlFontCollection implements FlutterFontCollection { /// fonts declared within. @override Future downloadAssetFonts(AssetManager assetManager) async { - final HttpFetchResponse response = await assetManager.loadAsset('FontManifest.json'); - - if (!response.hasPayload) { - printWarning('Font manifest does not exist at `${response.url}` - ignoring.'); - return; - } - - final Uint8List data = await response.asUint8List(); - final List? fontManifest = json.decode(utf8.decode(data)) as List?; - if (fontManifest == null) { - throw AssertionError( - 'There was a problem trying to load FontManifest.json'); - } - - _assetFontManager = FontManager(); - - for (final Map fontFamily - in fontManifest.cast>()) { - final String? family = fontFamily.tryString('family'); - final List> fontAssets = fontFamily.castList>('fonts'); - - for (final Map fontAsset in fontAssets) { - final String asset = fontAsset.readString('asset'); - final Map descriptors = {}; - for (final String descriptor in fontAsset.keys) { - if (descriptor != 'asset') { - descriptors[descriptor] = '${fontAsset[descriptor]}'; - } - } - _assetFontManager!.downloadAsset( - family!, 'url(${assetManager.getAssetUrl(asset)})', descriptors); + final FontManifest manifest = await fetchFontManifest(); + final FontManager assetFontManager = FontManager(); + _assetFontManager = assetFontManager; + for (final FontFamily family in manifest.families) { + for (final FontAsset fontAsset in family.fontAssets) { + assetFontManager.downloadAsset(family.name, fontAsset.asset, fontAsset.descriptors); } } - await _assetFontManager!.downloadAllFonts(); + await assetFontManager.downloadAllFonts(); } @override diff --git a/lib/web_ui/skwasm/BUILD.gn b/lib/web_ui/skwasm/BUILD.gn index 7ad61d87fefcd..cc5a7bd4e7cf1 100644 --- a/lib/web_ui/skwasm/BUILD.gn +++ b/lib/web_ui/skwasm/BUILD.gn @@ -8,12 +8,15 @@ wasm_lib("skwasm") { sources = [ "canvas.cpp", "contour_measure.cpp", + "data.cpp", + "fonts.cpp", "export.h", "helpers.h", "paint.cpp", "path.cpp", "picture.cpp", "shaders.cpp", + "string.cpp", "surface.cpp", "wrappers.h", ] @@ -46,5 +49,8 @@ wasm_lib("skwasm") { ] } - deps = [ "//third_party/skia" ] + deps = [ + "//third_party/skia", + "//third_party/skia/modules/skparagraph", + ] } diff --git a/lib/web_ui/skwasm/canvas.cpp b/lib/web_ui/skwasm/canvas.cpp index 79cd4d2f06213..9a07aef09bba1 100644 --- a/lib/web_ui/skwasm/canvas.cpp +++ b/lib/web_ui/skwasm/canvas.cpp @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include #include "export.h" #include "helpers.h" #include "wrappers.h" diff --git a/lib/web_ui/skwasm/contour_measure.cpp b/lib/web_ui/skwasm/contour_measure.cpp index fcc30ad407967..642d1fa36924a 100644 --- a/lib/web_ui/skwasm/contour_measure.cpp +++ b/lib/web_ui/skwasm/contour_measure.cpp @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include #include "export.h" #include "helpers.h" diff --git a/lib/web_ui/skwasm/data.cpp b/lib/web_ui/skwasm/data.cpp new file mode 100644 index 0000000000000..b3a6c5bffbfe8 --- /dev/null +++ b/lib/web_ui/skwasm/data.cpp @@ -0,0 +1,19 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "export.h" + +#include "third_party/skia/include/core/SkData.h" + +SKWASM_EXPORT SkData* skData_create(size_t size) { + return SkData::MakeUninitialized(size).release(); +} + +SKWASM_EXPORT void* skDataata_getPointer(SkData* data) { + return data->writable_data(); +} + +SKWASM_EXPORT void skData_dispose(SkData* data) { + return data->unref(); +} diff --git a/lib/web_ui/skwasm/export.h b/lib/web_ui/skwasm/export.h index cb0172e0bf621..fe4711aac20f6 100644 --- a/lib/web_ui/skwasm/export.h +++ b/lib/web_ui/skwasm/export.h @@ -4,4 +4,6 @@ #pragma once +#include + #define SKWASM_EXPORT extern "C" EMSCRIPTEN_KEEPALIVE diff --git a/lib/web_ui/skwasm/fonts.cpp b/lib/web_ui/skwasm/fonts.cpp new file mode 100644 index 0000000000000..4fa0ed2b42579 --- /dev/null +++ b/lib/web_ui/skwasm/fonts.cpp @@ -0,0 +1,44 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "export.h" +#include "third_party/skia/include/core/SkFontMgr.h" +#include "third_party/skia/modules/skparagraph/include/FontCollection.h" +#include "third_party/skia/modules/skparagraph/include/TypefaceFontProvider.h" + +using namespace skia::textlayout; + +struct FlutterFontCollection { + sk_sp collection; + sk_sp provider; +}; + +SKWASM_EXPORT FlutterFontCollection *fontCollection_create() { + auto collection = sk_make_sp(); + auto provider = sk_make_sp(); + collection->enableFontFallback(); + collection->setDefaultFontManager(provider); + return new FlutterFontCollection{ + std::move(collection), + std::move(provider), + }; +} + +SKWASM_EXPORT void fontCollection_dispose(FlutterFontCollection *collection) { + delete collection; +} + +SKWASM_EXPORT void fontCollection_registerFont( + FlutterFontCollection *collection, + SkData *fontData, + SkString *fontName +) { + fontData->ref(); + auto typeFace = collection->provider->makeFromData(sk_sp(fontData)); + if (fontName != nullptr) { + collection->provider->registerTypeface(std::move(typeFace), *fontName); + } else { + collection->provider->registerTypeface(std::move(typeFace)); + } +} diff --git a/lib/web_ui/skwasm/paint.cpp b/lib/web_ui/skwasm/paint.cpp index eb66fff6e292a..026a7a4d80b5f 100644 --- a/lib/web_ui/skwasm/paint.cpp +++ b/lib/web_ui/skwasm/paint.cpp @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include #include "export.h" #include "helpers.h" #include "third_party/skia/include/core/SkPaint.h" diff --git a/lib/web_ui/skwasm/path.cpp b/lib/web_ui/skwasm/path.cpp index f8fe6e1452e30..63690f1370108 100644 --- a/lib/web_ui/skwasm/path.cpp +++ b/lib/web_ui/skwasm/path.cpp @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include #include "export.h" #include "helpers.h" #include "third_party/skia/include/core/SkPath.h" diff --git a/lib/web_ui/skwasm/picture.cpp b/lib/web_ui/skwasm/picture.cpp index 2d80a985ab9bb..c12d7d42fc53b 100644 --- a/lib/web_ui/skwasm/picture.cpp +++ b/lib/web_ui/skwasm/picture.cpp @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include #include "export.h" #include "helpers.h" #include "third_party/skia/include/core/SkPictureRecorder.h" diff --git a/lib/web_ui/skwasm/shaders.cpp b/lib/web_ui/skwasm/shaders.cpp index 1c29c10e844fb..5a521f8184512 100644 --- a/lib/web_ui/skwasm/shaders.cpp +++ b/lib/web_ui/skwasm/shaders.cpp @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include #include "export.h" #include "helpers.h" #include "third_party/skia/include/effects/SkGradientShader.h" @@ -102,18 +101,6 @@ SKWASM_EXPORT void shader_dispose(SkShader* shader) { shader->unref(); } -SKWASM_EXPORT SkString* shaderSource_allocate(size_t length) { - return new SkString(length); -} - -SKWASM_EXPORT char* shaderSource_getData(SkString* string) { - return string->data(); -} - -SKWASM_EXPORT void shaderSource_free(SkString* string) { - return delete string; -} - SKWASM_EXPORT SkRuntimeEffect* runtimeEffect_create(SkString* source) { auto result = SkRuntimeEffect::MakeForShader(*source); if (result.effect == nullptr) { @@ -133,18 +120,6 @@ SKWASM_EXPORT size_t runtimeEffect_getUniformSize(SkRuntimeEffect* effect) { return effect->uniformSize(); } -SKWASM_EXPORT SkData* data_create(size_t size) { - return SkData::MakeUninitialized(size).release(); -} - -SKWASM_EXPORT void* data_getPointer(SkData* data) { - return data->writable_data(); -} - -SKWASM_EXPORT void data_dispose(SkData* data) { - return data->unref(); -} - SKWASM_EXPORT SkShader* shader_createRuntimeEffectShader( SkRuntimeEffect* runtimeEffect, SkData* uniforms, diff --git a/lib/web_ui/skwasm/string.cpp b/lib/web_ui/skwasm/string.cpp new file mode 100644 index 0000000000000..77e66d705dcfc --- /dev/null +++ b/lib/web_ui/skwasm/string.cpp @@ -0,0 +1,19 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "export.h" + +#include "third_party/skia/include/core/SkString.h" + +SKWASM_EXPORT SkString* skString_allocate(size_t length) { + return new SkString(length); +} + +SKWASM_EXPORT char* skString_getData(SkString* string) { + return string->data(); +} + +SKWASM_EXPORT void skString_free(SkString* string) { + return delete string; +} diff --git a/third_party/canvaskit/BUILD.gn b/third_party/canvaskit/BUILD.gn index 062aa10433ac3..af6b617bd8624 100644 --- a/third_party/canvaskit/BUILD.gn +++ b/third_party/canvaskit/BUILD.gn @@ -71,7 +71,15 @@ copy("canvaskit_chromium_group") { # This toolchain is only to be used by skwasm_group below. wasm_toolchain("skwasm") { extra_toolchain_args = { - skia_enable_skparagraph = false + # In Chromium browsers, we can use the browser's APIs to get the necessary + # ICU data. + skia_use_icu = false + skia_use_client_icu = true + skia_icu_bidi_third_party_dir = "//flutter/third_party/canvaskit/icu_bidi" + + skia_use_libjpeg_turbo_decode = false + skia_use_libpng_decode = false + skia_use_libwebp_decode = false # skwasm is multithreaded wasm_use_pthreads = true From ee37876d34caa073f8254253d9bf2c4ba90b14b8 Mon Sep 17 00:00:00 2001 From: Jackson Gardner Date: Sat, 15 Apr 2023 10:10:18 -0700 Subject: [PATCH 02/30] Fix mock http stuff to allow read callback. --- .../lib/src/engine/canvaskit/fonts.dart | 2 +- lib/web_ui/lib/src/engine/dom.dart | 22 +++++++-- lib/web_ui/lib/src/engine/fonts.dart | 2 +- .../lib/src/engine/text/font_collection.dart | 2 +- lib/web_ui/skwasm/BUILD.gn | 4 +- lib/web_ui/skwasm/fonts.cpp | 47 +++++++++---------- 6 files changed, 46 insertions(+), 33 deletions(-) diff --git a/lib/web_ui/lib/src/engine/canvaskit/fonts.dart b/lib/web_ui/lib/src/engine/canvaskit/fonts.dart index 646ff207fe06b..d06e53f069713 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/fonts.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/fonts.dart @@ -99,7 +99,7 @@ class SkiaFontCollection implements FlutterFontCollection { /// Loads fonts from `FontManifest.json`. @override Future downloadAssetFonts(AssetManager assetManager) async { - final FontManifest manifest = await fetchFontManifest(); + final FontManifest manifest = await fetchFontManifest(assetManager); final List> pendingFonts = >[]; for (final FontFamily family in manifest.families) { diff --git a/lib/web_ui/lib/src/engine/dom.dart b/lib/web_ui/lib/src/engine/dom.dart index 4019ab8d7f3df..50549741d297b 100644 --- a/lib/web_ui/lib/src/engine/dom.dart +++ b/lib/web_ui/lib/src/engine/dom.dart @@ -1660,19 +1660,33 @@ class MockHttpFetchPayload implements HttpFetchPayload { ByteBuffer? byteBuffer, Object? json, String? text, - MockOnRead? onRead, + int? chunkSize, }) : _byteBuffer = byteBuffer, _json = json, _text = text, - _onRead = onRead; + _chunkSize = chunkSize ?? 64; final ByteBuffer? _byteBuffer; final Object? _json; final String? _text; - final MockOnRead? _onRead; + final int _chunkSize; @override - Future read(HttpFetchReader callback) => _onRead!(callback); + Future read(HttpFetchReader callback) async { + if (_byteBuffer == null) { + return; + } + final int totalLength = _byteBuffer!.lengthInBytes; + int currentIndex = 0; + while (currentIndex < totalLength) { + final int chunkSize = math.min(_chunkSize, totalLength - currentIndex); + final Uint8List chunk = Uint8List.sublistView( + _byteBuffer!.asByteData(), currentIndex, currentIndex + chunkSize + ); + callback(chunk.toJS as T); + currentIndex += chunkSize; + } + } @override Future asByteBuffer() async => _byteBuffer!; diff --git a/lib/web_ui/lib/src/engine/fonts.dart b/lib/web_ui/lib/src/engine/fonts.dart index b45d816fcb5a0..9e7fe956c40f1 100644 --- a/lib/web_ui/lib/src/engine/fonts.dart +++ b/lib/web_ui/lib/src/engine/fonts.dart @@ -29,7 +29,7 @@ class FontManifest { List families; } -Future fetchFontManifest() async { +Future fetchFontManifest(AssetManager assetManager) async { final HttpFetchResponse response = await assetManager.loadAsset('FontManifest.json'); if (!response.hasPayload) { printWarning('Font manifest does not exist at `${response.url}` - ignoring.'); diff --git a/lib/web_ui/lib/src/engine/text/font_collection.dart b/lib/web_ui/lib/src/engine/text/font_collection.dart index ad8031b32c999..8293634660e8c 100644 --- a/lib/web_ui/lib/src/engine/text/font_collection.dart +++ b/lib/web_ui/lib/src/engine/text/font_collection.dart @@ -27,7 +27,7 @@ class HtmlFontCollection implements FlutterFontCollection { /// fonts declared within. @override Future downloadAssetFonts(AssetManager assetManager) async { - final FontManifest manifest = await fetchFontManifest(); + final FontManifest manifest = await fetchFontManifest(assetManager); final FontManager assetFontManager = FontManager(); _assetFontManager = assetFontManager; for (final FontFamily family in manifest.families) { diff --git a/lib/web_ui/skwasm/BUILD.gn b/lib/web_ui/skwasm/BUILD.gn index cc5a7bd4e7cf1..7fb55ceab5bc9 100644 --- a/lib/web_ui/skwasm/BUILD.gn +++ b/lib/web_ui/skwasm/BUILD.gn @@ -9,8 +9,8 @@ wasm_lib("skwasm") { "canvas.cpp", "contour_measure.cpp", "data.cpp", - "fonts.cpp", "export.h", + "fonts.cpp", "helpers.h", "paint.cpp", "path.cpp", @@ -49,7 +49,7 @@ wasm_lib("skwasm") { ] } - deps = [ + deps = [ "//third_party/skia", "//third_party/skia/modules/skparagraph", ] diff --git a/lib/web_ui/skwasm/fonts.cpp b/lib/web_ui/skwasm/fonts.cpp index 4fa0ed2b42579..bd57a5e04051a 100644 --- a/lib/web_ui/skwasm/fonts.cpp +++ b/lib/web_ui/skwasm/fonts.cpp @@ -10,35 +10,34 @@ using namespace skia::textlayout; struct FlutterFontCollection { - sk_sp collection; - sk_sp provider; + sk_sp collection; + sk_sp provider; }; -SKWASM_EXPORT FlutterFontCollection *fontCollection_create() { - auto collection = sk_make_sp(); - auto provider = sk_make_sp(); - collection->enableFontFallback(); - collection->setDefaultFontManager(provider); - return new FlutterFontCollection{ - std::move(collection), - std::move(provider), - }; +SKWASM_EXPORT FlutterFontCollection* fontCollection_create() { + auto collection = sk_make_sp(); + auto provider = sk_make_sp(); + collection->enableFontFallback(); + collection->setDefaultFontManager(provider); + return new FlutterFontCollection{ + std::move(collection), + std::move(provider), + }; } -SKWASM_EXPORT void fontCollection_dispose(FlutterFontCollection *collection) { - delete collection; +SKWASM_EXPORT void fontCollection_dispose(FlutterFontCollection* collection) { + delete collection; } SKWASM_EXPORT void fontCollection_registerFont( - FlutterFontCollection *collection, - SkData *fontData, - SkString *fontName -) { - fontData->ref(); - auto typeFace = collection->provider->makeFromData(sk_sp(fontData)); - if (fontName != nullptr) { - collection->provider->registerTypeface(std::move(typeFace), *fontName); - } else { - collection->provider->registerTypeface(std::move(typeFace)); - } + FlutterFontCollection* collection, + SkData* fontData, + SkString* fontName) { + fontData->ref(); + auto typeFace = collection->provider->makeFromData(sk_sp(fontData)); + if (fontName != nullptr) { + collection->provider->registerTypeface(std::move(typeFace), *fontName); + } else { + collection->provider->registerTypeface(std::move(typeFace)); + } } From a11804ed98cf950e1bcc0f33b7555a58f5ce11cd Mon Sep 17 00:00:00 2001 From: Jackson Gardner Date: Sat, 15 Apr 2023 10:32:31 -0700 Subject: [PATCH 03/30] Update licenses golden. --- ci/licenses_golden/licenses_flutter | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 61cb7b1a2d696..07d601b43b5e3 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1999,6 +1999,7 @@ ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/path_metri ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/picture.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/js_functions.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_canvas.dart + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_fonts.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_geometry.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_memory.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_paint.dart + ../../../flutter/LICENSE @@ -2006,6 +2007,8 @@ ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_pa ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_path_metrics.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_picture.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_shaders.dart + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_skdata.dart + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_skstring.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_surface.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/renderer.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/scene_builder.dart + ../../../flutter/LICENSE @@ -2056,12 +2059,15 @@ ORIGIN: ../../../flutter/lib/web_ui/lib/ui_web/src/ui_web/url_strategy.dart + .. ORIGIN: ../../../flutter/lib/web_ui/lib/window.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/skwasm/canvas.cpp + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/skwasm/contour_measure.cpp + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/lib/web_ui/skwasm/data.cpp + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/skwasm/export.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/lib/web_ui/skwasm/fonts.cpp + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/skwasm/helpers.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/skwasm/paint.cpp + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/skwasm/path.cpp + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/skwasm/picture.cpp + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/skwasm/shaders.cpp + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/lib/web_ui/skwasm/string.cpp + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/skwasm/surface.cpp + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/skwasm/wrappers.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/runtime/dart_isolate.cc + ../../../flutter/LICENSE @@ -4590,6 +4596,7 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/path_metrics FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/picture.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/js_functions.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_canvas.dart +FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_fonts.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_geometry.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_memory.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_paint.dart @@ -4597,6 +4604,8 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_path FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_path_metrics.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_picture.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_shaders.dart +FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_skdata.dart +FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_skstring.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_surface.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/renderer.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/scene_builder.dart @@ -4647,12 +4656,15 @@ FILE: ../../../flutter/lib/web_ui/lib/ui_web/src/ui_web/url_strategy.dart FILE: ../../../flutter/lib/web_ui/lib/window.dart FILE: ../../../flutter/lib/web_ui/skwasm/canvas.cpp FILE: ../../../flutter/lib/web_ui/skwasm/contour_measure.cpp +FILE: ../../../flutter/lib/web_ui/skwasm/data.cpp FILE: ../../../flutter/lib/web_ui/skwasm/export.h +FILE: ../../../flutter/lib/web_ui/skwasm/fonts.cpp FILE: ../../../flutter/lib/web_ui/skwasm/helpers.h FILE: ../../../flutter/lib/web_ui/skwasm/paint.cpp FILE: ../../../flutter/lib/web_ui/skwasm/path.cpp FILE: ../../../flutter/lib/web_ui/skwasm/picture.cpp FILE: ../../../flutter/lib/web_ui/skwasm/shaders.cpp +FILE: ../../../flutter/lib/web_ui/skwasm/string.cpp FILE: ../../../flutter/lib/web_ui/skwasm/surface.cpp FILE: ../../../flutter/lib/web_ui/skwasm/wrappers.h FILE: ../../../flutter/runtime/dart_isolate.cc From 553e23fce3ee6ac076ad1738a09f19a4375132e2 Mon Sep 17 00:00:00 2001 From: Jackson Gardner Date: Sat, 15 Apr 2023 10:49:34 -0700 Subject: [PATCH 04/30] Fix typo in function name. --- lib/web_ui/skwasm/data.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/web_ui/skwasm/data.cpp b/lib/web_ui/skwasm/data.cpp index b3a6c5bffbfe8..9c5e860d6d635 100644 --- a/lib/web_ui/skwasm/data.cpp +++ b/lib/web_ui/skwasm/data.cpp @@ -10,7 +10,7 @@ SKWASM_EXPORT SkData* skData_create(size_t size) { return SkData::MakeUninitialized(size).release(); } -SKWASM_EXPORT void* skDataata_getPointer(SkData* data) { +SKWASM_EXPORT void* skData_getPointer(SkData* data) { return data->writable_data(); } From 42d56a70d6771650b1eb8bffca796fe4d5e69b1c Mon Sep 17 00:00:00 2001 From: Jackson Gardner Date: Sun, 16 Apr 2023 21:55:19 -0700 Subject: [PATCH 05/30] Don't dartify values of string chunks. --- lib/web_ui/lib/src/engine/dom.dart | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/web_ui/lib/src/engine/dom.dart b/lib/web_ui/lib/src/engine/dom.dart index 50549741d297b..0ef621399dd7a 100644 --- a/lib/web_ui/lib/src/engine/dom.dart +++ b/lib/web_ui/lib/src/engine/dom.dart @@ -1809,9 +1809,7 @@ extension _DomStreamReaderExtension on _DomStreamReader { class _DomStreamChunk {} extension _DomStreamChunkExtension on _DomStreamChunk { - @JS('value') - external JSAny? get _value; - Object? get value => _value?.toObjectShallow; + external JSAny? get value; @JS('done') external JSBoolean get _done; From 4fb3179fc9235e21ef84a54e67083f4475330000 Mon Sep 17 00:00:00 2001 From: Jackson Gardner Date: Mon, 17 Apr 2023 10:26:02 -0700 Subject: [PATCH 06/30] Avoid using the `JSUint8Array` type objects, as the typedefs on the JS backends cause issues. --- lib/web_ui/lib/src/engine.dart | 1 + .../src/engine/js_interop/js_typed_data.dart | 24 +++++++++++++ .../lib/src/engine/skwasm/skwasm_impl.dart | 2 +- .../skwasm/skwasm_impl/font_collection.dart | 35 +++++++++++++++++++ .../{js_functions.dart => skwasm_module.dart} | 10 ++++++ 5 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 lib/web_ui/lib/src/engine/js_interop/js_typed_data.dart rename lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/{js_functions.dart => skwasm_module.dart} (70%) diff --git a/lib/web_ui/lib/src/engine.dart b/lib/web_ui/lib/src/engine.dart index 8c6b9fcef6558..808b7898a9251 100644 --- a/lib/web_ui/lib/src/engine.dart +++ b/lib/web_ui/lib/src/engine.dart @@ -109,6 +109,7 @@ export 'engine/html_image_codec.dart'; export 'engine/initialization.dart'; export 'engine/js_interop/js_loader.dart'; export 'engine/js_interop/js_promise.dart'; +export 'engine/js_interop/js_typed_data.dart'; export 'engine/key_map.g.dart'; export 'engine/keyboard_binding.dart'; export 'engine/mouse_cursor.dart'; diff --git a/lib/web_ui/lib/src/engine/js_interop/js_typed_data.dart b/lib/web_ui/lib/src/engine/js_interop/js_typed_data.dart new file mode 100644 index 0000000000000..ac382a8c203f7 --- /dev/null +++ b/lib/web_ui/lib/src/engine/js_interop/js_typed_data.dart @@ -0,0 +1,24 @@ +// 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:js_interop'; + +@JS() +@staticInterop +class ArrayBuffer {} + +@JS() +@staticInterop +class TypedArray {} + +extension TypedArrayExtension on TypedArray { + external void set(JSAny source, JSNumber start); + external JSNumber get length; +} + +@JS() +@staticInterop +class Uint8Array extends TypedArray { + external factory Uint8Array(ArrayBuffer buffer); +} diff --git a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl.dart b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl.dart index 535144f44a9a0..13d223e640888 100644 --- a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl.dart +++ b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl.dart @@ -18,7 +18,6 @@ export 'skwasm_impl/paragraph.dart'; export 'skwasm_impl/path.dart'; export 'skwasm_impl/path_metrics.dart'; export 'skwasm_impl/picture.dart'; -export 'skwasm_impl/raw/js_functions.dart'; export 'skwasm_impl/raw/raw_canvas.dart'; export 'skwasm_impl/raw/raw_fonts.dart'; export 'skwasm_impl/raw/raw_geometry.dart'; @@ -31,6 +30,7 @@ export 'skwasm_impl/raw/raw_shaders.dart'; export 'skwasm_impl/raw/raw_skdata.dart'; export 'skwasm_impl/raw/raw_skstring.dart'; export 'skwasm_impl/raw/raw_surface.dart'; +export 'skwasm_impl/raw/skwasm_module.dart'; export 'skwasm_impl/renderer.dart'; export 'skwasm_impl/scene_builder.dart'; export 'skwasm_impl/shaders.dart'; diff --git a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/font_collection.dart b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/font_collection.dart index 3a77da54176cf..048334e71ec97 100644 --- a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/font_collection.dart +++ b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/font_collection.dart @@ -5,6 +5,7 @@ import 'dart:async'; import 'dart:convert'; import 'dart:ffi'; +import 'dart:js_interop'; import 'dart:typed_data'; @@ -28,6 +29,40 @@ class SkwasmFontCollection implements FlutterFontCollection { @override Future downloadAssetFonts(AssetManager assetManager) async { + final FontManifest manifest = await fetchFontManifest(assetManager); + final List> fontFutures = >[]; + for (final FontFamily family in manifest.families) { + final List rawUtf8Bytes = utf8.encode(family.name); + final SkStringHandle stringHandle = skStringAllocate(rawUtf8Bytes.length); + final Pointer stringDataPointer = skStringGetData(stringHandle); + for (int i = 0; i < rawUtf8Bytes.length; i++) { + stringDataPointer[i] = rawUtf8Bytes[i]; + } + for (final FontAsset fontAsset in family.fontAssets) { + fontFutures.add(_downloadFontAsset(fontAsset.asset, stringHandle)); + } + skStringFree(stringHandle); + } + await Future.wait(fontFutures); + } + + Future _downloadFontAsset(String assetName, SkStringHandle familyNameHandle) async { + final HttpFetchResponse response = await assetManager.loadAsset(assetName); + int length = 0; + final List chunks = []; + await response.read((Uint8Array chunk) { + length += chunk.length.toDart.toInt(); + chunks.add(chunk); + }); + final SkDataHandle fontData = skDataCreate(length); + int dataAddress = skDataGetPointer(fontData).cast().address; + final Uint8Array wasmMemory = Uint8Array(skwasmInstance.wasmMemory.buffer); + for (final Uint8Array chunk in chunks) { + wasmMemory.set(chunk, dataAddress.toJS); + dataAddress += chunk.length.toDart.toInt(); + } + fontCollectionRegisterFont(_handle, fontData, familyNameHandle); + skDataDispose(fontData); } @override diff --git a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/js_functions.dart b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/skwasm_module.dart similarity index 70% rename from lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/js_functions.dart rename to lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/skwasm_module.dart index 43b3dedecabf5..de2f643322bb8 100644 --- a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/js_functions.dart +++ b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/skwasm_module.dart @@ -5,6 +5,15 @@ import 'dart:js_interop'; import 'package:js/js.dart'; +import 'package:ui/src/engine.dart'; + +@JS() +@staticInterop +class WebAssemblyMemory {} + +extension WebAssemblyMemoryExtension on WebAssemblyMemory { + external ArrayBuffer get buffer; +} @JS() @staticInterop @@ -13,6 +22,7 @@ class SkwasmInstance {} extension SkwasmInstanceExtension on SkwasmInstance { external JSNumber addFunction(JSFunction function, JSString signature); external void removeFunction(JSNumber functionPointer); + external WebAssemblyMemory get wasmMemory; } @JS('window._flutter_skwasmInstance') From e5148b108285714c90f900b7aade6971657b1db6 Mon Sep 17 00:00:00 2001 From: Jackson Gardner Date: Mon, 17 Apr 2023 11:12:15 -0700 Subject: [PATCH 07/30] Change typed array's `set` signature. --- lib/web_ui/lib/src/engine/js_interop/js_typed_data.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/web_ui/lib/src/engine/js_interop/js_typed_data.dart b/lib/web_ui/lib/src/engine/js_interop/js_typed_data.dart index ac382a8c203f7..adc2d8f6eba06 100644 --- a/lib/web_ui/lib/src/engine/js_interop/js_typed_data.dart +++ b/lib/web_ui/lib/src/engine/js_interop/js_typed_data.dart @@ -13,7 +13,7 @@ class ArrayBuffer {} class TypedArray {} extension TypedArrayExtension on TypedArray { - external void set(JSAny source, JSNumber start); + external void set(Uint8Array source, JSNumber start); external JSNumber get length; } From 77f0010fd8d53cc364d87078d28eb738bb7b2a40 Mon Sep 17 00:00:00 2001 From: Jackson Gardner Date: Mon, 17 Apr 2023 11:24:07 -0700 Subject: [PATCH 08/30] Update licenses golden. --- ci/licenses_golden/licenses_flutter | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index e7fcc5568c13a..260116fef2705 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1950,6 +1950,7 @@ ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/html_image_codec.dart + ../.. ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/initialization.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/js_interop/js_loader.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/js_interop/js_promise.dart + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/js_interop/js_typed_data.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/key_map.g.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/keyboard_binding.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/mouse_cursor.dart + ../../../flutter/LICENSE @@ -2002,7 +2003,6 @@ ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/paragraph. ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/path.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/path_metrics.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/picture.dart + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/js_functions.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_canvas.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_fonts.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_geometry.dart + ../../../flutter/LICENSE @@ -2015,6 +2015,7 @@ ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_sh ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_skdata.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_skstring.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_surface.dart + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/skwasm_module.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/renderer.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/scene_builder.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/shaders.dart + ../../../flutter/LICENSE @@ -4552,6 +4553,7 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/html_image_codec.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/initialization.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/js_interop/js_loader.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/js_interop/js_promise.dart +FILE: ../../../flutter/lib/web_ui/lib/src/engine/js_interop/js_typed_data.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/key_map.g.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/keyboard_binding.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/mouse_cursor.dart @@ -4604,7 +4606,6 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/paragraph.da FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/path.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/path_metrics.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/picture.dart -FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/js_functions.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_canvas.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_fonts.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_geometry.dart @@ -4617,6 +4618,7 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_shad FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_skdata.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_skstring.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_surface.dart +FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/skwasm_module.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/renderer.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/scene_builder.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/shaders.dart From 393ea59bf985467b4203ba5183f01a3f6552d75f Mon Sep 17 00:00:00 2001 From: Jackson Gardner Date: Mon, 17 Apr 2023 13:51:48 -0700 Subject: [PATCH 09/30] Fix some unit tests. --- .../lib/src/engine/canvaskit/image.dart | 27 ++++++------------- lib/web_ui/lib/src/engine/dom.dart | 23 +++++----------- .../src/engine/js_interop/js_typed_data.dart | 5 +++- .../skwasm/skwasm_impl/font_collection.dart | 6 ++++- .../test/engine/dom_http_fetch_test.dart | 3 ++- 5 files changed, 26 insertions(+), 38 deletions(-) diff --git a/lib/web_ui/lib/src/engine/canvaskit/image.dart b/lib/web_ui/lib/src/engine/canvaskit/image.dart index 3e167422d992a..1a6ef33ad44ed 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/image.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/image.dart @@ -3,23 +3,12 @@ // found in the LICENSE file. import 'dart:async'; +import 'dart:js_interop'; import 'dart:typed_data'; +import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; -import '../dom.dart'; -import '../html_image_codec.dart'; -import '../safe_browser_api.dart'; -import '../util.dart'; -import 'canvas.dart'; -import 'canvaskit_api.dart'; -import 'image_wasm_codecs.dart'; -import 'image_web_codecs.dart'; -import 'native_memory.dart'; -import 'painting.dart'; -import 'picture.dart'; -import 'picture_recorder.dart'; - /// Instantiates a [ui.Codec] backed by an `SkAnimatedImage` from Skia. FutureOr skiaInstantiateImageCodec(Uint8List list, [int? targetWidth, int? targetHeight]) { @@ -212,16 +201,16 @@ Future fetchImage(String url, WebOnlyImageCodecChunkCallback? chunkCa /// /// See: https://developer.mozilla.org/en-US/docs/Web/API/Streams_API Future readChunked(HttpFetchPayload payload, int contentLength, WebOnlyImageCodecChunkCallback chunkCallback) async { - final Uint8List result = Uint8List(contentLength); + final Uint8Array result = createUint8ArrayFromLength(contentLength); int position = 0; int cumulativeBytesLoaded = 0; - await payload.read((Uint8List chunk) { - cumulativeBytesLoaded += chunk.lengthInBytes; + await payload.read((Uint8Array chunk) { + cumulativeBytesLoaded += chunk.length.toDart.toInt(); chunkCallback(cumulativeBytesLoaded, contentLength); - result.setAll(position, chunk); - position += chunk.lengthInBytes; + result.set(chunk, position.toJS); + position += chunk.length.toDart.toInt(); }); - return result; + return (result as JSUint8Array).toDart; } /// A [ui.Image] backed by an `SkImage` from Skia. diff --git a/lib/web_ui/lib/src/engine/dom.dart b/lib/web_ui/lib/src/engine/dom.dart index 0ef621399dd7a..a62dbea2908f1 100644 --- a/lib/web_ui/lib/src/engine/dom.dart +++ b/lib/web_ui/lib/src/engine/dom.dart @@ -1657,31 +1657,22 @@ typedef MockOnRead = Future Function(HttpFetchReader callback); class MockHttpFetchPayload implements HttpFetchPayload { MockHttpFetchPayload({ - ByteBuffer? byteBuffer, - Object? json, - String? text, + required ByteBuffer byteBuffer, int? chunkSize, }) : _byteBuffer = byteBuffer, - _json = json, - _text = text, _chunkSize = chunkSize ?? 64; - final ByteBuffer? _byteBuffer; - final Object? _json; - final String? _text; + final ByteBuffer _byteBuffer; final int _chunkSize; @override Future read(HttpFetchReader callback) async { - if (_byteBuffer == null) { - return; - } - final int totalLength = _byteBuffer!.lengthInBytes; + final int totalLength = _byteBuffer.lengthInBytes; int currentIndex = 0; while (currentIndex < totalLength) { final int chunkSize = math.min(_chunkSize, totalLength - currentIndex); final Uint8List chunk = Uint8List.sublistView( - _byteBuffer!.asByteData(), currentIndex, currentIndex + chunkSize + _byteBuffer.asByteData(), currentIndex, currentIndex + chunkSize ); callback(chunk.toJS as T); currentIndex += chunkSize; @@ -1689,13 +1680,13 @@ class MockHttpFetchPayload implements HttpFetchPayload { } @override - Future asByteBuffer() async => _byteBuffer!; + Future asByteBuffer() async => _byteBuffer; @override - Future json() async => _json!; + Future json() async => throw AssertionError('json not supported by mock'); @override - Future text() async => _text!; + Future text() async => throw AssertionError('text not supported by mock'); } /// Indicates a missing HTTP payload when one was expected, such as when diff --git a/lib/web_ui/lib/src/engine/js_interop/js_typed_data.dart b/lib/web_ui/lib/src/engine/js_interop/js_typed_data.dart index adc2d8f6eba06..43f526f7afbc6 100644 --- a/lib/web_ui/lib/src/engine/js_interop/js_typed_data.dart +++ b/lib/web_ui/lib/src/engine/js_interop/js_typed_data.dart @@ -20,5 +20,8 @@ extension TypedArrayExtension on TypedArray { @JS() @staticInterop class Uint8Array extends TypedArray { - external factory Uint8Array(ArrayBuffer buffer); + external factory Uint8Array._(JSAny bufferOrLength); } + +Uint8Array createUint8ArrayFromBuffer(ArrayBuffer buffer) => Uint8Array._(buffer.toJS); +Uint8Array createUint8ArrayFromLength(int length) => Uint8Array._(length.toJS); diff --git a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/font_collection.dart b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/font_collection.dart index 048334e71ec97..05e8a82dfeef2 100644 --- a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/font_collection.dart +++ b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/font_collection.dart @@ -48,6 +48,10 @@ class SkwasmFontCollection implements FlutterFontCollection { Future _downloadFontAsset(String assetName, SkStringHandle familyNameHandle) async { final HttpFetchResponse response = await assetManager.loadAsset(assetName); + if (!response.hasPayload) { + printWarning('Failed to load font "$assetName", font file not found.'); + return; + } int length = 0; final List chunks = []; await response.read((Uint8Array chunk) { @@ -56,7 +60,7 @@ class SkwasmFontCollection implements FlutterFontCollection { }); final SkDataHandle fontData = skDataCreate(length); int dataAddress = skDataGetPointer(fontData).cast().address; - final Uint8Array wasmMemory = Uint8Array(skwasmInstance.wasmMemory.buffer); + final Uint8Array wasmMemory = createUint8ArrayFromBuffer(skwasmInstance.wasmMemory.buffer); for (final Uint8Array chunk in chunks) { wasmMemory.set(chunk, dataAddress.toJS); dataAddress += chunk.length.toDart.toInt(); diff --git a/lib/web_ui/test/engine/dom_http_fetch_test.dart b/lib/web_ui/test/engine/dom_http_fetch_test.dart index 1d1b8628ccdc5..606753ba4636b 100644 --- a/lib/web_ui/test/engine/dom_http_fetch_test.dart +++ b/lib/web_ui/test/engine/dom_http_fetch_test.dart @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:js_interop'; import 'dart:typed_data'; import 'package:test/bootstrap/browser.dart'; @@ -116,7 +117,7 @@ Future _testSuccessfulPayloads() async { expect(response.url, url); final List result = []; - await response.payload.read(result.addAll); + await response.payload.read((JSUint8Array chunk) => result.addAll(chunk.toDart)); expect(result, hasLength(length)); expect( result, From 1946222f35e06b8aa344c4e433eb22bc79d841f1 Mon Sep 17 00:00:00 2001 From: Jackson Gardner Date: Mon, 17 Apr 2023 17:19:18 -0700 Subject: [PATCH 10/30] Reorganized some testing things. --- lib/web_ui/lib/src/engine.dart | 1 - lib/web_ui/lib/src/engine/assets.dart | 76 ----------------- lib/web_ui/lib/src/engine/window.dart | 10 ++- lib/web_ui/test/canvaskit/common.dart | 5 +- .../flutter_tester_emulation_golden_test.dart | 3 +- .../canvaskit/skia_font_collection_test.dart | 36 ++++---- .../test/common/fake_asset_manager.dart | 83 +++++++++++++++++++ .../common}/test_embedding.dart | 17 ++-- lib/web_ui/test/engine/clipboard_test.dart | 2 + lib/web_ui/test/engine/history_test.dart | 2 +- .../engine/image/html_image_codec_test.dart | 3 +- lib/web_ui/test/engine/navigation_test.dart | 6 +- .../test/engine/recording_canvas_test.dart | 3 +- lib/web_ui/test/engine/routing_test.dart | 1 + .../html/canvas_clip_path_golden_test.dart | 3 +- .../test/html/canvas_context_golden_test.dart | 3 +- .../test/html/canvas_reuse_golden_test.dart | 4 +- .../compositing/canvas_blend_golden_test.dart | 3 +- .../canvas_image_blend_mode_golden_test.dart | 3 +- .../canvas_mask_filter_golden_test.dart | 3 +- .../dom_mask_filter_golden_test.dart | 3 +- .../canvas_draw_image_golden_test.dart | 3 +- .../drawing/draw_vertices_golden_test.dart | 3 +- .../test/html/path_metrics_golden_test.dart | 3 +- .../test/html/path_transform_golden_test.dart | 3 +- .../html/recording_canvas_golden_test.dart | 3 +- .../html/shaders/gradient_golden_test.dart | 3 +- .../shaders/image_shader_golden_test.dart | 3 +- .../shaders/linear_gradient_golden_test.dart | 3 +- .../shaders/radial_gradient_golden_test.dart | 3 +- .../text/canvas_paragraph_builder_test.dart | 3 +- .../text/canvas_paragraph_test.dart | 3 +- .../{ => html}/text/font_collection_test.dart | 0 .../{ => html}/text/font_loading_test.dart | 2 + .../text/layout_fragmenter_test.dart | 2 +- .../text/layout_service_helper.dart | 0 .../text/layout_service_plain_test.dart | 3 +- .../text/layout_service_rich_test.dart | 3 +- .../{ => html}/text/line_breaker_test.dart | 2 +- .../text/line_breaker_test_helper.dart | 0 .../text/line_breaker_test_raw_data.dart | 0 .../{ => html}/text/text_direction_test.dart | 2 +- .../{ => html}/text/word_breaker_test.dart | 0 lib/web_ui/test/html/text_test.dart | 1 + lib/web_ui/test/ui/fragment_shader_test.dart | 8 +- lib/web_ui/test/ui/utils.dart | 38 +-------- 46 files changed, 190 insertions(+), 174 deletions(-) create mode 100644 lib/web_ui/test/common/fake_asset_manager.dart rename lib/web_ui/{lib/src/engine => test/common}/test_embedding.dart (94%) rename lib/web_ui/test/{ => html}/text/canvas_paragraph_builder_test.dart (99%) rename lib/web_ui/test/{ => html}/text/canvas_paragraph_test.dart (99%) rename lib/web_ui/test/{ => html}/text/font_collection_test.dart (100%) rename lib/web_ui/test/{ => html}/text/font_loading_test.dart (98%) rename lib/web_ui/test/{ => html}/text/layout_fragmenter_test.dart (99%) rename lib/web_ui/test/{ => html}/text/layout_service_helper.dart (100%) rename lib/web_ui/test/{ => html}/text/layout_service_plain_test.dart (99%) rename lib/web_ui/test/{ => html}/text/layout_service_rich_test.dart (99%) rename lib/web_ui/test/{ => html}/text/line_breaker_test.dart (99%) rename lib/web_ui/test/{ => html}/text/line_breaker_test_helper.dart (100%) rename lib/web_ui/test/{ => html}/text/line_breaker_test_raw_data.dart (100%) rename lib/web_ui/test/{ => html}/text/text_direction_test.dart (99%) rename lib/web_ui/test/{ => html}/text/word_breaker_test.dart (100%) diff --git a/lib/web_ui/lib/src/engine.dart b/lib/web_ui/lib/src/engine.dart index 808b7898a9251..6b2c0879cb4ed 100644 --- a/lib/web_ui/lib/src/engine.dart +++ b/lib/web_ui/lib/src/engine.dart @@ -150,7 +150,6 @@ export 'engine/services/serialization.dart'; export 'engine/shader_data.dart'; export 'engine/shadow.dart'; export 'engine/svg.dart'; -export 'engine/test_embedding.dart'; export 'engine/text/canvas_paragraph.dart'; export 'engine/text/font_collection.dart'; export 'engine/text/fragmenter.dart'; diff --git a/lib/web_ui/lib/src/engine/assets.dart b/lib/web_ui/lib/src/engine/assets.dart index b200f824e4145..51a4acb77d91a 100644 --- a/lib/web_ui/lib/src/engine/assets.dart +++ b/lib/web_ui/lib/src/engine/assets.dart @@ -110,79 +110,3 @@ class AssetManager { return (await response.payload.asByteBuffer()).asByteData(); } } - -/// An asset manager that gives fake empty responses for assets. -class WebOnlyMockAssetManager extends AssetManager { - /// Mock asset directory relative to base url. - String defaultAssetsDir = ''; - - /// Mock empty asset manifest. - String defaultAssetManifest = '{}'; - - /// Mock font manifest overridable for unit testing. - String defaultFontManifest = ''' - [ - { - "family":"$robotoFontFamily", - "fonts":[{"asset":"$robotoTestFontUrl"}] - }, - { - "family":"$ahemFontFamily", - "fonts":[{"asset":"$ahemFontUrl"}] - } - ]'''; - - @override - String get assetsDir => defaultAssetsDir; - - @override - String getAssetUrl(String asset) => asset; - - @override - Future loadAsset(String asset) async { - if (asset == getAssetUrl('AssetManifest.json')) { - return MockHttpFetchResponse( - url: asset, - status: 200, - payload: MockHttpFetchPayload( - byteBuffer: _toByteData(utf8.encode(defaultAssetManifest)).buffer, - ), - ); - } - if (asset == getAssetUrl('FontManifest.json')) { - return MockHttpFetchResponse( - url: asset, - status: 200, - payload: MockHttpFetchPayload( - byteBuffer: _toByteData(utf8.encode(defaultFontManifest)).buffer, - ), - ); - } - - return MockHttpFetchResponse( - url: asset, - status: 404, - ); - } - - @override - Future load(String asset) { - if (asset == getAssetUrl('AssetManifest.json')) { - return Future.value( - _toByteData(utf8.encode(defaultAssetManifest))); - } - if (asset == getAssetUrl('FontManifest.json')) { - return Future.value( - _toByteData(utf8.encode(defaultFontManifest))); - } - throw HttpFetchNoPayloadError(asset, status: 404); - } - - ByteData _toByteData(List bytes) { - final ByteData byteData = ByteData(bytes.length); - for (int i = 0; i < bytes.length; i++) { - byteData.setUint8(i, bytes[i]); - } - return byteData; - } -} diff --git a/lib/web_ui/lib/src/engine/window.dart b/lib/web_ui/lib/src/engine/window.dart index 720611ec1f536..03f710a8e7fcc 100644 --- a/lib/web_ui/lib/src/engine/window.dart +++ b/lib/web_ui/lib/src/engine/window.dart @@ -20,7 +20,6 @@ import 'navigation/js_url_strategy.dart'; import 'navigation/url_strategy.dart'; import 'platform_dispatcher.dart'; import 'services.dart'; -import 'test_embedding.dart'; import 'util.dart'; typedef _HandleMessageCallBack = Future Function(); @@ -350,10 +349,13 @@ typedef _JsSetUrlStrategy = void Function(JsUrlStrategy?); @JS('_flutter_web_set_location_strategy') external set jsSetUrlStrategy(_JsSetUrlStrategy? newJsSetUrlStrategy); +ui_web.UrlStrategy? debugDefaultUrlStrategy; + ui_web.UrlStrategy? _createDefaultUrlStrategy() { - return ui.debugEmulateFlutterTesterEnvironment - ? TestUrlStrategy.fromEntry(const TestHistoryEntry('default', null, '/')) - : const HashUrlStrategy(); + if (ui.debugEmulateFlutterTesterEnvironment && debugDefaultUrlStrategy != null) { + return debugDefaultUrlStrategy; + } + return const HashUrlStrategy(); } /// The Web implementation of [ui.SingletonFlutterWindow]. diff --git a/lib/web_ui/test/canvaskit/common.dart b/lib/web_ui/test/canvaskit/common.dart index 68d88c0396dca..ffe0ba1876d5c 100644 --- a/lib/web_ui/test/canvaskit/common.dart +++ b/lib/web_ui/test/canvaskit/common.dart @@ -11,6 +11,8 @@ import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; import 'package:web_engine_tester/golden_tester.dart'; +import '../common/fake_asset_manager.dart'; + /// Used in tests instead of [ProductionCollector] to control Skia object /// collection explicitly, and to prevent leaks across tests. /// @@ -25,7 +27,8 @@ void setUpCanvasKitTest() { expect(renderer, isA(), reason: 'This test must run in CanvasKit mode.'); debugResetBrowserSupportsFinalizationRegistry(); debugDisableFontFallbacks = false; - await initializeEngine(assetManager: WebOnlyMockAssetManager()); + setUpStandardMocks(fakeAssetManager); + await initializeEngine(assetManager: fakeAssetManager); }); setUp(() async { diff --git a/lib/web_ui/test/canvaskit/flutter_tester_emulation_golden_test.dart b/lib/web_ui/test/canvaskit/flutter_tester_emulation_golden_test.dart index 81a2c340ff7b3..4b08b11666837 100644 --- a/lib/web_ui/test/canvaskit/flutter_tester_emulation_golden_test.dart +++ b/lib/web_ui/test/canvaskit/flutter_tester_emulation_golden_test.dart @@ -7,6 +7,7 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; +import '../common/test_embedding.dart'; import 'common.dart'; void main() { @@ -16,7 +17,7 @@ void main() { const ui.Rect kDefaultRegion = ui.Rect.fromLTRB(0, 0, 500, 250); void testMain() { - ui.debugEmulateFlutterTesterEnvironment = true; + setUpTestEnvironment(); group('flutter_tester emulation', () { setUpCanvasKitTest(); diff --git a/lib/web_ui/test/canvaskit/skia_font_collection_test.dart b/lib/web_ui/test/canvaskit/skia_font_collection_test.dart index 75764a8c35f4f..181cc6b33dc97 100644 --- a/lib/web_ui/test/canvaskit/skia_font_collection_test.dart +++ b/lib/web_ui/test/canvaskit/skia_font_collection_test.dart @@ -9,6 +9,8 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; +import '../common/fake_asset_manager.dart'; + void main() { internalBootstrapBrowserTest(() => testMain); } @@ -42,8 +44,8 @@ void testMain() { test('logs no warnings with the default mock asset manager', () async { final SkiaFontCollection fontCollection = SkiaFontCollection(); - final WebOnlyMockAssetManager mockAssetManager = - WebOnlyMockAssetManager(); + final FakeAssetManager mockAssetManager = FakeAssetManager(); + setUpStandardMocks(mockAssetManager); await fontCollection.downloadAssetFonts(mockAssetManager); fontCollection.registerDownloadedFonts(); @@ -61,9 +63,9 @@ void testMain() { ); }; final SkiaFontCollection fontCollection = SkiaFontCollection(); - final WebOnlyMockAssetManager mockAssetManager = - WebOnlyMockAssetManager(); - mockAssetManager.defaultFontManifest = ''' + final FakeAssetManager mockAssetManager = FakeAssetManager(); + setUpStandardMocks(mockAssetManager); + mockAssetManager.setMockAssetStringAsUtf8Data('FontManifest.json', ''' [ { "family":"Roboto", @@ -74,7 +76,7 @@ void testMain() { "fonts":[{"asset":"packages/bogus/BrokenFont.ttf"}] } ] - '''; + '''); // It should complete without error, but emit a warning about BrokenFont. await fontCollection.downloadAssetFonts(mockAssetManager); fontCollection.registerDownloadedFonts(); @@ -91,9 +93,9 @@ void testMain() { test('logs an HTTP warning if one of the registered fonts is missing (404 file not found)', () async { final SkiaFontCollection fontCollection = SkiaFontCollection(); - final WebOnlyMockAssetManager mockAssetManager = - WebOnlyMockAssetManager(); - mockAssetManager.defaultFontManifest = ''' + final FakeAssetManager mockAssetManager = FakeAssetManager(); + setUpStandardMocks(mockAssetManager); + mockAssetManager.setMockAssetStringAsUtf8Data('FontManifest.json', ''' [ { "family":"Roboto", @@ -104,7 +106,7 @@ void testMain() { "fonts":[{"asset":"packages/bogus/ThisFontDoesNotExist.ttf"}] } ] - '''; + '''); // It should complete without error, but emit a warning about ThisFontDoesNotExist. await fontCollection.downloadAssetFonts(mockAssetManager); @@ -120,16 +122,16 @@ void testMain() { test('prioritizes Ahem loaded via FontManifest.json', () async { final SkiaFontCollection fontCollection = SkiaFontCollection(); - final WebOnlyMockAssetManager mockAssetManager = - WebOnlyMockAssetManager(); - mockAssetManager.defaultFontManifest = ''' + final FakeAssetManager mockAssetManager = FakeAssetManager(); + setUpStandardMocks(mockAssetManager); + mockAssetManager.setMockAssetStringAsUtf8Data('FontManifest.json', ''' [ { "family":"Ahem", "fonts":[{"asset":"/assets/fonts/Roboto-Regular.ttf"}] } ] - '''.trim(); + '''.trim()); final ByteBuffer robotoData = await httpFetchByteBuffer('/assets/fonts/Roboto-Regular.ttf'); @@ -149,9 +151,9 @@ void testMain() { test('falls back to default Ahem URL', () async { final SkiaFontCollection fontCollection = SkiaFontCollection(); - final WebOnlyMockAssetManager mockAssetManager = - WebOnlyMockAssetManager(); - mockAssetManager.defaultFontManifest = '[]'; + final FakeAssetManager mockAssetManager = FakeAssetManager(); + setUpStandardMocks(mockAssetManager); + mockAssetManager.setMockAssetStringAsUtf8Data('FontManifest.json', '[]'); final ByteBuffer ahemData = await httpFetchByteBuffer('/assets/fonts/ahem.ttf'); diff --git a/lib/web_ui/test/common/fake_asset_manager.dart b/lib/web_ui/test/common/fake_asset_manager.dart new file mode 100644 index 0000000000000..a21a5ebe4549a --- /dev/null +++ b/lib/web_ui/test/common/fake_asset_manager.dart @@ -0,0 +1,83 @@ +// 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:convert'; +import 'dart:typed_data'; + +import 'package:ui/src/engine.dart'; + +class FakeAssetManager implements AssetManager { + @override + String get assetsDir => 'assets'; + + @override + String getAssetUrl(String asset) => asset; + + @override + Future load(String assetKey) async { + final ByteData? data = _assetMap[assetKey]; + if (data == null) { + throw HttpFetchNoPayloadError(assetKey, status: 404); + } + return data; + } + + @override + Future loadAsset(String assetKey) async { + final ByteData? data = _assetMap[assetKey]; + if (data == null) { + return MockHttpFetchResponse( + url: getAssetUrl(assetKey), + status: 404, + ); + } + return MockHttpFetchResponse( + url: getAssetUrl(assetKey), + status: 200, + payload: MockHttpFetchPayload( + byteBuffer: data.buffer, + ), + ); + } + + void setMockAssetData(String assetKey, ByteData assetData) { + _assetMap[assetKey] = assetData; + } + + void setMockAssetStringAsUtf8Data(String assetKey, String stringData) { + final List byteList = utf8.encode(stringData); + final Uint8List byteData = Uint8List(byteList.length); + byteData.setAll(0, byteList); + setMockAssetData(assetKey, ByteData.sublistView(byteData)); + } + + void clearMocks() { + _assetMap.clear(); + } + + final Map _assetMap = {}; +} + +FakeAssetManager fakeAssetManager = FakeAssetManager(); + +void setUpStandardMocks(FakeAssetManager assetManager) { + const String ahemFontFamily = 'Ahem'; + const String ahemFontUrl = '/assets/fonts/ahem.ttf'; + const String robotoFontFamily = 'Roboto'; + const String robotoTestFontUrl = '/assets/fonts/Roboto-Regular.ttf'; + + assetManager.setMockAssetStringAsUtf8Data('AssetManifest.json', '{}'); + assetManager.setMockAssetStringAsUtf8Data('FontManifest.json', + ''' + [ + { + "family":"$robotoFontFamily", + "fonts":[{"asset":"$robotoTestFontUrl"}] + }, + { + "family":"$ahemFontFamily", + "fonts":[{"asset":"$ahemFontUrl"}] + } + ]'''); +} diff --git a/lib/web_ui/lib/src/engine/test_embedding.dart b/lib/web_ui/test/common/test_embedding.dart similarity index 94% rename from lib/web_ui/lib/src/engine/test_embedding.dart rename to lib/web_ui/test/common/test_embedding.dart index 103830680348e..31a2d79422e1d 100644 --- a/lib/web_ui/lib/src/engine/test_embedding.dart +++ b/lib/web_ui/test/common/test_embedding.dart @@ -2,15 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// TODO(yjbanov): this does not need to be in the production sources. -// https://github.com/flutter/flutter/issues/100394 - import 'dart:async'; +import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; import 'package:ui/ui_web/src/ui_web.dart' as ui_web; -import '../engine.dart'; +import 'fake_asset_manager.dart'; Future? _platformInitializedFuture; @@ -25,14 +23,19 @@ Future initializeTestFlutterViewEmbedder({double devicePixelRatio = 3.0}) window.webOnlyDebugPhysicalSizeOverride = ui.Size(800 * devicePixelRatio, 600 * devicePixelRatio); scheduleFrameCallback = () {}; - ui.debugEmulateFlutterTesterEnvironment = true; + setUpTestEnvironment(); // Initialize platform once and reuse across all tests. if (_platformInitializedFuture != null) { return _platformInitializedFuture!; } - return _platformInitializedFuture = - initializeEngine(assetManager: WebOnlyMockAssetManager()); + setUpStandardMocks(fakeAssetManager); + return _platformInitializedFuture = initializeEngine(assetManager: fakeAssetManager); +} + +void setUpTestEnvironment() { + ui.debugEmulateFlutterTesterEnvironment = true; + debugDefaultUrlStrategy = TestUrlStrategy.fromEntry(const TestHistoryEntry('default', null, '/')); } const bool _debugLogHistoryActions = false; diff --git a/lib/web_ui/test/engine/clipboard_test.dart b/lib/web_ui/test/engine/clipboard_test.dart index 48578bf246b5b..6f4b62785c163 100644 --- a/lib/web_ui/test/engine/clipboard_test.dart +++ b/lib/web_ui/test/engine/clipboard_test.dart @@ -9,6 +9,8 @@ import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; +import '../common/test_embedding.dart'; + void main() { internalBootstrapBrowserTest(() => testMain); } diff --git a/lib/web_ui/test/engine/history_test.dart b/lib/web_ui/test/engine/history_test.dart index 203ab8b5922cf..5263b20f39e74 100644 --- a/lib/web_ui/test/engine/history_test.dart +++ b/lib/web_ui/test/engine/history_test.dart @@ -15,9 +15,9 @@ import 'package:ui/src/engine.dart' show DomEventListener, window; import 'package:ui/src/engine/browser_detection.dart'; import 'package:ui/src/engine/navigation.dart'; import 'package:ui/src/engine/services.dart'; -import 'package:ui/src/engine/test_embedding.dart'; import '../common/spy.dart'; +import '../common/test_embedding.dart'; Map _wrapOriginState(dynamic state) { return {'origin': true, 'state': state}; diff --git a/lib/web_ui/test/engine/image/html_image_codec_test.dart b/lib/web_ui/test/engine/image/html_image_codec_test.dart index 9017fde35d081..7d009e99f6915 100644 --- a/lib/web_ui/test/engine/image/html_image_codec_test.dart +++ b/lib/web_ui/test/engine/image/html_image_codec_test.dart @@ -8,9 +8,10 @@ import 'dart:typed_data'; import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/src/engine/html_image_codec.dart'; -import 'package:ui/src/engine/test_embedding.dart'; import 'package:ui/ui.dart' as ui; +import '../../common/test_embedding.dart'; + void main() { internalBootstrapBrowserTest(() => testMain); } diff --git a/lib/web_ui/test/engine/navigation_test.dart b/lib/web_ui/test/engine/navigation_test.dart index 27ec64e09dd0a..52aebf6a8c077 100644 --- a/lib/web_ui/test/engine/navigation_test.dart +++ b/lib/web_ui/test/engine/navigation_test.dart @@ -9,6 +9,8 @@ import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/src/engine.dart' as engine; +import '../common/test_embedding.dart'; + const engine.MethodCodec codec = engine.JSONMethodCodec(); void emptyCallback(ByteData date) {} @@ -18,10 +20,10 @@ void main() { } void testMain() { - engine.TestUrlStrategy? strategy; + TestUrlStrategy? strategy; setUp(() async { - strategy = engine.TestUrlStrategy(); + strategy = TestUrlStrategy(); await engine.window.debugInitializeHistory(strategy, useSingle: true); }); diff --git a/lib/web_ui/test/engine/recording_canvas_test.dart b/lib/web_ui/test/engine/recording_canvas_test.dart index 72c63f4143fa6..40dabbbc6fdfb 100644 --- a/lib/web_ui/test/engine/recording_canvas_test.dart +++ b/lib/web_ui/test/engine/recording_canvas_test.dart @@ -8,6 +8,7 @@ import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart'; import '../common/mock_engine_canvas.dart'; +import '../common/test_embedding.dart'; import '../html/screenshot.dart'; void main() { @@ -15,7 +16,7 @@ void main() { } void testMain() { - debugEmulateFlutterTesterEnvironment = true; + setUpTestEnvironment(); setUpStableTestFonts(); late RecordingCanvas underTest; diff --git a/lib/web_ui/test/engine/routing_test.dart b/lib/web_ui/test/engine/routing_test.dart index aa1d572102079..503b2b73f05e8 100644 --- a/lib/web_ui/test/engine/routing_test.dart +++ b/lib/web_ui/test/engine/routing_test.dart @@ -11,6 +11,7 @@ import 'package:ui/src/engine.dart' hide window; import 'package:ui/ui.dart' as ui; import '../common/matchers.dart'; +import '../common/test_embedding.dart'; import 'history_test.dart'; const MethodCodec codec = JSONMethodCodec(); diff --git a/lib/web_ui/test/html/canvas_clip_path_golden_test.dart b/lib/web_ui/test/html/canvas_clip_path_golden_test.dart index 7242600b361e6..425e5936da255 100644 --- a/lib/web_ui/test/html/canvas_clip_path_golden_test.dart +++ b/lib/web_ui/test/html/canvas_clip_path_golden_test.dart @@ -9,6 +9,7 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart' as engine; import 'package:ui/ui.dart' hide TextStyle; +import '../common/test_embedding.dart'; import 'screenshot.dart'; void main() { @@ -17,7 +18,7 @@ void main() { Future testMain() async { setUpAll(() async { - debugEmulateFlutterTesterEnvironment = true; + setUpTestEnvironment(); await webOnlyInitializePlatform(); await engine.renderer.fontCollection.debugDownloadTestFonts(); engine.renderer.fontCollection.registerDownloadedFonts(); diff --git a/lib/web_ui/test/html/canvas_context_golden_test.dart b/lib/web_ui/test/html/canvas_context_golden_test.dart index 53a9d30a2e201..4a08c42617356 100644 --- a/lib/web_ui/test/html/canvas_context_golden_test.dart +++ b/lib/web_ui/test/html/canvas_context_golden_test.dart @@ -7,6 +7,7 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart' as engine; import 'package:ui/ui.dart' hide TextStyle; +import '../common/test_embedding.dart'; import 'screenshot.dart'; void main() { @@ -20,7 +21,7 @@ Future testMain() async { const Rect screenRect = Rect.fromLTWH(0, 0, screenWidth, screenHeight); setUpAll(() async { - debugEmulateFlutterTesterEnvironment = true; + setUpTestEnvironment(); await webOnlyInitializePlatform(); await engine.renderer.fontCollection.debugDownloadTestFonts(); engine.renderer.fontCollection.registerDownloadedFonts(); diff --git a/lib/web_ui/test/html/canvas_reuse_golden_test.dart b/lib/web_ui/test/html/canvas_reuse_golden_test.dart index 0757f0851e879..ff37b765e9c15 100644 --- a/lib/web_ui/test/html/canvas_reuse_golden_test.dart +++ b/lib/web_ui/test/html/canvas_reuse_golden_test.dart @@ -9,6 +9,8 @@ import 'package:ui/ui.dart' hide TextStyle; import 'package:web_engine_tester/golden_tester.dart'; +import '../common/test_embedding.dart'; + void main() { internalBootstrapBrowserTest(() => testMain); } @@ -23,7 +25,7 @@ Future testMain() async { ..color = const Color(0xFFFF00FF); setUp(() async { - debugEmulateFlutterTesterEnvironment = true; + setUpTestEnvironment(); await webOnlyInitializePlatform(); await renderer.fontCollection.debugDownloadTestFonts(); renderer.fontCollection.registerDownloadedFonts(); diff --git a/lib/web_ui/test/html/compositing/canvas_blend_golden_test.dart b/lib/web_ui/test/html/compositing/canvas_blend_golden_test.dart index b1851aa4e51b6..6a10cad7c31d4 100644 --- a/lib/web_ui/test/html/compositing/canvas_blend_golden_test.dart +++ b/lib/web_ui/test/html/compositing/canvas_blend_golden_test.dart @@ -9,6 +9,7 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' hide TextStyle; +import '../../common/test_embedding.dart'; import '../screenshot.dart'; void main() { @@ -18,7 +19,7 @@ void main() { Future testMain() async { setUpAll(() async { - debugEmulateFlutterTesterEnvironment = true; + setUpTestEnvironment(); await webOnlyInitializePlatform(); await renderer.fontCollection.debugDownloadTestFonts(); renderer.fontCollection.registerDownloadedFonts(); diff --git a/lib/web_ui/test/html/compositing/canvas_image_blend_mode_golden_test.dart b/lib/web_ui/test/html/compositing/canvas_image_blend_mode_golden_test.dart index 3b985102d4f4c..c7779c769d3ab 100644 --- a/lib/web_ui/test/html/compositing/canvas_image_blend_mode_golden_test.dart +++ b/lib/web_ui/test/html/compositing/canvas_image_blend_mode_golden_test.dart @@ -7,6 +7,7 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' hide TextStyle; +import '../../common/test_embedding.dart'; import '../screenshot.dart'; import '../testimage.dart'; @@ -18,7 +19,7 @@ SurfacePaint makePaint() => Paint() as SurfacePaint; Future testMain() async { setUpAll(() async { - debugEmulateFlutterTesterEnvironment = true; + setUpTestEnvironment(); await webOnlyInitializePlatform(); await renderer.fontCollection.debugDownloadTestFonts(); renderer.fontCollection.registerDownloadedFonts(); diff --git a/lib/web_ui/test/html/compositing/canvas_mask_filter_golden_test.dart b/lib/web_ui/test/html/compositing/canvas_mask_filter_golden_test.dart index 03e8b8d2ccf5b..a088e27c3a38e 100644 --- a/lib/web_ui/test/html/compositing/canvas_mask_filter_golden_test.dart +++ b/lib/web_ui/test/html/compositing/canvas_mask_filter_golden_test.dart @@ -10,6 +10,7 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; +import '../../common/test_embedding.dart'; import '../screenshot.dart'; void main() { @@ -18,7 +19,7 @@ void main() { Future testMain() async { setUpAll(() async { - ui.debugEmulateFlutterTesterEnvironment = true; + setUpTestEnvironment(); await ui.webOnlyInitializePlatform(); await renderer.fontCollection.debugDownloadTestFonts(); renderer.fontCollection.registerDownloadedFonts(); diff --git a/lib/web_ui/test/html/compositing/dom_mask_filter_golden_test.dart b/lib/web_ui/test/html/compositing/dom_mask_filter_golden_test.dart index bf7e63d20fb0e..d381988e1c77f 100644 --- a/lib/web_ui/test/html/compositing/dom_mask_filter_golden_test.dart +++ b/lib/web_ui/test/html/compositing/dom_mask_filter_golden_test.dart @@ -6,6 +6,7 @@ import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' hide TextStyle; +import '../../common/test_embedding.dart'; import '../screenshot.dart'; void main() { @@ -14,7 +15,7 @@ void main() { Future testMain() async { setUp(() async { - debugEmulateFlutterTesterEnvironment = true; + setUpTestEnvironment(); await webOnlyInitializePlatform(); await renderer.fontCollection.debugDownloadTestFonts(); renderer.fontCollection.registerDownloadedFonts(); diff --git a/lib/web_ui/test/html/drawing/canvas_draw_image_golden_test.dart b/lib/web_ui/test/html/drawing/canvas_draw_image_golden_test.dart index ad86f7ad77b9e..b60e23ba6bbc5 100644 --- a/lib/web_ui/test/html/drawing/canvas_draw_image_golden_test.dart +++ b/lib/web_ui/test/html/drawing/canvas_draw_image_golden_test.dart @@ -14,6 +14,7 @@ import 'package:ui/ui.dart'; import 'package:web_engine_tester/golden_tester.dart'; +import '../../common/test_embedding.dart'; import '../screenshot.dart'; void main() { @@ -23,7 +24,7 @@ void main() { Future testMain() async { setUp(() async { - debugEmulateFlutterTesterEnvironment = true; + setUpTestEnvironment(); }); setUpStableTestFonts(); diff --git a/lib/web_ui/test/html/drawing/draw_vertices_golden_test.dart b/lib/web_ui/test/html/drawing/draw_vertices_golden_test.dart index 4790ff9bd4e43..54ae158e201a9 100644 --- a/lib/web_ui/test/html/drawing/draw_vertices_golden_test.dart +++ b/lib/web_ui/test/html/drawing/draw_vertices_golden_test.dart @@ -11,6 +11,7 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' hide ImageShader, TextStyle; +import '../../common/test_embedding.dart'; import '../screenshot.dart'; void main() { @@ -23,7 +24,7 @@ Future testMain() async { const Rect screenRect = Rect.fromLTWH(0, 0, screenWidth, screenHeight); setUpAll(() async { - debugEmulateFlutterTesterEnvironment = true; + setUpTestEnvironment(); await webOnlyInitializePlatform(); await renderer.fontCollection.debugDownloadTestFonts(); renderer.fontCollection.registerDownloadedFonts(); diff --git a/lib/web_ui/test/html/path_metrics_golden_test.dart b/lib/web_ui/test/html/path_metrics_golden_test.dart index 4a3ea96f7288d..a0861028b496b 100644 --- a/lib/web_ui/test/html/path_metrics_golden_test.dart +++ b/lib/web_ui/test/html/path_metrics_golden_test.dart @@ -8,6 +8,7 @@ import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' hide TextStyle; import '../common/matchers.dart'; +import '../common/test_embedding.dart'; import 'screenshot.dart'; void main() { @@ -23,7 +24,7 @@ Future testMain() async { const double kDashLength = 5.0; setUpAll(() async { - debugEmulateFlutterTesterEnvironment = true; + setUpTestEnvironment(); await webOnlyInitializePlatform(); await renderer.fontCollection.debugDownloadTestFonts(); renderer.fontCollection.registerDownloadedFonts(); diff --git a/lib/web_ui/test/html/path_transform_golden_test.dart b/lib/web_ui/test/html/path_transform_golden_test.dart index cb5b398169540..0472b7fe83c02 100644 --- a/lib/web_ui/test/html/path_transform_golden_test.dart +++ b/lib/web_ui/test/html/path_transform_golden_test.dart @@ -9,6 +9,7 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' hide TextStyle; +import '../common/test_embedding.dart'; import 'screenshot.dart'; void main() { @@ -21,7 +22,7 @@ Future testMain() async { const Rect screenRect = Rect.fromLTWH(0, 0, screenWidth, screenHeight); setUpAll(() async { - debugEmulateFlutterTesterEnvironment = true; + setUpTestEnvironment(); await webOnlyInitializePlatform(); await renderer.fontCollection.debugDownloadTestFonts(); renderer.fontCollection.registerDownloadedFonts(); diff --git a/lib/web_ui/test/html/recording_canvas_golden_test.dart b/lib/web_ui/test/html/recording_canvas_golden_test.dart index 3a32e02830ed7..4144e6785c6f6 100644 --- a/lib/web_ui/test/html/recording_canvas_golden_test.dart +++ b/lib/web_ui/test/html/recording_canvas_golden_test.dart @@ -12,6 +12,7 @@ import 'package:ui/ui.dart' hide TextStyle; import 'package:web_engine_tester/golden_tester.dart'; import '../common/matchers.dart'; +import '../common/test_embedding.dart'; import 'screenshot.dart'; void main() { @@ -20,7 +21,7 @@ void main() { Future testMain() async { setUpAll(() async { - debugEmulateFlutterTesterEnvironment = true; + setUpTestEnvironment(); }); setUpStableTestFonts(); diff --git a/lib/web_ui/test/html/shaders/gradient_golden_test.dart b/lib/web_ui/test/html/shaders/gradient_golden_test.dart index 5aebc78ef0070..ba0b5de869741 100644 --- a/lib/web_ui/test/html/shaders/gradient_golden_test.dart +++ b/lib/web_ui/test/html/shaders/gradient_golden_test.dart @@ -10,6 +10,7 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart'; +import '../../common/test_embedding.dart'; import '../screenshot.dart'; // TODO(yjbanov): unskip Firefox tests when Firefox implements WebGL in headless mode. @@ -26,7 +27,7 @@ Future testMain() async { const Rect region = Rect.fromLTWH(0, 0, 500, 240); setUp(() async { - debugEmulateFlutterTesterEnvironment = true; + setUpTestEnvironment(); }); setUpStableTestFonts(); diff --git a/lib/web_ui/test/html/shaders/image_shader_golden_test.dart b/lib/web_ui/test/html/shaders/image_shader_golden_test.dart index 405250062d462..3e0d56eefe43d 100644 --- a/lib/web_ui/test/html/shaders/image_shader_golden_test.dart +++ b/lib/web_ui/test/html/shaders/image_shader_golden_test.dart @@ -9,6 +9,7 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' hide TextStyle; +import '../../common/test_embedding.dart'; import '../screenshot.dart'; // TODO(yjbanov): unskip Firefox tests when Firefox implements WebGL in headless mode. @@ -25,7 +26,7 @@ Future testMain() async { final HtmlImage testImage = createTestImage(); setUpAll(() async { - debugEmulateFlutterTesterEnvironment = true; + setUpTestEnvironment(); await webOnlyInitializePlatform(); await renderer.fontCollection.debugDownloadTestFonts(); renderer.fontCollection.registerDownloadedFonts(); diff --git a/lib/web_ui/test/html/shaders/linear_gradient_golden_test.dart b/lib/web_ui/test/html/shaders/linear_gradient_golden_test.dart index 742067e4914e0..b886aa0e934cf 100644 --- a/lib/web_ui/test/html/shaders/linear_gradient_golden_test.dart +++ b/lib/web_ui/test/html/shaders/linear_gradient_golden_test.dart @@ -8,6 +8,7 @@ import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' hide TextStyle; +import '../../common/test_embedding.dart'; import '../screenshot.dart'; // TODO(yjbanov): unskip Firefox tests when Firefox implements WebGL in headless mode. @@ -19,7 +20,7 @@ void main() { Future testMain() async { setUpAll(() async { - debugEmulateFlutterTesterEnvironment = true; + setUpTestEnvironment(); await webOnlyInitializePlatform(); await renderer.fontCollection.debugDownloadTestFonts(); renderer.fontCollection.registerDownloadedFonts(); diff --git a/lib/web_ui/test/html/shaders/radial_gradient_golden_test.dart b/lib/web_ui/test/html/shaders/radial_gradient_golden_test.dart index 51bfab70965a1..6e6ef40c5d830 100644 --- a/lib/web_ui/test/html/shaders/radial_gradient_golden_test.dart +++ b/lib/web_ui/test/html/shaders/radial_gradient_golden_test.dart @@ -6,6 +6,7 @@ import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' hide TextStyle; +import '../../common/test_embedding.dart'; import '../screenshot.dart'; void main() { @@ -15,7 +16,7 @@ void main() { Future testMain() async { setUpAll(() async { - debugEmulateFlutterTesterEnvironment = true; + setUpTestEnvironment(); await webOnlyInitializePlatform(); await renderer.fontCollection.debugDownloadTestFonts(); renderer.fontCollection.registerDownloadedFonts(); diff --git a/lib/web_ui/test/text/canvas_paragraph_builder_test.dart b/lib/web_ui/test/html/text/canvas_paragraph_builder_test.dart similarity index 99% rename from lib/web_ui/test/text/canvas_paragraph_builder_test.dart rename to lib/web_ui/test/html/text/canvas_paragraph_builder_test.dart index 0989d248bdb53..b5910cc7de31d 100644 --- a/lib/web_ui/test/text/canvas_paragraph_builder_test.dart +++ b/lib/web_ui/test/html/text/canvas_paragraph_builder_test.dart @@ -7,7 +7,8 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart'; -import '../html/paragraph/helper.dart'; +import '../../common/test_embedding.dart'; +import '../paragraph/helper.dart'; /// Some text measurements are sensitive to browser implementations. Position /// info in the following tests only pass in Chrome, they are slightly different diff --git a/lib/web_ui/test/text/canvas_paragraph_test.dart b/lib/web_ui/test/html/text/canvas_paragraph_test.dart similarity index 99% rename from lib/web_ui/test/text/canvas_paragraph_test.dart rename to lib/web_ui/test/html/text/canvas_paragraph_test.dart index c7dbbecabf059..a887ccbe68c4a 100644 --- a/lib/web_ui/test/text/canvas_paragraph_test.dart +++ b/lib/web_ui/test/html/text/canvas_paragraph_test.dart @@ -7,7 +7,8 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; -import '../html/paragraph/helper.dart'; +import '../../common/test_embedding.dart'; +import '../paragraph/helper.dart'; void main() { internalBootstrapBrowserTest(() => testMain); diff --git a/lib/web_ui/test/text/font_collection_test.dart b/lib/web_ui/test/html/text/font_collection_test.dart similarity index 100% rename from lib/web_ui/test/text/font_collection_test.dart rename to lib/web_ui/test/html/text/font_collection_test.dart diff --git a/lib/web_ui/test/text/font_loading_test.dart b/lib/web_ui/test/html/text/font_loading_test.dart similarity index 98% rename from lib/web_ui/test/text/font_loading_test.dart rename to lib/web_ui/test/html/text/font_loading_test.dart index d96ca6acb22f0..64b2e34f0db2b 100644 --- a/lib/web_ui/test/text/font_loading_test.dart +++ b/lib/web_ui/test/html/text/font_loading_test.dart @@ -11,6 +11,8 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; +import '../../common/test_embedding.dart'; + void main() { internalBootstrapBrowserTest(() => testMain); } diff --git a/lib/web_ui/test/text/layout_fragmenter_test.dart b/lib/web_ui/test/html/text/layout_fragmenter_test.dart similarity index 99% rename from lib/web_ui/test/text/layout_fragmenter_test.dart rename to lib/web_ui/test/html/text/layout_fragmenter_test.dart index a36dc89433db7..fe8a8ca5a2852 100644 --- a/lib/web_ui/test/text/layout_fragmenter_test.dart +++ b/lib/web_ui/test/html/text/layout_fragmenter_test.dart @@ -7,7 +7,7 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart'; -import '../html/paragraph/helper.dart'; +import '../paragraph/helper.dart'; final EngineTextStyle defaultStyle = EngineTextStyle.only( color: const Color(0xFFFF0000), diff --git a/lib/web_ui/test/text/layout_service_helper.dart b/lib/web_ui/test/html/text/layout_service_helper.dart similarity index 100% rename from lib/web_ui/test/text/layout_service_helper.dart rename to lib/web_ui/test/html/text/layout_service_helper.dart diff --git a/lib/web_ui/test/text/layout_service_plain_test.dart b/lib/web_ui/test/html/text/layout_service_plain_test.dart similarity index 99% rename from lib/web_ui/test/text/layout_service_plain_test.dart rename to lib/web_ui/test/html/text/layout_service_plain_test.dart index 96c3e047cecd3..348a61639233e 100644 --- a/lib/web_ui/test/text/layout_service_plain_test.dart +++ b/lib/web_ui/test/html/text/layout_service_plain_test.dart @@ -7,7 +7,8 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; -import '../html/paragraph/helper.dart'; +import '../../common/test_embedding.dart'; +import '../paragraph/helper.dart'; import 'layout_service_helper.dart'; const bool skipWordSpacing = true; diff --git a/lib/web_ui/test/text/layout_service_rich_test.dart b/lib/web_ui/test/html/text/layout_service_rich_test.dart similarity index 99% rename from lib/web_ui/test/text/layout_service_rich_test.dart rename to lib/web_ui/test/html/text/layout_service_rich_test.dart index 381da5e228183..8fbdee7602b2e 100644 --- a/lib/web_ui/test/text/layout_service_rich_test.dart +++ b/lib/web_ui/test/html/text/layout_service_rich_test.dart @@ -8,7 +8,8 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; -import '../html/paragraph/helper.dart'; +import '../../common/test_embedding.dart'; +import '../paragraph/helper.dart'; import 'layout_service_helper.dart'; void main() { diff --git a/lib/web_ui/test/text/line_breaker_test.dart b/lib/web_ui/test/html/text/line_breaker_test.dart similarity index 99% rename from lib/web_ui/test/text/line_breaker_test.dart rename to lib/web_ui/test/html/text/line_breaker_test.dart index 275c4de47b60f..2bd99fcc20e4d 100644 --- a/lib/web_ui/test/text/line_breaker_test.dart +++ b/lib/web_ui/test/html/text/line_breaker_test.dart @@ -8,7 +8,7 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart'; -import '../html/paragraph/helper.dart'; +import '../paragraph/helper.dart'; import 'line_breaker_test_helper.dart'; import 'line_breaker_test_raw_data.dart'; diff --git a/lib/web_ui/test/text/line_breaker_test_helper.dart b/lib/web_ui/test/html/text/line_breaker_test_helper.dart similarity index 100% rename from lib/web_ui/test/text/line_breaker_test_helper.dart rename to lib/web_ui/test/html/text/line_breaker_test_helper.dart diff --git a/lib/web_ui/test/text/line_breaker_test_raw_data.dart b/lib/web_ui/test/html/text/line_breaker_test_raw_data.dart similarity index 100% rename from lib/web_ui/test/text/line_breaker_test_raw_data.dart rename to lib/web_ui/test/html/text/line_breaker_test_raw_data.dart diff --git a/lib/web_ui/test/text/text_direction_test.dart b/lib/web_ui/test/html/text/text_direction_test.dart similarity index 99% rename from lib/web_ui/test/text/text_direction_test.dart rename to lib/web_ui/test/html/text/text_direction_test.dart index 3c39220c0159e..9049c0948ef54 100644 --- a/lib/web_ui/test/text/text_direction_test.dart +++ b/lib/web_ui/test/html/text/text_direction_test.dart @@ -7,7 +7,7 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart'; -import '../html/paragraph/helper.dart'; +import '../paragraph/helper.dart'; void main() { internalBootstrapBrowserTest(() => testMain); diff --git a/lib/web_ui/test/text/word_breaker_test.dart b/lib/web_ui/test/html/text/word_breaker_test.dart similarity index 100% rename from lib/web_ui/test/text/word_breaker_test.dart rename to lib/web_ui/test/html/text/word_breaker_test.dart diff --git a/lib/web_ui/test/html/text_test.dart b/lib/web_ui/test/html/text_test.dart index 2b7e629fb2917..a04338c74c66e 100644 --- a/lib/web_ui/test/html/text_test.dart +++ b/lib/web_ui/test/html/text_test.dart @@ -12,6 +12,7 @@ import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart'; import '../common/matchers.dart'; +import '../common/test_embedding.dart'; import 'paragraph/helper.dart'; void main() { diff --git a/lib/web_ui/test/ui/fragment_shader_test.dart b/lib/web_ui/test/ui/fragment_shader_test.dart index 1fef73e8e0f55..4b2cdfd283863 100644 --- a/lib/web_ui/test/ui/fragment_shader_test.dart +++ b/lib/web_ui/test/ui/fragment_shader_test.dart @@ -2,15 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:convert'; -import 'dart:typed_data'; - import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; import 'package:web_engine_tester/golden_tester.dart'; +import '../common/fake_asset_manager.dart'; import 'utils.dart'; void main() { @@ -45,9 +43,9 @@ Future testMain() async { const ui.Rect region = ui.Rect.fromLTWH(0, 0, 300, 300); test('fragment shader', () async { - fakeAssetManager.setAsset( + fakeAssetManager.setMockAssetStringAsUtf8Data( 'voronoi_shader', - Uint8List.fromList(utf8.encode(kVoronoiShaderSksl)).buffer.asByteData() + kVoronoiShaderSksl ); final ui.FragmentProgram program = await renderer.createFragmentProgram('voronoi_shader'); final ui.FragmentShader shader = program.fragmentShader(); diff --git a/lib/web_ui/test/ui/utils.dart b/lib/web_ui/test/ui/utils.dart index 01b42125383bb..933768d69b7e6 100644 --- a/lib/web_ui/test/ui/utils.dart +++ b/lib/web_ui/test/ui/utils.dart @@ -4,50 +4,20 @@ import 'dart:async'; import 'dart:js_interop'; -import 'dart:typed_data'; import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/src/engine/skwasm/skwasm_stub.dart' if (dart.library.ffi) 'package:ui/src/engine/skwasm/skwasm_impl.dart'; import 'package:ui/ui.dart'; -class FakeAssetManager implements AssetManager { - FakeAssetManager(this._parent); - - @override - String get assetsDir => 'assets'; - - @override - String getAssetUrl(String asset) => asset; - - @override - Future load(String assetKey) async { - final ByteData? data = _assetMap[assetKey]; - if (data == null) { - return _parent.load(assetKey); - } - return data; - } - - @override - Future loadAsset(String asset) { - return _parent.loadAsset(asset); - } - - void setAsset(String assetKey, ByteData assetData) { - _assetMap[assetKey] = assetData; - } - - final Map _assetMap = {}; - final AssetManager _parent; -} - -FakeAssetManager fakeAssetManager = FakeAssetManager(WebOnlyMockAssetManager()); +import '../common/fake_asset_manager.dart'; +import '../common/test_embedding.dart'; /// Initializes the renderer for this test. void setUpUiTest() { setUpAll(() async { - debugEmulateFlutterTesterEnvironment = true; + setUpTestEnvironment(); + setUpStandardMocks(fakeAssetManager); await initializeEngine(assetManager: fakeAssetManager); await renderer.fontCollection.debugDownloadTestFonts(); renderer.fontCollection.registerDownloadedFonts(); From bf1f0fea4322880c8ec2ede840e2ad25155fa2ce Mon Sep 17 00:00:00 2001 From: Jackson Gardner Date: Mon, 17 Apr 2023 18:10:19 -0700 Subject: [PATCH 11/30] Update licenses golden. --- ci/licenses_golden/licenses_flutter | 2 -- 1 file changed, 2 deletions(-) diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 260116fef2705..b0860f510d2a0 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -2024,7 +2024,6 @@ ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/vertices.d ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_stub.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_stub/renderer.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/svg.dart + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/test_embedding.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/text/canvas_paragraph.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/text/font_collection.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/text/fragmenter.dart + ../../../flutter/LICENSE @@ -4627,7 +4626,6 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/vertices.dar FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_stub.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_stub/renderer.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/svg.dart -FILE: ../../../flutter/lib/web_ui/lib/src/engine/test_embedding.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/text/canvas_paragraph.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/text/font_collection.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/text/fragmenter.dart From f748764a09b4ada2616668334ee7a7b55b846460 Mon Sep 17 00:00:00 2001 From: Jackson Gardner Date: Tue, 18 Apr 2023 17:06:57 -0700 Subject: [PATCH 12/30] Reverted some of the test reorganization stuff that the framework was relying on. --- lib/web_ui/lib/src/engine.dart | 1 + lib/web_ui/lib/src/engine/assets.dart | 76 +++++++++++++++++ .../src/engine}/test_embedding.dart | 17 ++-- lib/web_ui/lib/src/engine/window.dart | 10 +-- lib/web_ui/test/canvaskit/common.dart | 5 +- .../flutter_tester_emulation_golden_test.dart | 3 +- .../canvaskit/skia_font_collection_test.dart | 36 ++++---- .../test/common/fake_asset_manager.dart | 83 ------------------- lib/web_ui/test/engine/clipboard_test.dart | 2 - lib/web_ui/test/engine/history_test.dart | 2 +- .../engine/image/html_image_codec_test.dart | 3 +- lib/web_ui/test/engine/navigation_test.dart | 6 +- .../test/engine/recording_canvas_test.dart | 3 +- lib/web_ui/test/engine/routing_test.dart | 1 - .../html/canvas_clip_path_golden_test.dart | 3 +- .../test/html/canvas_context_golden_test.dart | 3 +- .../test/html/canvas_reuse_golden_test.dart | 4 +- .../compositing/canvas_blend_golden_test.dart | 3 +- .../canvas_image_blend_mode_golden_test.dart | 3 +- .../canvas_mask_filter_golden_test.dart | 3 +- .../dom_mask_filter_golden_test.dart | 3 +- .../canvas_draw_image_golden_test.dart | 3 +- .../drawing/draw_vertices_golden_test.dart | 3 +- .../test/html/path_metrics_golden_test.dart | 3 +- .../test/html/path_transform_golden_test.dart | 3 +- .../html/recording_canvas_golden_test.dart | 3 +- .../html/shaders/gradient_golden_test.dart | 3 +- .../shaders/image_shader_golden_test.dart | 3 +- .../shaders/linear_gradient_golden_test.dart | 3 +- .../shaders/radial_gradient_golden_test.dart | 3 +- .../text/canvas_paragraph_builder_test.dart | 1 - .../test/html/text/canvas_paragraph_test.dart | 1 - .../test/html/text/font_loading_test.dart | 2 - .../html/text/layout_service_plain_test.dart | 1 - .../html/text/layout_service_rich_test.dart | 1 - lib/web_ui/test/html/text_test.dart | 1 - lib/web_ui/test/ui/fragment_shader_test.dart | 8 +- lib/web_ui/test/ui/utils.dart | 38 ++++++++- 38 files changed, 167 insertions(+), 183 deletions(-) rename lib/web_ui/{test/common => lib/src/engine}/test_embedding.dart (94%) delete mode 100644 lib/web_ui/test/common/fake_asset_manager.dart diff --git a/lib/web_ui/lib/src/engine.dart b/lib/web_ui/lib/src/engine.dart index 6b2c0879cb4ed..808b7898a9251 100644 --- a/lib/web_ui/lib/src/engine.dart +++ b/lib/web_ui/lib/src/engine.dart @@ -150,6 +150,7 @@ export 'engine/services/serialization.dart'; export 'engine/shader_data.dart'; export 'engine/shadow.dart'; export 'engine/svg.dart'; +export 'engine/test_embedding.dart'; export 'engine/text/canvas_paragraph.dart'; export 'engine/text/font_collection.dart'; export 'engine/text/fragmenter.dart'; diff --git a/lib/web_ui/lib/src/engine/assets.dart b/lib/web_ui/lib/src/engine/assets.dart index 51a4acb77d91a..b200f824e4145 100644 --- a/lib/web_ui/lib/src/engine/assets.dart +++ b/lib/web_ui/lib/src/engine/assets.dart @@ -110,3 +110,79 @@ class AssetManager { return (await response.payload.asByteBuffer()).asByteData(); } } + +/// An asset manager that gives fake empty responses for assets. +class WebOnlyMockAssetManager extends AssetManager { + /// Mock asset directory relative to base url. + String defaultAssetsDir = ''; + + /// Mock empty asset manifest. + String defaultAssetManifest = '{}'; + + /// Mock font manifest overridable for unit testing. + String defaultFontManifest = ''' + [ + { + "family":"$robotoFontFamily", + "fonts":[{"asset":"$robotoTestFontUrl"}] + }, + { + "family":"$ahemFontFamily", + "fonts":[{"asset":"$ahemFontUrl"}] + } + ]'''; + + @override + String get assetsDir => defaultAssetsDir; + + @override + String getAssetUrl(String asset) => asset; + + @override + Future loadAsset(String asset) async { + if (asset == getAssetUrl('AssetManifest.json')) { + return MockHttpFetchResponse( + url: asset, + status: 200, + payload: MockHttpFetchPayload( + byteBuffer: _toByteData(utf8.encode(defaultAssetManifest)).buffer, + ), + ); + } + if (asset == getAssetUrl('FontManifest.json')) { + return MockHttpFetchResponse( + url: asset, + status: 200, + payload: MockHttpFetchPayload( + byteBuffer: _toByteData(utf8.encode(defaultFontManifest)).buffer, + ), + ); + } + + return MockHttpFetchResponse( + url: asset, + status: 404, + ); + } + + @override + Future load(String asset) { + if (asset == getAssetUrl('AssetManifest.json')) { + return Future.value( + _toByteData(utf8.encode(defaultAssetManifest))); + } + if (asset == getAssetUrl('FontManifest.json')) { + return Future.value( + _toByteData(utf8.encode(defaultFontManifest))); + } + throw HttpFetchNoPayloadError(asset, status: 404); + } + + ByteData _toByteData(List bytes) { + final ByteData byteData = ByteData(bytes.length); + for (int i = 0; i < bytes.length; i++) { + byteData.setUint8(i, bytes[i]); + } + return byteData; + } +} diff --git a/lib/web_ui/test/common/test_embedding.dart b/lib/web_ui/lib/src/engine/test_embedding.dart similarity index 94% rename from lib/web_ui/test/common/test_embedding.dart rename to lib/web_ui/lib/src/engine/test_embedding.dart index 31a2d79422e1d..103830680348e 100644 --- a/lib/web_ui/test/common/test_embedding.dart +++ b/lib/web_ui/lib/src/engine/test_embedding.dart @@ -2,13 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// TODO(yjbanov): this does not need to be in the production sources. +// https://github.com/flutter/flutter/issues/100394 + import 'dart:async'; -import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; import 'package:ui/ui_web/src/ui_web.dart' as ui_web; -import 'fake_asset_manager.dart'; +import '../engine.dart'; Future? _platformInitializedFuture; @@ -23,19 +25,14 @@ Future initializeTestFlutterViewEmbedder({double devicePixelRatio = 3.0}) window.webOnlyDebugPhysicalSizeOverride = ui.Size(800 * devicePixelRatio, 600 * devicePixelRatio); scheduleFrameCallback = () {}; - setUpTestEnvironment(); + ui.debugEmulateFlutterTesterEnvironment = true; // Initialize platform once and reuse across all tests. if (_platformInitializedFuture != null) { return _platformInitializedFuture!; } - setUpStandardMocks(fakeAssetManager); - return _platformInitializedFuture = initializeEngine(assetManager: fakeAssetManager); -} - -void setUpTestEnvironment() { - ui.debugEmulateFlutterTesterEnvironment = true; - debugDefaultUrlStrategy = TestUrlStrategy.fromEntry(const TestHistoryEntry('default', null, '/')); + return _platformInitializedFuture = + initializeEngine(assetManager: WebOnlyMockAssetManager()); } const bool _debugLogHistoryActions = false; diff --git a/lib/web_ui/lib/src/engine/window.dart b/lib/web_ui/lib/src/engine/window.dart index 03f710a8e7fcc..720611ec1f536 100644 --- a/lib/web_ui/lib/src/engine/window.dart +++ b/lib/web_ui/lib/src/engine/window.dart @@ -20,6 +20,7 @@ import 'navigation/js_url_strategy.dart'; import 'navigation/url_strategy.dart'; import 'platform_dispatcher.dart'; import 'services.dart'; +import 'test_embedding.dart'; import 'util.dart'; typedef _HandleMessageCallBack = Future Function(); @@ -349,13 +350,10 @@ typedef _JsSetUrlStrategy = void Function(JsUrlStrategy?); @JS('_flutter_web_set_location_strategy') external set jsSetUrlStrategy(_JsSetUrlStrategy? newJsSetUrlStrategy); -ui_web.UrlStrategy? debugDefaultUrlStrategy; - ui_web.UrlStrategy? _createDefaultUrlStrategy() { - if (ui.debugEmulateFlutterTesterEnvironment && debugDefaultUrlStrategy != null) { - return debugDefaultUrlStrategy; - } - return const HashUrlStrategy(); + return ui.debugEmulateFlutterTesterEnvironment + ? TestUrlStrategy.fromEntry(const TestHistoryEntry('default', null, '/')) + : const HashUrlStrategy(); } /// The Web implementation of [ui.SingletonFlutterWindow]. diff --git a/lib/web_ui/test/canvaskit/common.dart b/lib/web_ui/test/canvaskit/common.dart index ffe0ba1876d5c..68d88c0396dca 100644 --- a/lib/web_ui/test/canvaskit/common.dart +++ b/lib/web_ui/test/canvaskit/common.dart @@ -11,8 +11,6 @@ import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; import 'package:web_engine_tester/golden_tester.dart'; -import '../common/fake_asset_manager.dart'; - /// Used in tests instead of [ProductionCollector] to control Skia object /// collection explicitly, and to prevent leaks across tests. /// @@ -27,8 +25,7 @@ void setUpCanvasKitTest() { expect(renderer, isA(), reason: 'This test must run in CanvasKit mode.'); debugResetBrowserSupportsFinalizationRegistry(); debugDisableFontFallbacks = false; - setUpStandardMocks(fakeAssetManager); - await initializeEngine(assetManager: fakeAssetManager); + await initializeEngine(assetManager: WebOnlyMockAssetManager()); }); setUp(() async { diff --git a/lib/web_ui/test/canvaskit/flutter_tester_emulation_golden_test.dart b/lib/web_ui/test/canvaskit/flutter_tester_emulation_golden_test.dart index 4b08b11666837..81a2c340ff7b3 100644 --- a/lib/web_ui/test/canvaskit/flutter_tester_emulation_golden_test.dart +++ b/lib/web_ui/test/canvaskit/flutter_tester_emulation_golden_test.dart @@ -7,7 +7,6 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; -import '../common/test_embedding.dart'; import 'common.dart'; void main() { @@ -17,7 +16,7 @@ void main() { const ui.Rect kDefaultRegion = ui.Rect.fromLTRB(0, 0, 500, 250); void testMain() { - setUpTestEnvironment(); + ui.debugEmulateFlutterTesterEnvironment = true; group('flutter_tester emulation', () { setUpCanvasKitTest(); diff --git a/lib/web_ui/test/canvaskit/skia_font_collection_test.dart b/lib/web_ui/test/canvaskit/skia_font_collection_test.dart index 181cc6b33dc97..75764a8c35f4f 100644 --- a/lib/web_ui/test/canvaskit/skia_font_collection_test.dart +++ b/lib/web_ui/test/canvaskit/skia_font_collection_test.dart @@ -9,8 +9,6 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; -import '../common/fake_asset_manager.dart'; - void main() { internalBootstrapBrowserTest(() => testMain); } @@ -44,8 +42,8 @@ void testMain() { test('logs no warnings with the default mock asset manager', () async { final SkiaFontCollection fontCollection = SkiaFontCollection(); - final FakeAssetManager mockAssetManager = FakeAssetManager(); - setUpStandardMocks(mockAssetManager); + final WebOnlyMockAssetManager mockAssetManager = + WebOnlyMockAssetManager(); await fontCollection.downloadAssetFonts(mockAssetManager); fontCollection.registerDownloadedFonts(); @@ -63,9 +61,9 @@ void testMain() { ); }; final SkiaFontCollection fontCollection = SkiaFontCollection(); - final FakeAssetManager mockAssetManager = FakeAssetManager(); - setUpStandardMocks(mockAssetManager); - mockAssetManager.setMockAssetStringAsUtf8Data('FontManifest.json', ''' + final WebOnlyMockAssetManager mockAssetManager = + WebOnlyMockAssetManager(); + mockAssetManager.defaultFontManifest = ''' [ { "family":"Roboto", @@ -76,7 +74,7 @@ void testMain() { "fonts":[{"asset":"packages/bogus/BrokenFont.ttf"}] } ] - '''); + '''; // It should complete without error, but emit a warning about BrokenFont. await fontCollection.downloadAssetFonts(mockAssetManager); fontCollection.registerDownloadedFonts(); @@ -93,9 +91,9 @@ void testMain() { test('logs an HTTP warning if one of the registered fonts is missing (404 file not found)', () async { final SkiaFontCollection fontCollection = SkiaFontCollection(); - final FakeAssetManager mockAssetManager = FakeAssetManager(); - setUpStandardMocks(mockAssetManager); - mockAssetManager.setMockAssetStringAsUtf8Data('FontManifest.json', ''' + final WebOnlyMockAssetManager mockAssetManager = + WebOnlyMockAssetManager(); + mockAssetManager.defaultFontManifest = ''' [ { "family":"Roboto", @@ -106,7 +104,7 @@ void testMain() { "fonts":[{"asset":"packages/bogus/ThisFontDoesNotExist.ttf"}] } ] - '''); + '''; // It should complete without error, but emit a warning about ThisFontDoesNotExist. await fontCollection.downloadAssetFonts(mockAssetManager); @@ -122,16 +120,16 @@ void testMain() { test('prioritizes Ahem loaded via FontManifest.json', () async { final SkiaFontCollection fontCollection = SkiaFontCollection(); - final FakeAssetManager mockAssetManager = FakeAssetManager(); - setUpStandardMocks(mockAssetManager); - mockAssetManager.setMockAssetStringAsUtf8Data('FontManifest.json', ''' + final WebOnlyMockAssetManager mockAssetManager = + WebOnlyMockAssetManager(); + mockAssetManager.defaultFontManifest = ''' [ { "family":"Ahem", "fonts":[{"asset":"/assets/fonts/Roboto-Regular.ttf"}] } ] - '''.trim()); + '''.trim(); final ByteBuffer robotoData = await httpFetchByteBuffer('/assets/fonts/Roboto-Regular.ttf'); @@ -151,9 +149,9 @@ void testMain() { test('falls back to default Ahem URL', () async { final SkiaFontCollection fontCollection = SkiaFontCollection(); - final FakeAssetManager mockAssetManager = FakeAssetManager(); - setUpStandardMocks(mockAssetManager); - mockAssetManager.setMockAssetStringAsUtf8Data('FontManifest.json', '[]'); + final WebOnlyMockAssetManager mockAssetManager = + WebOnlyMockAssetManager(); + mockAssetManager.defaultFontManifest = '[]'; final ByteBuffer ahemData = await httpFetchByteBuffer('/assets/fonts/ahem.ttf'); diff --git a/lib/web_ui/test/common/fake_asset_manager.dart b/lib/web_ui/test/common/fake_asset_manager.dart deleted file mode 100644 index a21a5ebe4549a..0000000000000 --- a/lib/web_ui/test/common/fake_asset_manager.dart +++ /dev/null @@ -1,83 +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:convert'; -import 'dart:typed_data'; - -import 'package:ui/src/engine.dart'; - -class FakeAssetManager implements AssetManager { - @override - String get assetsDir => 'assets'; - - @override - String getAssetUrl(String asset) => asset; - - @override - Future load(String assetKey) async { - final ByteData? data = _assetMap[assetKey]; - if (data == null) { - throw HttpFetchNoPayloadError(assetKey, status: 404); - } - return data; - } - - @override - Future loadAsset(String assetKey) async { - final ByteData? data = _assetMap[assetKey]; - if (data == null) { - return MockHttpFetchResponse( - url: getAssetUrl(assetKey), - status: 404, - ); - } - return MockHttpFetchResponse( - url: getAssetUrl(assetKey), - status: 200, - payload: MockHttpFetchPayload( - byteBuffer: data.buffer, - ), - ); - } - - void setMockAssetData(String assetKey, ByteData assetData) { - _assetMap[assetKey] = assetData; - } - - void setMockAssetStringAsUtf8Data(String assetKey, String stringData) { - final List byteList = utf8.encode(stringData); - final Uint8List byteData = Uint8List(byteList.length); - byteData.setAll(0, byteList); - setMockAssetData(assetKey, ByteData.sublistView(byteData)); - } - - void clearMocks() { - _assetMap.clear(); - } - - final Map _assetMap = {}; -} - -FakeAssetManager fakeAssetManager = FakeAssetManager(); - -void setUpStandardMocks(FakeAssetManager assetManager) { - const String ahemFontFamily = 'Ahem'; - const String ahemFontUrl = '/assets/fonts/ahem.ttf'; - const String robotoFontFamily = 'Roboto'; - const String robotoTestFontUrl = '/assets/fonts/Roboto-Regular.ttf'; - - assetManager.setMockAssetStringAsUtf8Data('AssetManifest.json', '{}'); - assetManager.setMockAssetStringAsUtf8Data('FontManifest.json', - ''' - [ - { - "family":"$robotoFontFamily", - "fonts":[{"asset":"$robotoTestFontUrl"}] - }, - { - "family":"$ahemFontFamily", - "fonts":[{"asset":"$ahemFontUrl"}] - } - ]'''); -} diff --git a/lib/web_ui/test/engine/clipboard_test.dart b/lib/web_ui/test/engine/clipboard_test.dart index 6f4b62785c163..48578bf246b5b 100644 --- a/lib/web_ui/test/engine/clipboard_test.dart +++ b/lib/web_ui/test/engine/clipboard_test.dart @@ -9,8 +9,6 @@ import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; -import '../common/test_embedding.dart'; - void main() { internalBootstrapBrowserTest(() => testMain); } diff --git a/lib/web_ui/test/engine/history_test.dart b/lib/web_ui/test/engine/history_test.dart index 5263b20f39e74..203ab8b5922cf 100644 --- a/lib/web_ui/test/engine/history_test.dart +++ b/lib/web_ui/test/engine/history_test.dart @@ -15,9 +15,9 @@ import 'package:ui/src/engine.dart' show DomEventListener, window; import 'package:ui/src/engine/browser_detection.dart'; import 'package:ui/src/engine/navigation.dart'; import 'package:ui/src/engine/services.dart'; +import 'package:ui/src/engine/test_embedding.dart'; import '../common/spy.dart'; -import '../common/test_embedding.dart'; Map _wrapOriginState(dynamic state) { return {'origin': true, 'state': state}; diff --git a/lib/web_ui/test/engine/image/html_image_codec_test.dart b/lib/web_ui/test/engine/image/html_image_codec_test.dart index 7d009e99f6915..9017fde35d081 100644 --- a/lib/web_ui/test/engine/image/html_image_codec_test.dart +++ b/lib/web_ui/test/engine/image/html_image_codec_test.dart @@ -8,10 +8,9 @@ import 'dart:typed_data'; import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/src/engine/html_image_codec.dart'; +import 'package:ui/src/engine/test_embedding.dart'; import 'package:ui/ui.dart' as ui; -import '../../common/test_embedding.dart'; - void main() { internalBootstrapBrowserTest(() => testMain); } diff --git a/lib/web_ui/test/engine/navigation_test.dart b/lib/web_ui/test/engine/navigation_test.dart index 52aebf6a8c077..27ec64e09dd0a 100644 --- a/lib/web_ui/test/engine/navigation_test.dart +++ b/lib/web_ui/test/engine/navigation_test.dart @@ -9,8 +9,6 @@ import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/src/engine.dart' as engine; -import '../common/test_embedding.dart'; - const engine.MethodCodec codec = engine.JSONMethodCodec(); void emptyCallback(ByteData date) {} @@ -20,10 +18,10 @@ void main() { } void testMain() { - TestUrlStrategy? strategy; + engine.TestUrlStrategy? strategy; setUp(() async { - strategy = TestUrlStrategy(); + strategy = engine.TestUrlStrategy(); await engine.window.debugInitializeHistory(strategy, useSingle: true); }); diff --git a/lib/web_ui/test/engine/recording_canvas_test.dart b/lib/web_ui/test/engine/recording_canvas_test.dart index 40dabbbc6fdfb..72c63f4143fa6 100644 --- a/lib/web_ui/test/engine/recording_canvas_test.dart +++ b/lib/web_ui/test/engine/recording_canvas_test.dart @@ -8,7 +8,6 @@ import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart'; import '../common/mock_engine_canvas.dart'; -import '../common/test_embedding.dart'; import '../html/screenshot.dart'; void main() { @@ -16,7 +15,7 @@ void main() { } void testMain() { - setUpTestEnvironment(); + debugEmulateFlutterTesterEnvironment = true; setUpStableTestFonts(); late RecordingCanvas underTest; diff --git a/lib/web_ui/test/engine/routing_test.dart b/lib/web_ui/test/engine/routing_test.dart index 503b2b73f05e8..aa1d572102079 100644 --- a/lib/web_ui/test/engine/routing_test.dart +++ b/lib/web_ui/test/engine/routing_test.dart @@ -11,7 +11,6 @@ import 'package:ui/src/engine.dart' hide window; import 'package:ui/ui.dart' as ui; import '../common/matchers.dart'; -import '../common/test_embedding.dart'; import 'history_test.dart'; const MethodCodec codec = JSONMethodCodec(); diff --git a/lib/web_ui/test/html/canvas_clip_path_golden_test.dart b/lib/web_ui/test/html/canvas_clip_path_golden_test.dart index 425e5936da255..7242600b361e6 100644 --- a/lib/web_ui/test/html/canvas_clip_path_golden_test.dart +++ b/lib/web_ui/test/html/canvas_clip_path_golden_test.dart @@ -9,7 +9,6 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart' as engine; import 'package:ui/ui.dart' hide TextStyle; -import '../common/test_embedding.dart'; import 'screenshot.dart'; void main() { @@ -18,7 +17,7 @@ void main() { Future testMain() async { setUpAll(() async { - setUpTestEnvironment(); + debugEmulateFlutterTesterEnvironment = true; await webOnlyInitializePlatform(); await engine.renderer.fontCollection.debugDownloadTestFonts(); engine.renderer.fontCollection.registerDownloadedFonts(); diff --git a/lib/web_ui/test/html/canvas_context_golden_test.dart b/lib/web_ui/test/html/canvas_context_golden_test.dart index 4a08c42617356..53a9d30a2e201 100644 --- a/lib/web_ui/test/html/canvas_context_golden_test.dart +++ b/lib/web_ui/test/html/canvas_context_golden_test.dart @@ -7,7 +7,6 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart' as engine; import 'package:ui/ui.dart' hide TextStyle; -import '../common/test_embedding.dart'; import 'screenshot.dart'; void main() { @@ -21,7 +20,7 @@ Future testMain() async { const Rect screenRect = Rect.fromLTWH(0, 0, screenWidth, screenHeight); setUpAll(() async { - setUpTestEnvironment(); + debugEmulateFlutterTesterEnvironment = true; await webOnlyInitializePlatform(); await engine.renderer.fontCollection.debugDownloadTestFonts(); engine.renderer.fontCollection.registerDownloadedFonts(); diff --git a/lib/web_ui/test/html/canvas_reuse_golden_test.dart b/lib/web_ui/test/html/canvas_reuse_golden_test.dart index ff37b765e9c15..0757f0851e879 100644 --- a/lib/web_ui/test/html/canvas_reuse_golden_test.dart +++ b/lib/web_ui/test/html/canvas_reuse_golden_test.dart @@ -9,8 +9,6 @@ import 'package:ui/ui.dart' hide TextStyle; import 'package:web_engine_tester/golden_tester.dart'; -import '../common/test_embedding.dart'; - void main() { internalBootstrapBrowserTest(() => testMain); } @@ -25,7 +23,7 @@ Future testMain() async { ..color = const Color(0xFFFF00FF); setUp(() async { - setUpTestEnvironment(); + debugEmulateFlutterTesterEnvironment = true; await webOnlyInitializePlatform(); await renderer.fontCollection.debugDownloadTestFonts(); renderer.fontCollection.registerDownloadedFonts(); diff --git a/lib/web_ui/test/html/compositing/canvas_blend_golden_test.dart b/lib/web_ui/test/html/compositing/canvas_blend_golden_test.dart index 6a10cad7c31d4..b1851aa4e51b6 100644 --- a/lib/web_ui/test/html/compositing/canvas_blend_golden_test.dart +++ b/lib/web_ui/test/html/compositing/canvas_blend_golden_test.dart @@ -9,7 +9,6 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' hide TextStyle; -import '../../common/test_embedding.dart'; import '../screenshot.dart'; void main() { @@ -19,7 +18,7 @@ void main() { Future testMain() async { setUpAll(() async { - setUpTestEnvironment(); + debugEmulateFlutterTesterEnvironment = true; await webOnlyInitializePlatform(); await renderer.fontCollection.debugDownloadTestFonts(); renderer.fontCollection.registerDownloadedFonts(); diff --git a/lib/web_ui/test/html/compositing/canvas_image_blend_mode_golden_test.dart b/lib/web_ui/test/html/compositing/canvas_image_blend_mode_golden_test.dart index c7779c769d3ab..3b985102d4f4c 100644 --- a/lib/web_ui/test/html/compositing/canvas_image_blend_mode_golden_test.dart +++ b/lib/web_ui/test/html/compositing/canvas_image_blend_mode_golden_test.dart @@ -7,7 +7,6 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' hide TextStyle; -import '../../common/test_embedding.dart'; import '../screenshot.dart'; import '../testimage.dart'; @@ -19,7 +18,7 @@ SurfacePaint makePaint() => Paint() as SurfacePaint; Future testMain() async { setUpAll(() async { - setUpTestEnvironment(); + debugEmulateFlutterTesterEnvironment = true; await webOnlyInitializePlatform(); await renderer.fontCollection.debugDownloadTestFonts(); renderer.fontCollection.registerDownloadedFonts(); diff --git a/lib/web_ui/test/html/compositing/canvas_mask_filter_golden_test.dart b/lib/web_ui/test/html/compositing/canvas_mask_filter_golden_test.dart index a088e27c3a38e..03e8b8d2ccf5b 100644 --- a/lib/web_ui/test/html/compositing/canvas_mask_filter_golden_test.dart +++ b/lib/web_ui/test/html/compositing/canvas_mask_filter_golden_test.dart @@ -10,7 +10,6 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; -import '../../common/test_embedding.dart'; import '../screenshot.dart'; void main() { @@ -19,7 +18,7 @@ void main() { Future testMain() async { setUpAll(() async { - setUpTestEnvironment(); + ui.debugEmulateFlutterTesterEnvironment = true; await ui.webOnlyInitializePlatform(); await renderer.fontCollection.debugDownloadTestFonts(); renderer.fontCollection.registerDownloadedFonts(); diff --git a/lib/web_ui/test/html/compositing/dom_mask_filter_golden_test.dart b/lib/web_ui/test/html/compositing/dom_mask_filter_golden_test.dart index d381988e1c77f..bf7e63d20fb0e 100644 --- a/lib/web_ui/test/html/compositing/dom_mask_filter_golden_test.dart +++ b/lib/web_ui/test/html/compositing/dom_mask_filter_golden_test.dart @@ -6,7 +6,6 @@ import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' hide TextStyle; -import '../../common/test_embedding.dart'; import '../screenshot.dart'; void main() { @@ -15,7 +14,7 @@ void main() { Future testMain() async { setUp(() async { - setUpTestEnvironment(); + debugEmulateFlutterTesterEnvironment = true; await webOnlyInitializePlatform(); await renderer.fontCollection.debugDownloadTestFonts(); renderer.fontCollection.registerDownloadedFonts(); diff --git a/lib/web_ui/test/html/drawing/canvas_draw_image_golden_test.dart b/lib/web_ui/test/html/drawing/canvas_draw_image_golden_test.dart index b60e23ba6bbc5..ad86f7ad77b9e 100644 --- a/lib/web_ui/test/html/drawing/canvas_draw_image_golden_test.dart +++ b/lib/web_ui/test/html/drawing/canvas_draw_image_golden_test.dart @@ -14,7 +14,6 @@ import 'package:ui/ui.dart'; import 'package:web_engine_tester/golden_tester.dart'; -import '../../common/test_embedding.dart'; import '../screenshot.dart'; void main() { @@ -24,7 +23,7 @@ void main() { Future testMain() async { setUp(() async { - setUpTestEnvironment(); + debugEmulateFlutterTesterEnvironment = true; }); setUpStableTestFonts(); diff --git a/lib/web_ui/test/html/drawing/draw_vertices_golden_test.dart b/lib/web_ui/test/html/drawing/draw_vertices_golden_test.dart index 54ae158e201a9..4790ff9bd4e43 100644 --- a/lib/web_ui/test/html/drawing/draw_vertices_golden_test.dart +++ b/lib/web_ui/test/html/drawing/draw_vertices_golden_test.dart @@ -11,7 +11,6 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' hide ImageShader, TextStyle; -import '../../common/test_embedding.dart'; import '../screenshot.dart'; void main() { @@ -24,7 +23,7 @@ Future testMain() async { const Rect screenRect = Rect.fromLTWH(0, 0, screenWidth, screenHeight); setUpAll(() async { - setUpTestEnvironment(); + debugEmulateFlutterTesterEnvironment = true; await webOnlyInitializePlatform(); await renderer.fontCollection.debugDownloadTestFonts(); renderer.fontCollection.registerDownloadedFonts(); diff --git a/lib/web_ui/test/html/path_metrics_golden_test.dart b/lib/web_ui/test/html/path_metrics_golden_test.dart index a0861028b496b..4a3ea96f7288d 100644 --- a/lib/web_ui/test/html/path_metrics_golden_test.dart +++ b/lib/web_ui/test/html/path_metrics_golden_test.dart @@ -8,7 +8,6 @@ import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' hide TextStyle; import '../common/matchers.dart'; -import '../common/test_embedding.dart'; import 'screenshot.dart'; void main() { @@ -24,7 +23,7 @@ Future testMain() async { const double kDashLength = 5.0; setUpAll(() async { - setUpTestEnvironment(); + debugEmulateFlutterTesterEnvironment = true; await webOnlyInitializePlatform(); await renderer.fontCollection.debugDownloadTestFonts(); renderer.fontCollection.registerDownloadedFonts(); diff --git a/lib/web_ui/test/html/path_transform_golden_test.dart b/lib/web_ui/test/html/path_transform_golden_test.dart index 0472b7fe83c02..cb5b398169540 100644 --- a/lib/web_ui/test/html/path_transform_golden_test.dart +++ b/lib/web_ui/test/html/path_transform_golden_test.dart @@ -9,7 +9,6 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' hide TextStyle; -import '../common/test_embedding.dart'; import 'screenshot.dart'; void main() { @@ -22,7 +21,7 @@ Future testMain() async { const Rect screenRect = Rect.fromLTWH(0, 0, screenWidth, screenHeight); setUpAll(() async { - setUpTestEnvironment(); + debugEmulateFlutterTesterEnvironment = true; await webOnlyInitializePlatform(); await renderer.fontCollection.debugDownloadTestFonts(); renderer.fontCollection.registerDownloadedFonts(); diff --git a/lib/web_ui/test/html/recording_canvas_golden_test.dart b/lib/web_ui/test/html/recording_canvas_golden_test.dart index 4144e6785c6f6..3a32e02830ed7 100644 --- a/lib/web_ui/test/html/recording_canvas_golden_test.dart +++ b/lib/web_ui/test/html/recording_canvas_golden_test.dart @@ -12,7 +12,6 @@ import 'package:ui/ui.dart' hide TextStyle; import 'package:web_engine_tester/golden_tester.dart'; import '../common/matchers.dart'; -import '../common/test_embedding.dart'; import 'screenshot.dart'; void main() { @@ -21,7 +20,7 @@ void main() { Future testMain() async { setUpAll(() async { - setUpTestEnvironment(); + debugEmulateFlutterTesterEnvironment = true; }); setUpStableTestFonts(); diff --git a/lib/web_ui/test/html/shaders/gradient_golden_test.dart b/lib/web_ui/test/html/shaders/gradient_golden_test.dart index ba0b5de869741..5aebc78ef0070 100644 --- a/lib/web_ui/test/html/shaders/gradient_golden_test.dart +++ b/lib/web_ui/test/html/shaders/gradient_golden_test.dart @@ -10,7 +10,6 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart'; -import '../../common/test_embedding.dart'; import '../screenshot.dart'; // TODO(yjbanov): unskip Firefox tests when Firefox implements WebGL in headless mode. @@ -27,7 +26,7 @@ Future testMain() async { const Rect region = Rect.fromLTWH(0, 0, 500, 240); setUp(() async { - setUpTestEnvironment(); + debugEmulateFlutterTesterEnvironment = true; }); setUpStableTestFonts(); diff --git a/lib/web_ui/test/html/shaders/image_shader_golden_test.dart b/lib/web_ui/test/html/shaders/image_shader_golden_test.dart index 3e0d56eefe43d..405250062d462 100644 --- a/lib/web_ui/test/html/shaders/image_shader_golden_test.dart +++ b/lib/web_ui/test/html/shaders/image_shader_golden_test.dart @@ -9,7 +9,6 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' hide TextStyle; -import '../../common/test_embedding.dart'; import '../screenshot.dart'; // TODO(yjbanov): unskip Firefox tests when Firefox implements WebGL in headless mode. @@ -26,7 +25,7 @@ Future testMain() async { final HtmlImage testImage = createTestImage(); setUpAll(() async { - setUpTestEnvironment(); + debugEmulateFlutterTesterEnvironment = true; await webOnlyInitializePlatform(); await renderer.fontCollection.debugDownloadTestFonts(); renderer.fontCollection.registerDownloadedFonts(); diff --git a/lib/web_ui/test/html/shaders/linear_gradient_golden_test.dart b/lib/web_ui/test/html/shaders/linear_gradient_golden_test.dart index b886aa0e934cf..742067e4914e0 100644 --- a/lib/web_ui/test/html/shaders/linear_gradient_golden_test.dart +++ b/lib/web_ui/test/html/shaders/linear_gradient_golden_test.dart @@ -8,7 +8,6 @@ import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' hide TextStyle; -import '../../common/test_embedding.dart'; import '../screenshot.dart'; // TODO(yjbanov): unskip Firefox tests when Firefox implements WebGL in headless mode. @@ -20,7 +19,7 @@ void main() { Future testMain() async { setUpAll(() async { - setUpTestEnvironment(); + debugEmulateFlutterTesterEnvironment = true; await webOnlyInitializePlatform(); await renderer.fontCollection.debugDownloadTestFonts(); renderer.fontCollection.registerDownloadedFonts(); diff --git a/lib/web_ui/test/html/shaders/radial_gradient_golden_test.dart b/lib/web_ui/test/html/shaders/radial_gradient_golden_test.dart index 6e6ef40c5d830..51bfab70965a1 100644 --- a/lib/web_ui/test/html/shaders/radial_gradient_golden_test.dart +++ b/lib/web_ui/test/html/shaders/radial_gradient_golden_test.dart @@ -6,7 +6,6 @@ import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' hide TextStyle; -import '../../common/test_embedding.dart'; import '../screenshot.dart'; void main() { @@ -16,7 +15,7 @@ void main() { Future testMain() async { setUpAll(() async { - setUpTestEnvironment(); + debugEmulateFlutterTesterEnvironment = true; await webOnlyInitializePlatform(); await renderer.fontCollection.debugDownloadTestFonts(); renderer.fontCollection.registerDownloadedFonts(); diff --git a/lib/web_ui/test/html/text/canvas_paragraph_builder_test.dart b/lib/web_ui/test/html/text/canvas_paragraph_builder_test.dart index b5910cc7de31d..c51e4e4897e3f 100644 --- a/lib/web_ui/test/html/text/canvas_paragraph_builder_test.dart +++ b/lib/web_ui/test/html/text/canvas_paragraph_builder_test.dart @@ -7,7 +7,6 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart'; -import '../../common/test_embedding.dart'; import '../paragraph/helper.dart'; /// Some text measurements are sensitive to browser implementations. Position diff --git a/lib/web_ui/test/html/text/canvas_paragraph_test.dart b/lib/web_ui/test/html/text/canvas_paragraph_test.dart index a887ccbe68c4a..48dcfa89b9e68 100644 --- a/lib/web_ui/test/html/text/canvas_paragraph_test.dart +++ b/lib/web_ui/test/html/text/canvas_paragraph_test.dart @@ -7,7 +7,6 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; -import '../../common/test_embedding.dart'; import '../paragraph/helper.dart'; void main() { diff --git a/lib/web_ui/test/html/text/font_loading_test.dart b/lib/web_ui/test/html/text/font_loading_test.dart index 64b2e34f0db2b..d96ca6acb22f0 100644 --- a/lib/web_ui/test/html/text/font_loading_test.dart +++ b/lib/web_ui/test/html/text/font_loading_test.dart @@ -11,8 +11,6 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; -import '../../common/test_embedding.dart'; - void main() { internalBootstrapBrowserTest(() => testMain); } diff --git a/lib/web_ui/test/html/text/layout_service_plain_test.dart b/lib/web_ui/test/html/text/layout_service_plain_test.dart index 348a61639233e..ca9257864c376 100644 --- a/lib/web_ui/test/html/text/layout_service_plain_test.dart +++ b/lib/web_ui/test/html/text/layout_service_plain_test.dart @@ -7,7 +7,6 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; -import '../../common/test_embedding.dart'; import '../paragraph/helper.dart'; import 'layout_service_helper.dart'; diff --git a/lib/web_ui/test/html/text/layout_service_rich_test.dart b/lib/web_ui/test/html/text/layout_service_rich_test.dart index 8fbdee7602b2e..d7c53da10833b 100644 --- a/lib/web_ui/test/html/text/layout_service_rich_test.dart +++ b/lib/web_ui/test/html/text/layout_service_rich_test.dart @@ -8,7 +8,6 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; -import '../../common/test_embedding.dart'; import '../paragraph/helper.dart'; import 'layout_service_helper.dart'; diff --git a/lib/web_ui/test/html/text_test.dart b/lib/web_ui/test/html/text_test.dart index a04338c74c66e..2b7e629fb2917 100644 --- a/lib/web_ui/test/html/text_test.dart +++ b/lib/web_ui/test/html/text_test.dart @@ -12,7 +12,6 @@ import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart'; import '../common/matchers.dart'; -import '../common/test_embedding.dart'; import 'paragraph/helper.dart'; void main() { diff --git a/lib/web_ui/test/ui/fragment_shader_test.dart b/lib/web_ui/test/ui/fragment_shader_test.dart index 4b2cdfd283863..1fef73e8e0f55 100644 --- a/lib/web_ui/test/ui/fragment_shader_test.dart +++ b/lib/web_ui/test/ui/fragment_shader_test.dart @@ -2,13 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:convert'; +import 'dart:typed_data'; + import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; import 'package:web_engine_tester/golden_tester.dart'; -import '../common/fake_asset_manager.dart'; import 'utils.dart'; void main() { @@ -43,9 +45,9 @@ Future testMain() async { const ui.Rect region = ui.Rect.fromLTWH(0, 0, 300, 300); test('fragment shader', () async { - fakeAssetManager.setMockAssetStringAsUtf8Data( + fakeAssetManager.setAsset( 'voronoi_shader', - kVoronoiShaderSksl + Uint8List.fromList(utf8.encode(kVoronoiShaderSksl)).buffer.asByteData() ); final ui.FragmentProgram program = await renderer.createFragmentProgram('voronoi_shader'); final ui.FragmentShader shader = program.fragmentShader(); diff --git a/lib/web_ui/test/ui/utils.dart b/lib/web_ui/test/ui/utils.dart index 933768d69b7e6..01b42125383bb 100644 --- a/lib/web_ui/test/ui/utils.dart +++ b/lib/web_ui/test/ui/utils.dart @@ -4,20 +4,50 @@ import 'dart:async'; import 'dart:js_interop'; +import 'dart:typed_data'; import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/src/engine/skwasm/skwasm_stub.dart' if (dart.library.ffi) 'package:ui/src/engine/skwasm/skwasm_impl.dart'; import 'package:ui/ui.dart'; -import '../common/fake_asset_manager.dart'; -import '../common/test_embedding.dart'; +class FakeAssetManager implements AssetManager { + FakeAssetManager(this._parent); + + @override + String get assetsDir => 'assets'; + + @override + String getAssetUrl(String asset) => asset; + + @override + Future load(String assetKey) async { + final ByteData? data = _assetMap[assetKey]; + if (data == null) { + return _parent.load(assetKey); + } + return data; + } + + @override + Future loadAsset(String asset) { + return _parent.loadAsset(asset); + } + + void setAsset(String assetKey, ByteData assetData) { + _assetMap[assetKey] = assetData; + } + + final Map _assetMap = {}; + final AssetManager _parent; +} + +FakeAssetManager fakeAssetManager = FakeAssetManager(WebOnlyMockAssetManager()); /// Initializes the renderer for this test. void setUpUiTest() { setUpAll(() async { - setUpTestEnvironment(); - setUpStandardMocks(fakeAssetManager); + debugEmulateFlutterTesterEnvironment = true; await initializeEngine(assetManager: fakeAssetManager); await renderer.fontCollection.debugDownloadTestFonts(); renderer.fontCollection.registerDownloadedFonts(); From e2f2968de1472cc6fdc3bdfe7a00934856296bda Mon Sep 17 00:00:00 2001 From: Jackson Gardner Date: Tue, 18 Apr 2023 17:27:55 -0700 Subject: [PATCH 13/30] Update licenses golden. --- ci/licenses_golden/licenses_flutter | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 87dd087e6a77a..02ef4a59a3343 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -2023,6 +2023,7 @@ ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/vertices.d ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_stub.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_stub/renderer.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/svg.dart + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/test_embedding.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/text/canvas_paragraph.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/text/font_collection.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/text/fragmenter.dart + ../../../flutter/LICENSE @@ -4624,6 +4625,7 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/vertices.dar FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_stub.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_stub/renderer.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/svg.dart +FILE: ../../../flutter/lib/web_ui/lib/src/engine/test_embedding.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/text/canvas_paragraph.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/text/font_collection.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/text/fragmenter.dart From 1689301265865c823b892d65a5fd920a0271dcd4 Mon Sep 17 00:00:00 2001 From: Jackson Gardner Date: Thu, 20 Apr 2023 17:36:24 -0700 Subject: [PATCH 14/30] Partway through font loading refactor. --- lib/web_ui/lib/src/engine/assets.dart | 76 --------- .../src/engine/canvaskit/font_fallbacks.dart | 2 +- .../lib/src/engine/canvaskit/fonts.dart | 146 ++++++++--------- .../lib/src/engine/canvaskit/renderer.dart | 20 ++- lib/web_ui/lib/src/engine/fonts.dart | 67 +++++--- lib/web_ui/lib/src/engine/initialization.dart | 24 +-- .../skwasm/skwasm_impl/font_collection.dart | 56 ++++--- .../skwasm/skwasm_impl/raw/raw_fonts.dart | 4 +- lib/web_ui/lib/src/engine/test_embedding.dart | 23 --- .../lib/src/engine/text/font_collection.dart | 142 ++++++---------- lib/web_ui/skwasm/fonts.cpp | 6 +- .../test/canvaskit/canvaskit_api_test.dart | 5 - lib/web_ui/test/canvaskit/common.dart | 5 +- .../canvaskit/skia_font_collection_test.dart | 72 +++------ .../test/common/fake_asset_manager.dart | 151 ++++++++++++++++++ .../test/common/initialize_view_embedder.dart | 31 ++++ lib/web_ui/test/engine/clipboard_test.dart | 2 + .../engine/image/html_image_codec_test.dart | 3 +- .../test/engine/image_to_byte_data_test.dart | 8 +- .../html/canvas_clip_path_golden_test.dart | 6 +- .../test/html/canvas_context_golden_test.dart | 5 +- .../text/canvas_paragraph_builder_test.dart | 1 + .../test/html/text/canvas_paragraph_test.dart | 1 + .../test/html/text/font_loading_test.dart | 2 + .../html/text/layout_service_plain_test.dart | 1 + .../html/text/layout_service_rich_test.dart | 1 + lib/web_ui/test/html/text_test.dart | 1 + lib/web_ui/test/ui/font_collection_test.dart | 47 ++++++ lib/web_ui/test/ui/utils.dart | 40 +---- 29 files changed, 504 insertions(+), 444 deletions(-) create mode 100644 lib/web_ui/test/common/fake_asset_manager.dart create mode 100644 lib/web_ui/test/common/initialize_view_embedder.dart create mode 100644 lib/web_ui/test/ui/font_collection_test.dart diff --git a/lib/web_ui/lib/src/engine/assets.dart b/lib/web_ui/lib/src/engine/assets.dart index b200f824e4145..51a4acb77d91a 100644 --- a/lib/web_ui/lib/src/engine/assets.dart +++ b/lib/web_ui/lib/src/engine/assets.dart @@ -110,79 +110,3 @@ class AssetManager { return (await response.payload.asByteBuffer()).asByteData(); } } - -/// An asset manager that gives fake empty responses for assets. -class WebOnlyMockAssetManager extends AssetManager { - /// Mock asset directory relative to base url. - String defaultAssetsDir = ''; - - /// Mock empty asset manifest. - String defaultAssetManifest = '{}'; - - /// Mock font manifest overridable for unit testing. - String defaultFontManifest = ''' - [ - { - "family":"$robotoFontFamily", - "fonts":[{"asset":"$robotoTestFontUrl"}] - }, - { - "family":"$ahemFontFamily", - "fonts":[{"asset":"$ahemFontUrl"}] - } - ]'''; - - @override - String get assetsDir => defaultAssetsDir; - - @override - String getAssetUrl(String asset) => asset; - - @override - Future loadAsset(String asset) async { - if (asset == getAssetUrl('AssetManifest.json')) { - return MockHttpFetchResponse( - url: asset, - status: 200, - payload: MockHttpFetchPayload( - byteBuffer: _toByteData(utf8.encode(defaultAssetManifest)).buffer, - ), - ); - } - if (asset == getAssetUrl('FontManifest.json')) { - return MockHttpFetchResponse( - url: asset, - status: 200, - payload: MockHttpFetchPayload( - byteBuffer: _toByteData(utf8.encode(defaultFontManifest)).buffer, - ), - ); - } - - return MockHttpFetchResponse( - url: asset, - status: 404, - ); - } - - @override - Future load(String asset) { - if (asset == getAssetUrl('AssetManifest.json')) { - return Future.value( - _toByteData(utf8.encode(defaultAssetManifest))); - } - if (asset == getAssetUrl('FontManifest.json')) { - return Future.value( - _toByteData(utf8.encode(defaultFontManifest))); - } - throw HttpFetchNoPayloadError(asset, status: 404); - } - - ByteData _toByteData(List bytes) { - final ByteData byteData = ByteData(bytes.length); - for (int i = 0; i < bytes.length; i++) { - byteData.setUint8(i, bytes[i]); - } - return byteData; - } -} diff --git a/lib/web_ui/lib/src/engine/canvaskit/font_fallbacks.dart b/lib/web_ui/lib/src/engine/canvaskit/font_fallbacks.dart index ddf1298e94bf1..708b105e40ff2 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/font_fallbacks.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/font_fallbacks.dart @@ -447,7 +447,7 @@ class FallbackFontDownloadQueue { final Uint8List bytes = downloadedData[url]!; FontFallbackData.instance.registerFallbackFont(font.name, bytes); if (pendingFonts.isEmpty) { - renderer.fontCollection.registerDownloadedFonts(); + (renderer.fontCollection as SkiaFontCollection).registerDownloadedFonts(); sendFontChangeMessage(); } } diff --git a/lib/web_ui/lib/src/engine/canvaskit/fonts.dart b/lib/web_ui/lib/src/engine/canvaskit/fonts.dart index d06e53f069713..5eb8df4757c78 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/fonts.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/fonts.dart @@ -5,14 +5,7 @@ import 'dart:async'; import 'dart:typed_data'; -import 'package:web_test_fonts/web_test_fonts.dart'; - -import '../assets.dart'; -import '../dom.dart'; -import '../fonts.dart'; -import '../util.dart'; -import 'canvaskit_api.dart'; -import 'font_fallbacks.dart'; +import 'package:ui/src/engine.dart'; // This URL was found by using the Google Fonts Developer API to find the URL // for Roboto. The API warns that this URL is not stable. In order to update @@ -76,12 +69,12 @@ class SkiaFontCollection implements FlutterFontCollection { } @override - Future loadFontFromList(Uint8List list, {String? fontFamily}) async { + Future loadFontFromList(Uint8List list, {String? fontFamily}) async { if (fontFamily == null) { fontFamily = _readActualFamilyName(list); if (fontFamily == null) { printWarning('Failed to read font family name. Aborting font load.'); - return; + return false; } } @@ -92,35 +85,65 @@ class SkiaFontCollection implements FlutterFontCollection { _registerWithFontProvider(); } else { printWarning('Failed to parse font family "$fontFamily"'); - return; + return false; } + return true; } /// Loads fonts from `FontManifest.json`. @override - Future downloadAssetFonts(AssetManager assetManager) async { - final FontManifest manifest = await fetchFontManifest(assetManager); - final List> pendingFonts = >[]; - + Future loadAssetFonts(FontManifest manifest) async { + final List> pendingDownloads = >[]; + bool loadedRoboto = false; for (final FontFamily family in manifest.families) { + if (family.name == 'Roboto') { + loadedRoboto = true; + } for (final FontAsset fontAsset in family.fontAssets) { - _downloadFont(pendingFonts, assetManager.getAssetUrl(fontAsset.asset), family.name); + final String url = assetManager.getAssetUrl(fontAsset.asset); + pendingDownloads.add(_downloadFont(fontAsset.asset, url, family.name)); } } /// We need a default fallback font for CanvasKit, in order to /// avoid crashing while laying out text with an unregistered font. We chose /// Roboto to match Android. - if (!_isFontFamilyDownloaded('Roboto')) { + if (!loadedRoboto) { // Download Roboto and add it to the font buffers. - _downloadFont(pendingFonts, _robotoUrl, 'Roboto'); + pendingDownloads.add(_downloadFont('RobotoFallback', _robotoUrl, 'Roboto')); + } + + final Map fontFailures = {}; + final List<(String, UnregisteredFont)> downloadedFonts = <(String, UnregisteredFont)>[]; + for (final FontDownloadResult result in await Future.wait(pendingDownloads)) { + if (result.font != null) { + downloadedFonts.add((result.assetName, result.font!)); + } else { + fontFailures[result.assetName] = result.error!; + } } - final List completedPendingFonts = await Future.wait(pendingFonts); - _unregisteredFonts.addAll(completedPendingFonts.whereType()); + // Make sure CanvasKit is actually loaded + await renderer.initialize(); + + final List loadedFonts = []; + for (final (String assetName, UnregisteredFont unregisteredFont) in downloadedFonts) { + final Uint8List bytes = unregisteredFont.bytes.asUint8List(); + final SkTypeface? typeface = + canvasKit.Typeface.MakeFreeTypeFaceFromData(bytes.buffer); + if (typeface != null) { + loadedFonts.add(assetName); + _registeredFonts.add(RegisteredFont(bytes, unregisteredFont.family, typeface)); + } else { + printWarning('Failed to load font ${unregisteredFont.family} at ${unregisteredFont.url}'); + printWarning('Verify that ${unregisteredFont.url} contains a valid font.'); + fontFailures[assetName] = FontInvalidDataError(unregisteredFont.url); + } + } + registerDownloadedFonts(); + return AssetFontsResult(loadedFonts, fontFailures); } - @override void registerDownloadedFonts() { RegisteredFont? makeRegisterFont(ByteBuffer buffer, String url, String family) { final Uint8List bytes = buffer.asUint8List(); @@ -150,61 +173,29 @@ class SkiaFontCollection implements FlutterFontCollection { _registerWithFontProvider(); } - /// Whether the [fontFamily] was registered and/or loaded. - bool _isFontFamilyDownloaded(String fontFamily) { - return _downloadedFontFamilies.contains(fontFamily); - } - - /// Loads the Ahem font, unless it's already been loaded using - /// `FontManifest.json` (see [downloadAssetFonts]). - /// - /// `FontManifest.json` has higher priority than the default test font URLs. - /// This allows customizing test environments where fonts are loaded from - /// different URLs. - @override - Future debugDownloadTestFonts() async { - final List> pendingFonts = >[]; - for (final MapEntry fontEntry in testFontUrls.entries) { - if (!_isFontFamilyDownloaded(fontEntry.key)) { - _downloadFont(pendingFonts, fontEntry.value, fontEntry.key); - } - } - final List completedPendingFonts = await Future.wait(pendingFonts); - final List fonts = [ - UnregisteredFont( - EmbeddedTestFont.flutterTest.data.buffer, - '', - EmbeddedTestFont.flutterTest.fontFamily, - ), - ...completedPendingFonts.whereType(), - ]; - _unregisteredFonts.addAll(fonts); - - // Ahem must be added to font fallbacks list regardless of where it was - // downloaded from. - FontFallbackData.instance.globalFontFallbacks.add(ahemFontFamily); - } - - void _downloadFont( - List> waitUnregisteredFonts, + Future _downloadFont( + String assetName, String url, - String family - ) { - Future downloadFont() async { - // Try to get the font leniently. Do not crash the app when failing to - // fetch the font in the spirit of "gradual degradation of functionality". - try { - final ByteBuffer data = await httpFetchByteBuffer(url); - return UnregisteredFont(data, url, family); - } catch (e) { - printWarning('Failed to load font $family at $url'); - printWarning(e.toString()); - return null; + String fontFamily + ) async { + final ByteBuffer fontData; + + // Try to get the font leniently. Do not crash the app when failing to + // fetch the font in the spirit of "gradual degradation of functionality". + try { + final HttpFetchResponse response = await httpFetch(url); + if (!response.hasPayload) { + return FontDownloadResult.fromError(assetName, FontNotFoundError(url)); } - } - _downloadedFontFamilies.add(family); - waitUnregisteredFonts.add(downloadFont()); + fontData = await response.asByteBuffer(); + } catch (e) { + printWarning('Failed to load font $fontFamily at $url'); + printWarning(e.toString()); + return FontDownloadResult.fromError(assetName, FontDownloadError(url, e)); + } + _downloadedFontFamilies.add(fontFamily); + return FontDownloadResult.fromFont(assetName, UnregisteredFont(fontData, url, fontFamily)); } @@ -250,3 +241,12 @@ class UnregisteredFont { final String url; final String family; } + +class FontDownloadResult { + FontDownloadResult.fromFont(this.assetName, UnregisteredFont this.font) : error = null; + FontDownloadResult.fromError(this.assetName, FontLoadError this.error) : font = null; + + final String assetName; + final UnregisteredFont? font; + final FontLoadError? error; +} diff --git a/lib/web_ui/lib/src/engine/canvaskit/renderer.dart b/lib/web_ui/lib/src/engine/canvaskit/renderer.dart index 06db1bc9a2a61..cec642f014188 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/renderer.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/renderer.dart @@ -48,6 +48,8 @@ class CanvasKitRenderer implements Renderer { static CanvasKitRenderer get instance => _instance; static late CanvasKitRenderer _instance; + Future? _initialized; + @override String get rendererTag => 'canvaskit'; @@ -66,14 +68,16 @@ class CanvasKitRenderer implements Renderer { @override Future initialize() async { - if (windowFlutterCanvasKit != null) { - canvasKit = windowFlutterCanvasKit!; - } else { - canvasKit = await downloadCanvasKit(); - windowFlutterCanvasKit = canvasKit; - } - - _instance = this; + _initialized ??= () async { + if (windowFlutterCanvasKit != null) { + canvasKit = windowFlutterCanvasKit!; + } else { + canvasKit = await downloadCanvasKit(); + windowFlutterCanvasKit = canvasKit; + } + _instance = this; + }(); + return _initialized; } @override diff --git a/lib/web_ui/lib/src/engine/fonts.dart b/lib/web_ui/lib/src/engine/fonts.dart index 9e7fe956c40f1..933685e52f793 100644 --- a/lib/web_ui/lib/src/engine/fonts.dart +++ b/lib/web_ui/lib/src/engine/fonts.dart @@ -76,28 +76,53 @@ Future fetchFontManifest(AssetManager assetManager) async { return FontManifest(families); } +abstract class FontLoadError extends Error { + FontLoadError(this.url); + + String url; + String get message; +} + +class FontNotFoundError extends FontLoadError { + FontNotFoundError(super.url); + + @override + String get message => 'Font asset not found at url $url.'; +} + +class FontDownloadError extends FontLoadError { + FontDownloadError(super.url, this.error); + + dynamic error; + + @override + String get message => 'Failed to download font asset at url $url with error: $error.'; +} + +class FontInvalidDataError extends FontLoadError { + FontInvalidDataError(super.url); + + @override + String get message => 'Invalid data for font asset at url $url.'; +} + +class AssetFontsResult { + AssetFontsResult(this.loadedFonts, this.fontFailures); + + /// A list of asset keys for fonts that were successfully loaded. + final List loadedFonts; + + /// A map of the asset keys to failures for fonts that failed to load. + final Map fontFailures; +} + abstract class FlutterFontCollection { + /// Loads a font directly from font data. + Future loadFontFromList(Uint8List list, {String? fontFamily}); + + /// Completes when fonts from FontManifest.json have been loaded. + Future loadAssetFonts(FontManifest manifest); - /// Fonts loaded with [loadFontFromList] do not need to be registered - /// with [registerDownloadedFonts]. Fonts are both downloaded and registered - /// with [loadFontFromList] calls. - Future loadFontFromList(Uint8List list, {String? fontFamily}); - - /// Completes when fonts from FontManifest.json have been downloaded. - Future downloadAssetFonts(AssetManager assetManager); - - /// Registers both downloaded fonts and fallback fonts with the TypefaceFontProvider. - /// - /// Downloading of fonts happens separately from registering of fonts so that - /// the download step can happen concurrently with the initalization of the renderer. - /// - /// The correct order of calls to register downloaded fonts: - /// 1) [downloadAssetFonts] - /// 2) [registerDownloadedFonts] - /// - /// For fallbackFonts, call registerFallbackFont (see font_fallbacks.dart) - /// for each fallback font before calling [registerDownloadedFonts] - void registerDownloadedFonts(); - FutureOr debugDownloadTestFonts(); + // Unregisters all fonts. void clear(); } diff --git a/lib/web_ui/lib/src/engine/initialization.dart b/lib/web_ui/lib/src/engine/initialization.dart index 7db4df0821b93..5e292a7d38480 100644 --- a/lib/web_ui/lib/src/engine/initialization.dart +++ b/lib/web_ui/lib/src/engine/initialization.dart @@ -6,24 +6,9 @@ import 'dart:async'; import 'dart:developer' as developer; import 'dart:js_interop'; -import 'package:ui/src/engine/assets.dart'; -import 'package:ui/src/engine/browser_detection.dart'; -import 'package:ui/src/engine/configuration.dart'; -import 'package:ui/src/engine/embedder.dart'; -import 'package:ui/src/engine/mouse_cursor.dart'; -import 'package:ui/src/engine/navigation.dart'; -import 'package:ui/src/engine/platform_dispatcher.dart'; -import 'package:ui/src/engine/platform_views/content_manager.dart'; -import 'package:ui/src/engine/profiler.dart'; -import 'package:ui/src/engine/raw_keyboard.dart'; -import 'package:ui/src/engine/renderer.dart'; -import 'package:ui/src/engine/safe_browser_api.dart'; -import 'package:ui/src/engine/semantics/accessibility.dart'; -import 'package:ui/src/engine/window.dart'; +import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; -import 'dom.dart'; - /// The mode the app is running in. /// Keep these in sync with the same constants on the framework-side under foundation/constants.dart. const bool kReleaseMode = @@ -216,7 +201,6 @@ Future initializeEngineServices({ Future initializeRendererCallback () async => renderer.initialize(); await Future.wait(>[initializeRendererCallback(), _downloadAssetFonts()]); - renderer.fontCollection.registerDownloadedFonts(); _initializationState = DebugEngineInitializationState.initializedServices; } @@ -264,11 +248,7 @@ Future _downloadAssetFonts() async { renderer.fontCollection.clear(); if (_assetManager != null) { - await renderer.fontCollection.downloadAssetFonts(_assetManager!); - } - - if (ui.debugEmulateFlutterTesterEnvironment) { - await renderer.fontCollection.debugDownloadTestFonts(); + await renderer.fontCollection.loadAssetFonts(await fetchFontManifest(assetManager)); } } diff --git a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/font_collection.dart b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/font_collection.dart index 05e8a82dfeef2..cd121acb37547 100644 --- a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/font_collection.dart +++ b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/font_collection.dart @@ -15,22 +15,19 @@ import 'package:ui/src/engine/skwasm/skwasm_impl.dart'; class SkwasmFontCollection implements FlutterFontCollection { SkwasmFontCollection() : _handle = fontCollectionCreate(); - final FontCollectionHandle _handle; + FontCollectionHandle _handle; @override void clear() { - // TODO(jacksongardner): implement clear + fontCollectionDispose(_handle); + _handle = fontCollectionCreate(); } @override - FutureOr debugDownloadTestFonts() { - // TODO(jacksongardner): implement debugDownloadTestFonts - } - - @override - Future downloadAssetFonts(AssetManager assetManager) async { - final FontManifest manifest = await fetchFontManifest(assetManager); + Future loadAssetFonts(FontManifest manifest) async { final List> fontFutures = >[]; + final List loadedFonts = []; + final Map fontFailures = {}; for (final FontFamily family in manifest.families) { final List rawUtf8Bytes = utf8.encode(family.name); final SkStringHandle stringHandle = skStringAllocate(rawUtf8Bytes.length); @@ -39,18 +36,30 @@ class SkwasmFontCollection implements FlutterFontCollection { stringDataPointer[i] = rawUtf8Bytes[i]; } for (final FontAsset fontAsset in family.fontAssets) { - fontFutures.add(_downloadFontAsset(fontAsset.asset, stringHandle)); + fontFutures.add(() async { + final FontLoadError? error = await _downloadFontAsset(fontAsset, stringHandle); + if (error == null) { + loadedFonts.add(fontAsset.asset); + } else { + fontFailures[fontAsset.asset] = error; + } + }()); } skStringFree(stringHandle); } await Future.wait(fontFutures); + return AssetFontsResult(loadedFonts, fontFailures); } - Future _downloadFontAsset(String assetName, SkStringHandle familyNameHandle) async { - final HttpFetchResponse response = await assetManager.loadAsset(assetName); + Future _downloadFontAsset(FontAsset asset, SkStringHandle familyNameHandle) async { + final HttpFetchResponse response; + try { + response = await assetManager.loadAsset(asset.asset); + } catch (error) { + return FontDownloadError(assetManager.getAssetUrl(asset.asset), error); + } if (!response.hasPayload) { - printWarning('Failed to load font "$assetName", font file not found.'); - return; + return FontNotFoundError(assetManager.getAssetUrl(asset.asset)); } int length = 0; final List chunks = []; @@ -65,17 +74,22 @@ class SkwasmFontCollection implements FlutterFontCollection { wasmMemory.set(chunk, dataAddress.toJS); dataAddress += chunk.length.toDart.toInt(); } - fontCollectionRegisterFont(_handle, fontData, familyNameHandle); + final bool result = fontCollectionRegisterFont(_handle, fontData, familyNameHandle); skDataDispose(fontData); + if (!result) { + return FontInvalidDataError(assetManager.getAssetUrl(asset.asset)); + } + return null; } @override - Future loadFontFromList(Uint8List list, {String? fontFamily}) async { + Future loadFontFromList(Uint8List list, {String? fontFamily}) async { final SkDataHandle dataHandle = skDataCreate(list.length); final Pointer dataPointer = skDataGetPointer(dataHandle).cast(); for (int i = 0; i < list.length; i++) { dataPointer[i] = list[i]; } + bool success; if (fontFamily != null) { final List rawUtf8Bytes = utf8.encode(fontFamily); final SkStringHandle stringHandle = skStringAllocate(rawUtf8Bytes.length); @@ -83,16 +97,12 @@ class SkwasmFontCollection implements FlutterFontCollection { for (int i = 0; i < rawUtf8Bytes.length; i++) { stringDataPointer[i] = rawUtf8Bytes[i]; } - fontCollectionRegisterFont(_handle, dataHandle, stringHandle); + success = fontCollectionRegisterFont(_handle, dataHandle, stringHandle); skStringFree(stringHandle); } else { - fontCollectionRegisterFont(_handle, dataHandle, nullptr); + success = fontCollectionRegisterFont(_handle, dataHandle, nullptr); } skDataDispose(dataHandle); - } - - @override - void registerDownloadedFonts() { - // TODO(jacksongardner): implement registerDownloadedFonts + return success; } } diff --git a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_fonts.dart b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_fonts.dart index 40b03450a5188..5bbd928d1ce2e 100644 --- a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_fonts.dart +++ b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_fonts.dart @@ -18,12 +18,12 @@ external FontCollectionHandle fontCollectionCreate(); @Native(symbol: 'fontCollection_dispose', isLeaf: true) external void fontCollectionDispose(FontCollectionHandle handle); -@Native(symbol: 'fontCollection_registerFont', isLeaf: true) -external void fontCollectionRegisterFont( +external bool fontCollectionRegisterFont( FontCollectionHandle handle, SkDataHandle fontData, SkStringHandle fontName, diff --git a/lib/web_ui/lib/src/engine/test_embedding.dart b/lib/web_ui/lib/src/engine/test_embedding.dart index 103830680348e..85030b714aab2 100644 --- a/lib/web_ui/lib/src/engine/test_embedding.dart +++ b/lib/web_ui/lib/src/engine/test_embedding.dart @@ -12,29 +12,6 @@ import 'package:ui/ui_web/src/ui_web.dart' as ui_web; import '../engine.dart'; -Future? _platformInitializedFuture; - -Future initializeTestFlutterViewEmbedder({double devicePixelRatio = 3.0}) { - // Force-initialize FlutterViewEmbedder so it doesn't overwrite test pixel ratio. - ensureFlutterViewEmbedderInitialized(); - - // The following parameters are hard-coded in Flutter's test embedder. Since - // we don't have an embedder yet this is the lowest-most layer we can put - // this stuff in. - window.debugOverrideDevicePixelRatio(devicePixelRatio); - window.webOnlyDebugPhysicalSizeOverride = - ui.Size(800 * devicePixelRatio, 600 * devicePixelRatio); - scheduleFrameCallback = () {}; - ui.debugEmulateFlutterTesterEnvironment = true; - - // Initialize platform once and reuse across all tests. - if (_platformInitializedFuture != null) { - return _platformInitializedFuture!; - } - return _platformInitializedFuture = - initializeEngine(assetManager: WebOnlyMockAssetManager()); -} - const bool _debugLogHistoryActions = false; class TestHistoryEntry { diff --git a/lib/web_ui/lib/src/engine/text/font_collection.dart b/lib/web_ui/lib/src/engine/text/font_collection.dart index 8293634660e8c..59cfcd31c2698 100644 --- a/lib/web_ui/lib/src/engine/text/font_collection.dart +++ b/lib/web_ui/lib/src/engine/text/font_collection.dart @@ -6,9 +6,7 @@ import 'dart:async'; import 'dart:typed_data'; import 'package:ui/src/engine/fonts.dart'; -import 'package:web_test_fonts/web_test_fonts.dart'; -import '../assets.dart'; import '../dom.dart'; import '../util.dart'; import 'layout_service.dart'; @@ -20,70 +18,48 @@ import 'layout_service.dart'; /// font manifest. If test fonts are enabled, then call /// [debugDownloadTestFonts] as well. class HtmlFontCollection implements FlutterFontCollection { - FontManager? _assetFontManager; - FontManager? _testFontManager; - /// Reads the font manifest using the [assetManager] and downloads all of the /// fonts declared within. @override - Future downloadAssetFonts(AssetManager assetManager) async { - final FontManifest manifest = await fetchFontManifest(assetManager); - final FontManager assetFontManager = FontManager(); - _assetFontManager = assetFontManager; + Future loadAssetFonts(FontManifest manifest) async { + final List> pendingFonts = >[]; for (final FontFamily family in manifest.families) { for (final FontAsset fontAsset in family.fontAssets) { - assetFontManager.downloadAsset(family.name, fontAsset.asset, fontAsset.descriptors); + pendingFonts.add(() async { + return ( + fontAsset.asset, + await _loadFontAsset(family.name, fontAsset.asset, fontAsset.descriptors) + ); + }()); } } - await assetFontManager.downloadAllFonts(); - } - @override - Future loadFontFromList(Uint8List list, {String? fontFamily}) { - if (fontFamily == null) { - throw AssertionError('Font family must be provided to HtmlFontCollection.'); + final List loadedFonts = []; + final Map fontFailures = {}; + for (final (String asset, FontLoadError? error) in await Future.wait(pendingFonts)) { + if (error == null) { + loadedFonts.add(asset); + } else { + fontFailures[asset] = error; + } } - return _assetFontManager!._loadFontFaceBytes(fontFamily, list); + return AssetFontsResult(loadedFonts, fontFailures); } - /// Downloads fonts that are used by tests. @override - Future debugDownloadTestFonts() async { - final FontManager fontManager = _testFontManager = FontManager(); - fontManager._downloadedFonts.add(createDomFontFace( - EmbeddedTestFont.flutterTest.fontFamily, - EmbeddedTestFont.flutterTest.data, - )); - for (final MapEntry fontEntry in testFontUrls.entries) { - fontManager.downloadAsset(fontEntry.key, 'url(${fontEntry.value})', const {}); + Future loadFontFromList(Uint8List list, {String? fontFamily}) async { + if (fontFamily == null) { + printWarning('Font family must be provided to HtmlFontCollection.'); + return false; } - await fontManager.downloadAllFonts(); - } - - @override - void registerDownloadedFonts() { - _assetFontManager?.registerDownloadedFonts(); - _testFontManager?.registerDownloadedFonts(); + return _loadFontFaceBytes(fontFamily, list); } /// Unregister all fonts that have been registered. @override void clear() { - _assetFontManager = null; - _testFontManager = null; domDocument.fonts!.clear(); } -} - -/// Manages a collection of fonts and ensures they are loaded. -class FontManager { - - /// Fonts that started the downloading process. Once the fonts have downloaded - /// without error, they are moved to [_downloadedFonts]. Those fonts - /// are subsequently registered by [registerDownloadedFonts]. - final List> _fontLoadingFutures = >[]; - - final List _downloadedFonts = []; // Regular expression to detect a string with no punctuations. // For example font family 'Ahem!' does not fall into this category @@ -126,74 +102,62 @@ class FontManager { /// /// * https://developer.mozilla.org/en-US/docs/Web/CSS/font-family#Valid_family_names /// * https://drafts.csswg.org/css-fonts-3/#font-family-prop - void downloadAsset( + Future _loadFontAsset( String family, String asset, Map descriptors, - ) { - if (startWithDigit.hasMatch(family) || - notPunctuation.stringMatch(family) != family) { - // Load a font family name with special characters once here wrapped in - // quotes. - _loadFontFace("'$family'", asset, descriptors); + ) async { + final List fontFaces = []; + try { + if (startWithDigit.hasMatch(family) || + notPunctuation.stringMatch(family) != family) { + // Load a font family name with special characters once here wrapped in + // quotes. + fontFaces.add(await _loadFontFace("'$family'", asset, descriptors)); + } + // Load all fonts, without quoted family names. + fontFaces.add(await _loadFontFace(family, asset, descriptors)); + } on FontLoadError catch (error) { + return error; + } + try { + fontFaces.forEach(domDocument.fonts!.add); + } catch (e) { + return FontInvalidDataError(asset); } - // Load all fonts, without quoted family names. - _loadFontFace(family, asset, descriptors); + return null; } - void _loadFontFace( + Future _loadFontFace( String family, String asset, Map descriptors, - ) { - Future fontFaceLoad(DomFontFace fontFace) async { - try { - final DomFontFace loadedFontFace = await fontFace.load(); - return loadedFontFace; - } catch (e) { - printWarning('Error while trying to load font family "$family":\n$e'); - return null; - } - } + ) async { // try/catch because `new FontFace` can crash with an improper font family. try { final DomFontFace fontFace = createDomFontFace(family, asset, descriptors); - _fontLoadingFutures.add(fontFaceLoad(fontFace)); + return await fontFace.load(); } catch (e) { printWarning('Error while loading font family "$family":\n$e'); + throw FontDownloadError(asset, e); } } - void registerDownloadedFonts() { - if (_downloadedFonts.isEmpty) { - return; - } - _downloadedFonts.forEach(domDocument.fonts!.add); - } - - - Future downloadAllFonts() async { - final List loadedFonts = await Future.wait(_fontLoadingFutures); - _downloadedFonts.addAll(loadedFonts.whereType()); - } - // Loads a font from bytes, surfacing errors through the future. - Future _loadFontFaceBytes(String family, Uint8List list) { + Future _loadFontFaceBytes(String family, Uint8List list) async { // Since these fonts are loaded by user code, surface the error // through the returned future. final DomFontFace fontFace = createDomFontFace(family, list); - return fontFace.load().then((_) { + try { domDocument.fonts!.add(fontFace); // There might be paragraph measurements for this new font before it is // loaded. They were measured using fallback font, so we should clear the // cache. Spanometer.clearRulersCache(); - }, onError: (dynamic exception) { - // Failures here will throw an DomException which confusingly - // does not implement Exception or Error. Rethrow an Exception so it can - // be caught in user code without depending on dart:html or requiring a - // catch block without "on". - throw Exception(exception.toString()); - }); + } catch (exception) { + // Failures here will throw an DomException. Return false. + return false; + } + return true; } } diff --git a/lib/web_ui/skwasm/fonts.cpp b/lib/web_ui/skwasm/fonts.cpp index bd57a5e04051a..53fbc08a8c559 100644 --- a/lib/web_ui/skwasm/fonts.cpp +++ b/lib/web_ui/skwasm/fonts.cpp @@ -29,15 +29,19 @@ SKWASM_EXPORT void fontCollection_dispose(FlutterFontCollection* collection) { delete collection; } -SKWASM_EXPORT void fontCollection_registerFont( +SKWASM_EXPORT bool fontCollection_registerFont( FlutterFontCollection* collection, SkData* fontData, SkString* fontName) { fontData->ref(); auto typeFace = collection->provider->makeFromData(sk_sp(fontData)); + if (!typeFace) { + return false; + } if (fontName != nullptr) { collection->provider->registerTypeface(std::move(typeFace), *fontName); } else { collection->provider->registerTypeface(std::move(typeFace)); } + return true; } diff --git a/lib/web_ui/test/canvaskit/canvaskit_api_test.dart b/lib/web_ui/test/canvaskit/canvaskit_api_test.dart index 748d5e535010d..5b9518b869384 100644 --- a/lib/web_ui/test/canvaskit/canvaskit_api_test.dart +++ b/lib/web_ui/test/canvaskit/canvaskit_api_test.dart @@ -1528,11 +1528,6 @@ void _textStyleTests() { } void _paragraphTests() { - setUpAll(() async { - await CanvasKitRenderer.instance.fontCollection.debugDownloadTestFonts(); - CanvasKitRenderer.instance.fontCollection.registerDownloadedFonts(); - }); - // This test is just a kitchen sink that blasts CanvasKit with all paragraph // properties all at once, making sure CanvasKit doesn't choke on anything. // In particular, this tests that our JS bindings are correct, such as that diff --git a/lib/web_ui/test/canvaskit/common.dart b/lib/web_ui/test/canvaskit/common.dart index 991a77f8ffd10..e4f954ddc9c89 100644 --- a/lib/web_ui/test/canvaskit/common.dart +++ b/lib/web_ui/test/canvaskit/common.dart @@ -11,14 +11,17 @@ import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; import 'package:web_engine_tester/golden_tester.dart'; +import '../common/fake_asset_manager.dart'; + const MethodCodec codec = StandardMethodCodec(); /// Common test setup for all CanvasKit unit-tests. void setUpCanvasKitTest() { + setUpTestFonts(); setUpAll(() async { expect(renderer, isA(), reason: 'This test must run in CanvasKit mode.'); debugDisableFontFallbacks = false; - await initializeEngine(assetManager: WebOnlyMockAssetManager()); + await initializeEngine(assetManager: fakeAssetManager); }); tearDown(() { diff --git a/lib/web_ui/test/canvaskit/skia_font_collection_test.dart b/lib/web_ui/test/canvaskit/skia_font_collection_test.dart index 75764a8c35f4f..903c2d6128cd3 100644 --- a/lib/web_ui/test/canvaskit/skia_font_collection_test.dart +++ b/lib/web_ui/test/canvaskit/skia_font_collection_test.dart @@ -9,18 +9,23 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; +import '../common/fake_asset_manager.dart'; +import 'common.dart'; + void main() { internalBootstrapBrowserTest(() => testMain); } void testMain() { group('$SkiaFontCollection', () { + setUpCanvasKitTest(); + final List warnings = []; late void Function(String) oldPrintWarning; + late FakeAssetScope testAssetScope; setUpAll(() async { ensureFlutterViewEmbedderInitialized(); - await renderer.initialize(); oldPrintWarning = printWarning; printWarning = (String warning) { warnings.add(warning); @@ -32,20 +37,19 @@ void testMain() { }); setUp(() { + testAssetScope = fakeAssetManager.pushAssetScope(); mockHttpFetchResponseFactory = null; warnings.clear(); }); tearDown(() { + fakeAssetManager.popAssetScope(testAssetScope); mockHttpFetchResponseFactory = null; }); test('logs no warnings with the default mock asset manager', () async { final SkiaFontCollection fontCollection = SkiaFontCollection(); - final WebOnlyMockAssetManager mockAssetManager = - WebOnlyMockAssetManager(); - await fontCollection.downloadAssetFonts(mockAssetManager); - fontCollection.registerDownloadedFonts(); + await fontCollection.loadAssetFonts(await fetchFontManifest(fakeAssetManager)); expect(warnings, isEmpty); }); @@ -61,9 +65,7 @@ void testMain() { ); }; final SkiaFontCollection fontCollection = SkiaFontCollection(); - final WebOnlyMockAssetManager mockAssetManager = - WebOnlyMockAssetManager(); - mockAssetManager.defaultFontManifest = ''' + testAssetScope.setAsset('FontManifest.json', stringAsUtf8Data(''' [ { "family":"Roboto", @@ -74,10 +76,9 @@ void testMain() { "fonts":[{"asset":"packages/bogus/BrokenFont.ttf"}] } ] - '''; + ''')); // It should complete without error, but emit a warning about BrokenFont. - await fontCollection.downloadAssetFonts(mockAssetManager); - fontCollection.registerDownloadedFonts(); + await fontCollection.loadAssetFonts(await fetchFontManifest(fakeAssetManager)); expect( warnings, containsAllInOrder( @@ -91,9 +92,7 @@ void testMain() { test('logs an HTTP warning if one of the registered fonts is missing (404 file not found)', () async { final SkiaFontCollection fontCollection = SkiaFontCollection(); - final WebOnlyMockAssetManager mockAssetManager = - WebOnlyMockAssetManager(); - mockAssetManager.defaultFontManifest = ''' + testAssetScope.setAsset('FontManifest.json', stringAsUtf8Data(''' [ { "family":"Roboto", @@ -104,11 +103,10 @@ void testMain() { "fonts":[{"asset":"packages/bogus/ThisFontDoesNotExist.ttf"}] } ] - '''; + ''')); // It should complete without error, but emit a warning about ThisFontDoesNotExist. - await fontCollection.downloadAssetFonts(mockAssetManager); - fontCollection.registerDownloadedFonts(); + await fontCollection.loadAssetFonts(await fetchFontManifest(fakeAssetManager)); expect( warnings, containsAllInOrder([ @@ -120,22 +118,18 @@ void testMain() { test('prioritizes Ahem loaded via FontManifest.json', () async { final SkiaFontCollection fontCollection = SkiaFontCollection(); - final WebOnlyMockAssetManager mockAssetManager = - WebOnlyMockAssetManager(); - mockAssetManager.defaultFontManifest = ''' + testAssetScope.setAsset('FontManifest.json', stringAsUtf8Data(''' [ { "family":"Ahem", "fonts":[{"asset":"/assets/fonts/Roboto-Regular.ttf"}] } ] - '''.trim(); + '''.trim())); final ByteBuffer robotoData = await httpFetchByteBuffer('/assets/fonts/Roboto-Regular.ttf'); - await fontCollection.downloadAssetFonts(mockAssetManager); - await fontCollection.debugDownloadTestFonts(); - fontCollection.registerDownloadedFonts(); + await fontCollection.loadAssetFonts(await fetchFontManifest(fakeAssetManager)); expect(warnings, isEmpty); // Use `singleWhere` to make sure only one version of 'Ahem' is loaded. @@ -149,15 +143,11 @@ void testMain() { test('falls back to default Ahem URL', () async { final SkiaFontCollection fontCollection = SkiaFontCollection(); - final WebOnlyMockAssetManager mockAssetManager = - WebOnlyMockAssetManager(); - mockAssetManager.defaultFontManifest = '[]'; + testAssetScope.setAsset('FontManifest.json', stringAsUtf8Data('[]')); final ByteBuffer ahemData = await httpFetchByteBuffer('/assets/fonts/ahem.ttf'); - await fontCollection.downloadAssetFonts(mockAssetManager); - await fontCollection.debugDownloadTestFonts(); - fontCollection.registerDownloadedFonts(); + await fontCollection.loadAssetFonts(await fetchFontManifest(fakeAssetManager)); expect(warnings, isEmpty); // Use `singleWhere` to make sure only one version of 'Ahem' is loaded. @@ -168,27 +158,5 @@ void testMain() { // what's specified in the manifest, and the manifest takes precedence. expect(ahem.bytes.length, ahemData.lengthInBytes); }); - - test('download fonts separately from registering', () async { - final SkiaFontCollection fontCollection = SkiaFontCollection(); - - await fontCollection.debugDownloadTestFonts(); - /// Fonts should have been downloaded, but not yet registered - expect(fontCollection.debugRegisteredFonts, isEmpty); - - fontCollection.registerDownloadedFonts(); - /// Fonts should now be registered and _registeredFonts should be filled - expect(fontCollection.debugRegisteredFonts, isNotEmpty); - expect(warnings, isEmpty); - }); - - test('FlutterTest is the default test font', () async { - final SkiaFontCollection fontCollection = SkiaFontCollection(); - - await fontCollection.debugDownloadTestFonts(); - fontCollection.registerDownloadedFonts(); - expect(fontCollection.debugRegisteredFonts, isNotEmpty); - expect(fontCollection.debugRegisteredFonts!.first.family, 'FlutterTest'); - }); }); } diff --git a/lib/web_ui/test/common/fake_asset_manager.dart b/lib/web_ui/test/common/fake_asset_manager.dart new file mode 100644 index 0000000000000..45c85b6840f0f --- /dev/null +++ b/lib/web_ui/test/common/fake_asset_manager.dart @@ -0,0 +1,151 @@ +// 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:convert'; +import 'dart:typed_data'; + +import 'package:test/test.dart'; +import 'package:ui/src/engine.dart'; + +class FakeAssetManager implements AssetManager { + FakeAssetManager(); + + @override + String get assetsDir => 'assets'; + + @override + String getAssetUrl(String asset) => asset; + + @override + Future load(String assetKey) async { + final ByteData? data = _assetMap[assetKey]; + if (data == null) { + throw HttpFetchNoPayloadError(assetKey, status: 404); + } + return data; + } + + @override + Future loadAsset(String asset) async { + final ByteData? assetData = await _currentScope?.getAssetData(asset); + if (assetData != null) { + return MockHttpFetchResponse( + url: asset, + status: 200, + payload: MockHttpFetchPayload( + byteBuffer: assetData.buffer, + ), + ); + } else { + return MockHttpFetchResponse( + url: asset, + status: 404, + ); + } + } + + FakeAssetScope pushAssetScope() { + final FakeAssetScope scope = FakeAssetScope._(_currentScope); + _currentScope = scope; + return scope; + } + + void popAssetScope(FakeAssetScope scope) { + assert(_currentScope == scope); + _currentScope = scope._parent; + } + + void setAsset(String assetKey, ByteData assetData) { + _assetMap[assetKey] = assetData; + } + + FakeAssetScope? _currentScope; + final Map _assetMap = {}; +} + +class FakeAssetScope { + FakeAssetScope._(this._parent); + + final FakeAssetScope? _parent; + final Map Function()> _assetFetcherMap = Function()>{}; + + void setAsset(String assetKey, ByteData assetData) { + _assetFetcherMap[assetKey] = () async => assetData; + } + + void setAssetPassthrough(String assetKey) { + _assetFetcherMap[assetKey] = () async { + return ByteData.view(await httpFetchByteBuffer(assetKey)); + }; + } + + Future? getAssetData(String assetKey) { + final Future Function()? fetcher = _assetFetcherMap[assetKey]; + if (fetcher != null) { + return fetcher(); + } + if (_parent != null) { + return _parent!.getAssetData(assetKey); + } + return null; + } +} + +FakeAssetManager fakeAssetManager = FakeAssetManager(); + +ByteData stringAsUtf8Data(String string) { + return ByteData.view(Uint8List.fromList(utf8.encode(string)).buffer); +} + +const String ahemFontFamily = 'Ahem'; +const String ahemFontUrl = '/assets/fonts/ahem.ttf'; +const String robotoFontFamily = 'Roboto'; +const String robotoTestFontUrl = '/assets/fonts/Roboto-Regular.ttf'; +const String robotoVariableFontFamily = 'RobotoVariable'; +const String robotoVariableFontUrl = '/assets/fonts/RobotoSlab-VariableFont_wght.ttf'; + +/// The list of test fonts, in the form of font family name - font file url pairs. +/// This list does not include embedded test fonts, which need to be loaded and +/// registered separately in [FontCollection.debugDownloadTestFonts]. +const Map testFontUrls = { + ahemFontFamily: ahemFontUrl, + robotoFontFamily: robotoTestFontUrl, + robotoVariableFontFamily: robotoVariableFontUrl, +}; + +FakeAssetScope configureDebugFontsAssetScope(FakeAssetManager manager) { + final FakeAssetScope scope = manager.pushAssetScope(); + scope.setAsset('AssetManifest.json', stringAsUtf8Data('{}')); + scope.setAsset('FontManifest.json', stringAsUtf8Data(''' + [ + { + "family":"$robotoFontFamily", + "fonts":[{"asset":"$robotoTestFontUrl"}] + }, + { + "family":"$ahemFontFamily", + "fonts":[{"asset":"$ahemFontUrl"}] + }, + { + "family":"$robotoVariableFontFamily", + "fonts":[{"asset":"$robotoVariableFontUrl"}] + } + ]''')); + scope.setAssetPassthrough(robotoTestFontUrl); + scope.setAssetPassthrough(ahemFontUrl); + scope.setAssetPassthrough(robotoVariableFontUrl); + return scope; +} + +void setUpTestFonts() { + late final FakeAssetScope debugFontsScope; + setUpAll(() async { + debugFontsScope = configureDebugFontsAssetScope(fakeAssetManager); + await initializeEngine(assetManager: fakeAssetManager); + }); + + tearDownAll(() async { + fakeAssetManager.popAssetScope(debugFontsScope); + }); +} diff --git a/lib/web_ui/test/common/initialize_view_embedder.dart b/lib/web_ui/test/common/initialize_view_embedder.dart new file mode 100644 index 0000000000000..123d96596f6a0 --- /dev/null +++ b/lib/web_ui/test/common/initialize_view_embedder.dart @@ -0,0 +1,31 @@ +// 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 'package:ui/src/engine.dart'; +import 'package:ui/ui.dart' as ui; + +import 'fake_asset_manager.dart'; + +Future? _platformInitializedFuture; + +Future initializeTestFlutterViewEmbedder({double devicePixelRatio = 3.0}) { + // Force-initialize FlutterViewEmbedder so it doesn't overwrite test pixel ratio. + ensureFlutterViewEmbedderInitialized(); + + // The following parameters are hard-coded in Flutter's test embedder. Since + // we don't have an embedder yet this is the lowest-most layer we can put + // this stuff in. + window.debugOverrideDevicePixelRatio(devicePixelRatio); + window.webOnlyDebugPhysicalSizeOverride = + ui.Size(800 * devicePixelRatio, 600 * devicePixelRatio); + scheduleFrameCallback = () {}; + ui.debugEmulateFlutterTesterEnvironment = true; + + // Initialize platform once and reuse across all tests. + if (_platformInitializedFuture != null) { + return _platformInitializedFuture!; + } + return _platformInitializedFuture = + initializeEngine(assetManager: fakeAssetManager); +} diff --git a/lib/web_ui/test/engine/clipboard_test.dart b/lib/web_ui/test/engine/clipboard_test.dart index 48578bf246b5b..9ea91ec70ea95 100644 --- a/lib/web_ui/test/engine/clipboard_test.dart +++ b/lib/web_ui/test/engine/clipboard_test.dart @@ -9,6 +9,8 @@ import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; +import '../common/initialize_view_embedder.dart'; + void main() { internalBootstrapBrowserTest(() => testMain); } diff --git a/lib/web_ui/test/engine/image/html_image_codec_test.dart b/lib/web_ui/test/engine/image/html_image_codec_test.dart index 9017fde35d081..27fd5cae701b6 100644 --- a/lib/web_ui/test/engine/image/html_image_codec_test.dart +++ b/lib/web_ui/test/engine/image/html_image_codec_test.dart @@ -8,9 +8,10 @@ import 'dart:typed_data'; import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/src/engine/html_image_codec.dart'; -import 'package:ui/src/engine/test_embedding.dart'; import 'package:ui/ui.dart' as ui; +import '../../common/initialize_view_embedder.dart'; + void main() { internalBootstrapBrowserTest(() => testMain); } diff --git a/lib/web_ui/test/engine/image_to_byte_data_test.dart b/lib/web_ui/test/engine/image_to_byte_data_test.dart index a9bb8a791f2ea..556da379b2c15 100644 --- a/lib/web_ui/test/engine/image_to_byte_data_test.dart +++ b/lib/web_ui/test/engine/image_to_byte_data_test.dart @@ -9,15 +9,17 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart'; +import '../common/fake_asset_manager.dart'; + void main() { internalBootstrapBrowserTest(() => testMain); } Future testMain() async { + setUpTestFonts(); + setUpAll(() async { - await webOnlyInitializePlatform(); - await renderer.fontCollection.debugDownloadTestFonts(); - renderer.fontCollection.registerDownloadedFonts(); + await initializeEngine(assetManager: fakeAssetManager); }); Future createTestImageByColor(Color color) async { diff --git a/lib/web_ui/test/html/canvas_clip_path_golden_test.dart b/lib/web_ui/test/html/canvas_clip_path_golden_test.dart index 7242600b361e6..ce575898e7d5f 100644 --- a/lib/web_ui/test/html/canvas_clip_path_golden_test.dart +++ b/lib/web_ui/test/html/canvas_clip_path_golden_test.dart @@ -7,8 +7,10 @@ import 'dart:js_util' as js_util; import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/src/engine.dart' as engine; +import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' hide TextStyle; +import '../common/fake_asset_manager.dart'; import 'screenshot.dart'; void main() { @@ -18,9 +20,7 @@ void main() { Future testMain() async { setUpAll(() async { debugEmulateFlutterTesterEnvironment = true; - await webOnlyInitializePlatform(); - await engine.renderer.fontCollection.debugDownloadTestFonts(); - engine.renderer.fontCollection.registerDownloadedFonts(); + await initializeEngine(assetManager: fakeAssetManager); }); // Regression test for https://github.com/flutter/flutter/issues/48683 diff --git a/lib/web_ui/test/html/canvas_context_golden_test.dart b/lib/web_ui/test/html/canvas_context_golden_test.dart index 53a9d30a2e201..e44d3339909fd 100644 --- a/lib/web_ui/test/html/canvas_context_golden_test.dart +++ b/lib/web_ui/test/html/canvas_context_golden_test.dart @@ -7,6 +7,7 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart' as engine; import 'package:ui/ui.dart' hide TextStyle; +import '../common/fake_asset_manager.dart'; import 'screenshot.dart'; void main() { @@ -21,9 +22,7 @@ Future testMain() async { setUpAll(() async { debugEmulateFlutterTesterEnvironment = true; - await webOnlyInitializePlatform(); - await engine.renderer.fontCollection.debugDownloadTestFonts(); - engine.renderer.fontCollection.registerDownloadedFonts(); + await engine.initializeEngine(assetManager: fakeAssetManager); }); // Regression test for https://github.com/flutter/flutter/issues/49429 diff --git a/lib/web_ui/test/html/text/canvas_paragraph_builder_test.dart b/lib/web_ui/test/html/text/canvas_paragraph_builder_test.dart index c51e4e4897e3f..0d1e8bbc1e873 100644 --- a/lib/web_ui/test/html/text/canvas_paragraph_builder_test.dart +++ b/lib/web_ui/test/html/text/canvas_paragraph_builder_test.dart @@ -7,6 +7,7 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart'; +import '../../common/initialize_view_embedder.dart'; import '../paragraph/helper.dart'; /// Some text measurements are sensitive to browser implementations. Position diff --git a/lib/web_ui/test/html/text/canvas_paragraph_test.dart b/lib/web_ui/test/html/text/canvas_paragraph_test.dart index 48dcfa89b9e68..f4e4096c87ff2 100644 --- a/lib/web_ui/test/html/text/canvas_paragraph_test.dart +++ b/lib/web_ui/test/html/text/canvas_paragraph_test.dart @@ -7,6 +7,7 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; +import '../../common/initialize_view_embedder.dart'; import '../paragraph/helper.dart'; void main() { diff --git a/lib/web_ui/test/html/text/font_loading_test.dart b/lib/web_ui/test/html/text/font_loading_test.dart index d96ca6acb22f0..c7686bd1a7beb 100644 --- a/lib/web_ui/test/html/text/font_loading_test.dart +++ b/lib/web_ui/test/html/text/font_loading_test.dart @@ -11,6 +11,8 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; +import '../../common/initialize_view_embedder.dart'; + void main() { internalBootstrapBrowserTest(() => testMain); } diff --git a/lib/web_ui/test/html/text/layout_service_plain_test.dart b/lib/web_ui/test/html/text/layout_service_plain_test.dart index ca9257864c376..961bf8e309965 100644 --- a/lib/web_ui/test/html/text/layout_service_plain_test.dart +++ b/lib/web_ui/test/html/text/layout_service_plain_test.dart @@ -7,6 +7,7 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; +import '../../common/initialize_view_embedder.dart'; import '../paragraph/helper.dart'; import 'layout_service_helper.dart'; diff --git a/lib/web_ui/test/html/text/layout_service_rich_test.dart b/lib/web_ui/test/html/text/layout_service_rich_test.dart index d7c53da10833b..b714c90a3bb4e 100644 --- a/lib/web_ui/test/html/text/layout_service_rich_test.dart +++ b/lib/web_ui/test/html/text/layout_service_rich_test.dart @@ -8,6 +8,7 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; +import '../../common/initialize_view_embedder.dart'; import '../paragraph/helper.dart'; import 'layout_service_helper.dart'; diff --git a/lib/web_ui/test/html/text_test.dart b/lib/web_ui/test/html/text_test.dart index 2b7e629fb2917..d6ea701421779 100644 --- a/lib/web_ui/test/html/text_test.dart +++ b/lib/web_ui/test/html/text_test.dart @@ -11,6 +11,7 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart'; +import '../common/initialize_view_embedder.dart'; import '../common/matchers.dart'; import 'paragraph/helper.dart'; diff --git a/lib/web_ui/test/ui/font_collection_test.dart b/lib/web_ui/test/ui/font_collection_test.dart new file mode 100644 index 0000000000000..a04c94872cb11 --- /dev/null +++ b/lib/web_ui/test/ui/font_collection_test.dart @@ -0,0 +1,47 @@ +// 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:convert'; +import 'dart:typed_data'; + +import 'package:test/bootstrap/browser.dart'; +import 'package:test/test.dart'; +import 'package:ui/src/engine.dart'; + +import 'utils.dart'; + +void main() { + internalBootstrapBrowserTest(() => testMain); +} + +Future testMain() async { + setUpUiTest(); + + test('Loading valid font from data succeeds without family name', () async { + final FlutterFontCollection collection = renderer.fontCollection; + final ByteBuffer ahemData = await httpFetchByteBuffer('/assets/fonts/ahem.ttf'); + await expectLater( + collection.loadFontFromList(ahemData.asUint8List()), + returnsNormally + ); + }, skip: isHtml); // HtmlFontCollection requires family name + + test('Loading valid font from data succeeds with family name', () async { + final FlutterFontCollection collection = renderer.fontCollection; + final ByteBuffer ahemData = await httpFetchByteBuffer('/assets/fonts/ahem.ttf'); + await expectLater( + collection.loadFontFromList(ahemData.asUint8List(), fontFamily: 'FamilyName'), + returnsNormally + ); + }); + + test('Loading invalid font from data throws', () async { + final FlutterFontCollection collection = renderer.fontCollection; + final List invalidFontData = utf8.encode('This is not valid font data'); + await expectLater( + collection.loadFontFromList(Uint8List.fromList(invalidFontData), fontFamily: 'FamilyName'), + throwsException + ); + }); +} diff --git a/lib/web_ui/test/ui/utils.dart b/lib/web_ui/test/ui/utils.dart index 01b42125383bb..4ce4f515c5612 100644 --- a/lib/web_ui/test/ui/utils.dart +++ b/lib/web_ui/test/ui/utils.dart @@ -4,53 +4,19 @@ import 'dart:async'; import 'dart:js_interop'; -import 'dart:typed_data'; import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/src/engine/skwasm/skwasm_stub.dart' if (dart.library.ffi) 'package:ui/src/engine/skwasm/skwasm_impl.dart'; import 'package:ui/ui.dart'; -class FakeAssetManager implements AssetManager { - FakeAssetManager(this._parent); - - @override - String get assetsDir => 'assets'; - - @override - String getAssetUrl(String asset) => asset; - - @override - Future load(String assetKey) async { - final ByteData? data = _assetMap[assetKey]; - if (data == null) { - return _parent.load(assetKey); - } - return data; - } - - @override - Future loadAsset(String asset) { - return _parent.loadAsset(asset); - } - - void setAsset(String assetKey, ByteData assetData) { - _assetMap[assetKey] = assetData; - } - - final Map _assetMap = {}; - final AssetManager _parent; -} - -FakeAssetManager fakeAssetManager = FakeAssetManager(WebOnlyMockAssetManager()); +import '../common/fake_asset_manager.dart'; /// Initializes the renderer for this test. void setUpUiTest() { - setUpAll(() async { + setUpTestFonts(); + setUpAll(() { debugEmulateFlutterTesterEnvironment = true; - await initializeEngine(assetManager: fakeAssetManager); - await renderer.fontCollection.debugDownloadTestFonts(); - renderer.fontCollection.registerDownloadedFonts(); }); } From 99f0787ae013585e824a5b48ac2eb8feee301b2a Mon Sep 17 00:00:00 2001 From: Jackson Gardner Date: Fri, 21 Apr 2023 13:04:07 -0700 Subject: [PATCH 15/30] More unit test fixes. --- lib/web_ui/lib/src/engine/assets.dart | 14 --- .../lib/src/engine/canvaskit/fonts.dart | 4 + lib/web_ui/lib/src/engine/initialization.dart | 10 ++ lib/web_ui/lib/src/engine/test_embedding.dart | 2 - .../lib/src/engine/text/font_collection.dart | 22 ++-- lib/web_ui/test/canvaskit/common.dart | 13 ++- .../canvaskit/fallback_fonts_golden_test.dart | 4 + .../canvaskit/skia_font_collection_test.dart | 16 +-- .../test/common/fake_asset_manager.dart | 13 --- .../test/common/initialize_view_embedder.dart | 31 ------ .../test/common/test_initialization.dart | 57 ++++++++++ lib/web_ui/test/engine/clipboard_test.dart | 4 +- .../engine/image/html_image_codec_test.dart | 4 +- .../test/engine/image_to_byte_data_test.dart | 8 +- .../test/engine/recording_canvas_test.dart | 5 +- .../test/html/bitmap_canvas_golden_test.dart | 4 +- .../test/html/canvas_reuse_golden_test.dart | 9 +- lib/web_ui/test/html/clip_op_golden_test.dart | 3 +- .../backdrop_filter_golden_test.dart | 8 +- .../compositing/canvas_blend_golden_test.dart | 9 +- .../canvas_image_blend_mode_golden_test.dart | 8 +- .../canvas_mask_filter_golden_test.dart | 8 +- .../compositing/color_filter_golden_test.dart | 8 +- .../compositing/compositing_golden_test.dart | 7 +- .../dom_mask_filter_golden_test.dart | 8 +- .../canvas_draw_color_golden_test.dart | 6 +- .../canvas_draw_image_golden_test.dart | 8 +- .../canvas_draw_picture_golden_test.dart | 6 +- .../drawing/draw_vertices_golden_test.dart | 8 +- .../test/html/paragraph/bidi_golden_test.dart | 4 +- .../html/paragraph/general_golden_test.dart | 4 +- .../html/paragraph/justify_golden_test.dart | 4 +- .../html/paragraph/overflow_golden_test.dart | 4 +- .../paragraph/placeholders_golden_test.dart | 4 +- .../html/paragraph/shadows_golden_test.dart | 4 +- .../text_multiline_clipping_golden_test.dart | 4 +- .../paragraph/text_overflow_golden_test.dart | 4 +- .../text_placeholders_golden_test.dart | 5 +- .../test/html/path_metrics_golden_test.dart | 8 +- .../test/html/path_transform_golden_test.dart | 8 +- .../html/recording_canvas_golden_test.dart | 8 +- lib/web_ui/test/html/screenshot.dart | 12 -- .../html/shaders/gradient_golden_test.dart | 7 +- .../shaders/image_shader_golden_test.dart | 8 +- .../shaders/linear_gradient_golden_test.dart | 8 +- .../shaders/radial_gradient_golden_test.dart | 9 +- .../html/shaders/shader_mask_golden_test.dart | 7 +- lib/web_ui/test/html/shadow_golden_test.dart | 4 +- .../text/canvas_paragraph_builder_test.dart | 4 +- .../test/html/text/canvas_paragraph_test.dart | 4 +- .../test/html/text/font_collection_test.dart | 103 +++++++++++------- .../test/html/text/font_loading_test.dart | 8 +- .../html/text/layout_service_plain_test.dart | 4 +- .../html/text/layout_service_rich_test.dart | 4 +- lib/web_ui/test/html/text_test.dart | 5 +- lib/web_ui/test/ui/README.md | 2 +- .../test/ui/canvas_curves_golden_test.dart | 3 +- .../test/ui/canvas_lines_golden_test.dart | 3 +- lib/web_ui/test/ui/canvas_test.dart | 4 +- lib/web_ui/test/ui/color_test.dart | 4 +- lib/web_ui/test/ui/font_collection_test.dart | 21 ++-- lib/web_ui/test/ui/fragment_shader_test.dart | 4 +- lib/web_ui/test/ui/gradient_golden_test.dart | 3 +- lib/web_ui/test/ui/gradient_test.dart | 3 +- .../test/ui/paragraph_builder_test.dart | 3 +- lib/web_ui/test/ui/path_metrics_test.dart | 4 +- lib/web_ui/test/ui/path_test.dart | 3 +- lib/web_ui/test/ui/picture_test.dart | 4 +- lib/web_ui/test/ui/rect_test.dart | 4 +- lib/web_ui/test/ui/rrect_test.dart | 4 +- lib/web_ui/test/ui/scene_builder_test.dart | 3 +- lib/web_ui/test/ui/shadow_test.dart | 3 +- lib/web_ui/test/ui/title_test.dart | 4 +- lib/web_ui/test/ui/utils.dart | 11 -- 74 files changed, 307 insertions(+), 338 deletions(-) delete mode 100644 lib/web_ui/test/common/initialize_view_embedder.dart create mode 100644 lib/web_ui/test/common/test_initialization.dart diff --git a/lib/web_ui/lib/src/engine/assets.dart b/lib/web_ui/lib/src/engine/assets.dart index 51a4acb77d91a..585f9d4f39dad 100644 --- a/lib/web_ui/lib/src/engine/assets.dart +++ b/lib/web_ui/lib/src/engine/assets.dart @@ -8,20 +8,6 @@ import 'dart:typed_data'; import 'dom.dart'; import 'util.dart'; -const String ahemFontFamily = 'Ahem'; -const String ahemFontUrl = '/assets/fonts/ahem.ttf'; -const String robotoFontFamily = 'Roboto'; -const String robotoTestFontUrl = '/assets/fonts/Roboto-Regular.ttf'; - -/// The list of test fonts, in the form of font family name - font file url pairs. -/// This list does not include embedded test fonts, which need to be loaded and -/// registered separately in [FontCollection.debugDownloadTestFonts]. -const Map testFontUrls = { - ahemFontFamily: ahemFontUrl, - robotoFontFamily: robotoTestFontUrl, - 'RobotoVariable': '/assets/fonts/RobotoSlab-VariableFont_wght.ttf', -}; - /// This class downloads assets over the network. /// /// Assets are resolved relative to [assetsDir] inside the absolute base diff --git a/lib/web_ui/lib/src/engine/canvaskit/fonts.dart b/lib/web_ui/lib/src/engine/canvaskit/fonts.dart index 5eb8df4757c78..cc329a3cdb47b 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/fonts.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/fonts.dart @@ -78,6 +78,9 @@ class SkiaFontCollection implements FlutterFontCollection { } } + // Make sure CanvasKit is actually loaded + await renderer.initialize(); + final SkTypeface? typeface = canvasKit.Typeface.MakeFreeTypeFaceFromData(list.buffer); if (typeface != null) { @@ -185,6 +188,7 @@ class SkiaFontCollection implements FlutterFontCollection { try { final HttpFetchResponse response = await httpFetch(url); if (!response.hasPayload) { + printWarning('Font family $fontFamily not found (404) at $url'); return FontDownloadResult.fromError(assetName, FontNotFoundError(url)); } diff --git a/lib/web_ui/lib/src/engine/initialization.dart b/lib/web_ui/lib/src/engine/initialization.dart index 5e292a7d38480..18cb6597f90d5 100644 --- a/lib/web_ui/lib/src/engine/initialization.dart +++ b/lib/web_ui/lib/src/engine/initialization.dart @@ -8,6 +8,7 @@ import 'dart:js_interop'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; +import 'package:web_test_fonts/web_test_fonts.dart'; /// The mode the app is running in. /// Keep these in sync with the same constants on the framework-side under foundation/constants.dart. @@ -247,6 +248,15 @@ void _setAssetManager(AssetManager assetManager) { Future _downloadAssetFonts() async { renderer.fontCollection.clear(); + if (ui.debugEmulateFlutterTesterEnvironment) { + // Load the embedded test font before loading fonts from the assets so that + // the embedded test font is the default (first) font. + await renderer.fontCollection.loadFontFromList( + EmbeddedTestFont.flutterTest.data, + fontFamily: EmbeddedTestFont.flutterTest.fontFamily + ); + } + if (_assetManager != null) { await renderer.fontCollection.loadAssetFonts(await fetchFontManifest(assetManager)); } diff --git a/lib/web_ui/lib/src/engine/test_embedding.dart b/lib/web_ui/lib/src/engine/test_embedding.dart index 85030b714aab2..18febe3f233ff 100644 --- a/lib/web_ui/lib/src/engine/test_embedding.dart +++ b/lib/web_ui/lib/src/engine/test_embedding.dart @@ -10,8 +10,6 @@ import 'dart:async'; import 'package:ui/ui.dart' as ui; import 'package:ui/ui_web/src/ui_web.dart' as ui_web; -import '../engine.dart'; - const bool _debugLogHistoryActions = false; class TestHistoryEntry { diff --git a/lib/web_ui/lib/src/engine/text/font_collection.dart b/lib/web_ui/lib/src/engine/text/font_collection.dart index 59cfcd31c2698..d7995efc7f086 100644 --- a/lib/web_ui/lib/src/engine/text/font_collection.dart +++ b/lib/web_ui/lib/src/engine/text/font_collection.dart @@ -5,11 +5,7 @@ import 'dart:async'; import 'dart:typed_data'; -import 'package:ui/src/engine/fonts.dart'; - -import '../dom.dart'; -import '../util.dart'; -import 'layout_service.dart'; +import 'package:ui/src/engine.dart'; /// This class is responsible for registering and loading fonts. /// @@ -108,6 +104,7 @@ class HtmlFontCollection implements FlutterFontCollection { Map descriptors, ) async { final List fontFaces = []; + final List errors = []; try { if (startWithDigit.hasMatch(family) || notPunctuation.stringMatch(family) != family) { @@ -115,11 +112,20 @@ class HtmlFontCollection implements FlutterFontCollection { // quotes. fontFaces.add(await _loadFontFace("'$family'", asset, descriptors)); } - // Load all fonts, without quoted family names. + } on FontLoadError catch (error) { + errors.add(error); + } + try { + // Load all fonts, without quoted family names. fontFaces.add(await _loadFontFace(family, asset, descriptors)); } on FontLoadError catch (error) { - return error; + errors.add(error); + } + if (fontFaces.isEmpty) { + // We failed to load either font face. Return the first error. + return errors.first; } + try { fontFaces.forEach(domDocument.fonts!.add); } catch (e) { @@ -135,7 +141,7 @@ class HtmlFontCollection implements FlutterFontCollection { ) async { // try/catch because `new FontFace` can crash with an improper font family. try { - final DomFontFace fontFace = createDomFontFace(family, asset, descriptors); + final DomFontFace fontFace = createDomFontFace(family, 'url(${assetManager.getAssetUrl(asset)})', descriptors); return await fontFace.load(); } catch (e) { printWarning('Error while loading font family "$family":\n$e'); diff --git a/lib/web_ui/test/canvaskit/common.dart b/lib/web_ui/test/canvaskit/common.dart index e4f954ddc9c89..dfd230dac9e95 100644 --- a/lib/web_ui/test/canvaskit/common.dart +++ b/lib/web_ui/test/canvaskit/common.dart @@ -11,17 +11,18 @@ import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; import 'package:web_engine_tester/golden_tester.dart'; -import '../common/fake_asset_manager.dart'; +import '../common/test_initialization.dart'; const MethodCodec codec = StandardMethodCodec(); /// Common test setup for all CanvasKit unit-tests. void setUpCanvasKitTest() { - setUpTestFonts(); - setUpAll(() async { - expect(renderer, isA(), reason: 'This test must run in CanvasKit mode.'); - debugDisableFontFallbacks = false; - await initializeEngine(assetManager: fakeAssetManager); + setUpUnitTests(); + + setUpAll(() { + // Ahem must be added to font fallbacks list regardless of where it was + // downloaded from. + FontFallbackData.instance.globalFontFallbacks.add('Ahem'); }); tearDown(() { 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 960beeb607952..e077a56f88521 100644 --- a/lib/web_ui/test/canvaskit/fallback_fonts_golden_test.dart +++ b/lib/web_ui/test/canvaskit/fallback_fonts_golden_test.dart @@ -24,6 +24,10 @@ void testMain() { group('Font fallbacks', () { setUpCanvasKitTest(); + setUpAll(() { + debugDisableFontFallbacks = false; + }); + /// Used to save and restore [ui.window.onPlatformMessage] after each test. ui.PlatformMessageCallback? savedCallback; diff --git a/lib/web_ui/test/canvaskit/skia_font_collection_test.dart b/lib/web_ui/test/canvaskit/skia_font_collection_test.dart index 903c2d6128cd3..a46c812742d3a 100644 --- a/lib/web_ui/test/canvaskit/skia_font_collection_test.dart +++ b/lib/web_ui/test/canvaskit/skia_font_collection_test.dart @@ -110,8 +110,7 @@ void testMain() { expect( warnings, containsAllInOrder([ - 'Failed to load font ThisFontDoesNotExist at packages/bogus/ThisFontDoesNotExist.ttf', - 'Flutter Web engine failed to fetch "packages/bogus/ThisFontDoesNotExist.ttf". HTTP request succeeded, but the server responded with HTTP status 404.', + 'Font family ThisFontDoesNotExist not found (404) at packages/bogus/ThisFontDoesNotExist.ttf' ]), ); }); @@ -142,14 +141,10 @@ void testMain() { }); test('falls back to default Ahem URL', () async { - final SkiaFontCollection fontCollection = SkiaFontCollection(); - testAssetScope.setAsset('FontManifest.json', stringAsUtf8Data('[]')); + final SkiaFontCollection fontCollection = renderer.fontCollection as SkiaFontCollection; final ByteBuffer ahemData = await httpFetchByteBuffer('/assets/fonts/ahem.ttf'); - await fontCollection.loadAssetFonts(await fetchFontManifest(fakeAssetManager)); - expect(warnings, isEmpty); - // Use `singleWhere` to make sure only one version of 'Ahem' is loaded. final RegisteredFont ahem = fontCollection.debugRegisteredFonts! .singleWhere((RegisteredFont font) => font.family == 'Ahem'); @@ -158,5 +153,12 @@ void testMain() { // what's specified in the manifest, and the manifest takes precedence. expect(ahem.bytes.length, ahemData.lengthInBytes); }); + + test('FlutterTest is the default test font', () async { + final SkiaFontCollection fontCollection = renderer.fontCollection as SkiaFontCollection; + + expect(fontCollection.debugRegisteredFonts, isNotEmpty); + expect(fontCollection.debugRegisteredFonts!.first.family, 'FlutterTest'); + }); }); } diff --git a/lib/web_ui/test/common/fake_asset_manager.dart b/lib/web_ui/test/common/fake_asset_manager.dart index 45c85b6840f0f..2aea72c30315d 100644 --- a/lib/web_ui/test/common/fake_asset_manager.dart +++ b/lib/web_ui/test/common/fake_asset_manager.dart @@ -5,7 +5,6 @@ import 'dart:convert'; import 'dart:typed_data'; -import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; class FakeAssetManager implements AssetManager { @@ -137,15 +136,3 @@ FakeAssetScope configureDebugFontsAssetScope(FakeAssetManager manager) { scope.setAssetPassthrough(robotoVariableFontUrl); return scope; } - -void setUpTestFonts() { - late final FakeAssetScope debugFontsScope; - setUpAll(() async { - debugFontsScope = configureDebugFontsAssetScope(fakeAssetManager); - await initializeEngine(assetManager: fakeAssetManager); - }); - - tearDownAll(() async { - fakeAssetManager.popAssetScope(debugFontsScope); - }); -} diff --git a/lib/web_ui/test/common/initialize_view_embedder.dart b/lib/web_ui/test/common/initialize_view_embedder.dart deleted file mode 100644 index 123d96596f6a0..0000000000000 --- a/lib/web_ui/test/common/initialize_view_embedder.dart +++ /dev/null @@ -1,31 +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 'package:ui/src/engine.dart'; -import 'package:ui/ui.dart' as ui; - -import 'fake_asset_manager.dart'; - -Future? _platformInitializedFuture; - -Future initializeTestFlutterViewEmbedder({double devicePixelRatio = 3.0}) { - // Force-initialize FlutterViewEmbedder so it doesn't overwrite test pixel ratio. - ensureFlutterViewEmbedderInitialized(); - - // The following parameters are hard-coded in Flutter's test embedder. Since - // we don't have an embedder yet this is the lowest-most layer we can put - // this stuff in. - window.debugOverrideDevicePixelRatio(devicePixelRatio); - window.webOnlyDebugPhysicalSizeOverride = - ui.Size(800 * devicePixelRatio, 600 * devicePixelRatio); - scheduleFrameCallback = () {}; - ui.debugEmulateFlutterTesterEnvironment = true; - - // Initialize platform once and reuse across all tests. - if (_platformInitializedFuture != null) { - return _platformInitializedFuture!; - } - return _platformInitializedFuture = - initializeEngine(assetManager: fakeAssetManager); -} diff --git a/lib/web_ui/test/common/test_initialization.dart b/lib/web_ui/test/common/test_initialization.dart new file mode 100644 index 0000000000000..9483be637a945 --- /dev/null +++ b/lib/web_ui/test/common/test_initialization.dart @@ -0,0 +1,57 @@ +// 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 'package:test/test.dart'; +import 'package:ui/src/engine.dart' as engine; +import 'package:ui/ui.dart' as ui; + +import 'fake_asset_manager.dart'; + +void setUpUnitTests() { + late final FakeAssetScope debugFontsScope; + setUpAll(() async { + // Force-initialize FlutterViewEmbedder so it doesn't overwrite test pixel ratio. + engine.ensureFlutterViewEmbedderInitialized(); + + // The following parameters are hard-coded in Flutter's test embedder. Since + // we don't have an embedder yet this is the lowest-most layer we can put + // this stuff in. + const double devicePixelRatio = 3.0; + engine.window.debugOverrideDevicePixelRatio(devicePixelRatio); + engine.window.webOnlyDebugPhysicalSizeOverride = + const ui.Size(800 * devicePixelRatio, 600 * devicePixelRatio); + engine.scheduleFrameCallback = () {}; + ui.debugEmulateFlutterTesterEnvironment = true; + + debugFontsScope = configureDebugFontsAssetScope(fakeAssetManager); + await engine.initializeEngine(assetManager: fakeAssetManager); + }); + + tearDownAll(() async { + fakeAssetManager.popAssetScope(debugFontsScope); + }); +} + +Future? _platformInitializedFuture; + +Future initializeTestFlutterViewEmbedder({double devicePixelRatio = 3.0}) { + // Force-initialize FlutterViewEmbedder so it doesn't overwrite test pixel ratio. + engine.ensureFlutterViewEmbedderInitialized(); + + // The following parameters are hard-coded in Flutter's test embedder. Since + // we don't have an embedder yet this is the lowest-most layer we can put + // this stuff in. + engine.window.debugOverrideDevicePixelRatio(devicePixelRatio); + engine.window.webOnlyDebugPhysicalSizeOverride = + ui.Size(800 * devicePixelRatio, 600 * devicePixelRatio); + engine.scheduleFrameCallback = () {}; + ui.debugEmulateFlutterTesterEnvironment = true; + + // Initialize platform once and reuse across all tests. + if (_platformInitializedFuture != null) { + return _platformInitializedFuture!; + } + return _platformInitializedFuture = + engine.initializeEngine(assetManager: fakeAssetManager); +} diff --git a/lib/web_ui/test/engine/clipboard_test.dart b/lib/web_ui/test/engine/clipboard_test.dart index 9ea91ec70ea95..baeca91df6c7e 100644 --- a/lib/web_ui/test/engine/clipboard_test.dart +++ b/lib/web_ui/test/engine/clipboard_test.dart @@ -9,14 +9,14 @@ import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; -import '../common/initialize_view_embedder.dart'; +import '../common/test_initialization.dart'; void main() { internalBootstrapBrowserTest(() => testMain); } Future testMain() async { - await initializeTestFlutterViewEmbedder(); + setUpUnitTests(); group('message handler', () { const String testText = 'test text'; diff --git a/lib/web_ui/test/engine/image/html_image_codec_test.dart b/lib/web_ui/test/engine/image/html_image_codec_test.dart index 27fd5cae701b6..1e0381ee0ec5f 100644 --- a/lib/web_ui/test/engine/image/html_image_codec_test.dart +++ b/lib/web_ui/test/engine/image/html_image_codec_test.dart @@ -10,14 +10,14 @@ import 'package:test/test.dart'; import 'package:ui/src/engine/html_image_codec.dart'; import 'package:ui/ui.dart' as ui; -import '../../common/initialize_view_embedder.dart'; +import '../../common/test_initialization.dart'; void main() { internalBootstrapBrowserTest(() => testMain); } Future testMain() async { - await initializeTestFlutterViewEmbedder(); + setUpUnitTests(); group('HtmCodec', () { test('supports raw images - RGBA8888', () async { final Completer completer = Completer(); diff --git a/lib/web_ui/test/engine/image_to_byte_data_test.dart b/lib/web_ui/test/engine/image_to_byte_data_test.dart index 556da379b2c15..306e50c560ec2 100644 --- a/lib/web_ui/test/engine/image_to_byte_data_test.dart +++ b/lib/web_ui/test/engine/image_to_byte_data_test.dart @@ -9,18 +9,14 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart'; -import '../common/fake_asset_manager.dart'; +import '../common/test_initialization.dart'; void main() { internalBootstrapBrowserTest(() => testMain); } Future testMain() async { - setUpTestFonts(); - - setUpAll(() async { - await initializeEngine(assetManager: fakeAssetManager); - }); + setUpUnitTests(); Future createTestImageByColor(Color color) async { final EnginePictureRecorder recorder = EnginePictureRecorder(); diff --git a/lib/web_ui/test/engine/recording_canvas_test.dart b/lib/web_ui/test/engine/recording_canvas_test.dart index 72c63f4143fa6..6571a374b4a8f 100644 --- a/lib/web_ui/test/engine/recording_canvas_test.dart +++ b/lib/web_ui/test/engine/recording_canvas_test.dart @@ -8,15 +8,14 @@ import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart'; import '../common/mock_engine_canvas.dart'; -import '../html/screenshot.dart'; +import '../common/test_initialization.dart'; void main() { internalBootstrapBrowserTest(() => testMain); } void testMain() { - debugEmulateFlutterTesterEnvironment = true; - setUpStableTestFonts(); + setUpUnitTests(); late RecordingCanvas underTest; late MockEngineCanvas mockCanvas; diff --git a/lib/web_ui/test/html/bitmap_canvas_golden_test.dart b/lib/web_ui/test/html/bitmap_canvas_golden_test.dart index 1852988f64029..ce5862358d65e 100644 --- a/lib/web_ui/test/html/bitmap_canvas_golden_test.dart +++ b/lib/web_ui/test/html/bitmap_canvas_golden_test.dart @@ -10,8 +10,8 @@ import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart'; import 'package:web_engine_tester/golden_tester.dart'; +import '../common/test_initialization.dart'; import 'paragraph/helper.dart'; -import 'screenshot.dart'; void main() { internalBootstrapBrowserTest(() => testMain); @@ -35,7 +35,7 @@ Future testMain() async { flutterViewEmbedder.glassPaneShadow.querySelector('flt-scene-host')!.append(testScene); } - setUpStableTestFonts(); + setUpUnitTests(); tearDown(() { flutterViewEmbedder.glassPaneShadow.querySelector('flt-scene')?.remove(); diff --git a/lib/web_ui/test/html/canvas_reuse_golden_test.dart b/lib/web_ui/test/html/canvas_reuse_golden_test.dart index 0757f0851e879..ded21b4350e42 100644 --- a/lib/web_ui/test/html/canvas_reuse_golden_test.dart +++ b/lib/web_ui/test/html/canvas_reuse_golden_test.dart @@ -9,6 +9,8 @@ import 'package:ui/ui.dart' hide TextStyle; import 'package:web_engine_tester/golden_tester.dart'; +import '../common/test_initialization.dart'; + void main() { internalBootstrapBrowserTest(() => testMain); } @@ -22,12 +24,7 @@ Future testMain() async { ..strokeWidth = 2.0 ..color = const Color(0xFFFF00FF); - setUp(() async { - debugEmulateFlutterTesterEnvironment = true; - await webOnlyInitializePlatform(); - await renderer.fontCollection.debugDownloadTestFonts(); - renderer.fontCollection.registerDownloadedFonts(); - }); + setUpUnitTests(); // Regression test for https://github.com/flutter/flutter/issues/51514 test("Canvas is reused and z-index doesn't leak across paints", () async { diff --git a/lib/web_ui/test/html/clip_op_golden_test.dart b/lib/web_ui/test/html/clip_op_golden_test.dart index 2d2b34535dc61..91ee1766c7b2f 100644 --- a/lib/web_ui/test/html/clip_op_golden_test.dart +++ b/lib/web_ui/test/html/clip_op_golden_test.dart @@ -7,6 +7,7 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart'; +import '../common/test_initialization.dart'; import 'paragraph/helper.dart'; import 'screenshot.dart'; @@ -15,7 +16,7 @@ void main() { } Future testMain() async { - setUpStableTestFonts(); + setUpUnitTests(); /// Regression test for https://github.com/flutter/flutter/issues/64734. test('Clips using difference', () async { diff --git a/lib/web_ui/test/html/compositing/backdrop_filter_golden_test.dart b/lib/web_ui/test/html/compositing/backdrop_filter_golden_test.dart index 41743319b73ef..6e38f7506a286 100644 --- a/lib/web_ui/test/html/compositing/backdrop_filter_golden_test.dart +++ b/lib/web_ui/test/html/compositing/backdrop_filter_golden_test.dart @@ -9,16 +9,14 @@ import 'package:ui/ui.dart'; import 'package:web_engine_tester/golden_tester.dart'; +import '../../common/test_initialization.dart'; + void main() { internalBootstrapBrowserTest(() => testMain); } Future testMain() async { - setUpAll(() async { - await webOnlyInitializePlatform(); - await renderer.fontCollection.debugDownloadTestFonts(); - renderer.fontCollection.registerDownloadedFonts(); - }); + setUpUnitTests(); setUp(() async { debugShowClipLayers = true; diff --git a/lib/web_ui/test/html/compositing/canvas_blend_golden_test.dart b/lib/web_ui/test/html/compositing/canvas_blend_golden_test.dart index b1851aa4e51b6..b7322ad9c171a 100644 --- a/lib/web_ui/test/html/compositing/canvas_blend_golden_test.dart +++ b/lib/web_ui/test/html/compositing/canvas_blend_golden_test.dart @@ -9,6 +9,7 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' hide TextStyle; +import '../../common/test_initialization.dart'; import '../screenshot.dart'; void main() { @@ -16,13 +17,7 @@ void main() { } Future testMain() async { - - setUpAll(() async { - debugEmulateFlutterTesterEnvironment = true; - await webOnlyInitializePlatform(); - await renderer.fontCollection.debugDownloadTestFonts(); - renderer.fontCollection.registerDownloadedFonts(); - }); + setUpUnitTests(); test('Blend circles with difference and color', () async { final RecordingCanvas rc = diff --git a/lib/web_ui/test/html/compositing/canvas_image_blend_mode_golden_test.dart b/lib/web_ui/test/html/compositing/canvas_image_blend_mode_golden_test.dart index 3b985102d4f4c..857d5a50952be 100644 --- a/lib/web_ui/test/html/compositing/canvas_image_blend_mode_golden_test.dart +++ b/lib/web_ui/test/html/compositing/canvas_image_blend_mode_golden_test.dart @@ -7,6 +7,7 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' hide TextStyle; +import '../../common/test_initialization.dart'; import '../screenshot.dart'; import '../testimage.dart'; @@ -17,12 +18,7 @@ void main() { SurfacePaint makePaint() => Paint() as SurfacePaint; Future testMain() async { - setUpAll(() async { - debugEmulateFlutterTesterEnvironment = true; - await webOnlyInitializePlatform(); - await renderer.fontCollection.debugDownloadTestFonts(); - renderer.fontCollection.registerDownloadedFonts(); - }); + setUpUnitTests(); const Color red = Color(0xFFFF0000); const Color green = Color(0xFF00FF00); diff --git a/lib/web_ui/test/html/compositing/canvas_mask_filter_golden_test.dart b/lib/web_ui/test/html/compositing/canvas_mask_filter_golden_test.dart index 03e8b8d2ccf5b..844890a03af2a 100644 --- a/lib/web_ui/test/html/compositing/canvas_mask_filter_golden_test.dart +++ b/lib/web_ui/test/html/compositing/canvas_mask_filter_golden_test.dart @@ -10,6 +10,7 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; +import '../../common/test_initialization.dart'; import '../screenshot.dart'; void main() { @@ -17,12 +18,7 @@ void main() { } Future testMain() async { - setUpAll(() async { - ui.debugEmulateFlutterTesterEnvironment = true; - await ui.webOnlyInitializePlatform(); - await renderer.fontCollection.debugDownloadTestFonts(); - renderer.fontCollection.registerDownloadedFonts(); - }); + setUpUnitTests(); tearDown(() { ContextStateHandle.debugEmulateWebKitMaskFilter = false; diff --git a/lib/web_ui/test/html/compositing/color_filter_golden_test.dart b/lib/web_ui/test/html/compositing/color_filter_golden_test.dart index 3da07d2fc5ccc..23caec7dc29af 100644 --- a/lib/web_ui/test/html/compositing/color_filter_golden_test.dart +++ b/lib/web_ui/test/html/compositing/color_filter_golden_test.dart @@ -11,6 +11,8 @@ import 'package:ui/ui.dart'; import 'package:web_engine_tester/golden_tester.dart'; +import '../../common/test_initialization.dart'; + const Rect region = Rect.fromLTWH(0, 0, 500, 500); void main() { @@ -18,11 +20,7 @@ void main() { } Future testMain() async { - setUpAll(() async { - await webOnlyInitializePlatform(); - await renderer.fontCollection.debugDownloadTestFonts(); - renderer.fontCollection.registerDownloadedFonts(); - }); + setUpUnitTests(); setUp(() async { debugShowClipLayers = true; diff --git a/lib/web_ui/test/html/compositing/compositing_golden_test.dart b/lib/web_ui/test/html/compositing/compositing_golden_test.dart index 451c468a2222b..9c475f86d6b30 100644 --- a/lib/web_ui/test/html/compositing/compositing_golden_test.dart +++ b/lib/web_ui/test/html/compositing/compositing_golden_test.dart @@ -11,6 +11,7 @@ import 'package:ui/ui.dart' as ui; import 'package:web_engine_tester/golden_tester.dart'; import '../../common/matchers.dart'; +import '../../common/test_initialization.dart'; const ui.Rect region = ui.Rect.fromLTWH(0, 0, 500, 100); @@ -19,11 +20,7 @@ void main() { } Future testMain() async { - setUpAll(() async { - await ui.webOnlyInitializePlatform(); - await renderer.fontCollection.debugDownloadTestFonts(); - renderer.fontCollection.registerDownloadedFonts(); - }); + setUpUnitTests(); setUp(() async { // To debug test failures uncomment the following to visualize clipping diff --git a/lib/web_ui/test/html/compositing/dom_mask_filter_golden_test.dart b/lib/web_ui/test/html/compositing/dom_mask_filter_golden_test.dart index bf7e63d20fb0e..a651f84e9d06a 100644 --- a/lib/web_ui/test/html/compositing/dom_mask_filter_golden_test.dart +++ b/lib/web_ui/test/html/compositing/dom_mask_filter_golden_test.dart @@ -6,6 +6,7 @@ import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' hide TextStyle; +import '../../common/test_initialization.dart'; import '../screenshot.dart'; void main() { @@ -13,12 +14,7 @@ void main() { } Future testMain() async { - setUp(() async { - debugEmulateFlutterTesterEnvironment = true; - await webOnlyInitializePlatform(); - await renderer.fontCollection.debugDownloadTestFonts(); - renderer.fontCollection.registerDownloadedFonts(); - }); + setUpUnitTests(); test('Should blur rectangles based on sigma.', () async { final RecordingCanvas rc = diff --git a/lib/web_ui/test/html/drawing/canvas_draw_color_golden_test.dart b/lib/web_ui/test/html/drawing/canvas_draw_color_golden_test.dart index 8b26b7342f6c1..0d5b82916f292 100644 --- a/lib/web_ui/test/html/drawing/canvas_draw_color_golden_test.dart +++ b/lib/web_ui/test/html/drawing/canvas_draw_color_golden_test.dart @@ -7,6 +7,7 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart'; +import '../../common/test_initialization.dart'; import '../screenshot.dart'; void main() { @@ -14,12 +15,11 @@ void main() { } Future testMain() async { + setUpUnitTests(); + setUp(() async { debugShowClipLayers = true; SurfaceSceneBuilder.debugForgetFrameScene(); - await webOnlyInitializePlatform(); - await renderer.fontCollection.debugDownloadTestFonts(); - renderer.fontCollection.registerDownloadedFonts(); }); tearDown(() { diff --git a/lib/web_ui/test/html/drawing/canvas_draw_image_golden_test.dart b/lib/web_ui/test/html/drawing/canvas_draw_image_golden_test.dart index ad86f7ad77b9e..647e2f221af6f 100644 --- a/lib/web_ui/test/html/drawing/canvas_draw_image_golden_test.dart +++ b/lib/web_ui/test/html/drawing/canvas_draw_image_golden_test.dart @@ -14,6 +14,7 @@ import 'package:ui/ui.dart'; import 'package:web_engine_tester/golden_tester.dart'; +import '../../common/test_initialization.dart'; import '../screenshot.dart'; void main() { @@ -21,12 +22,7 @@ void main() { } Future testMain() async { - - setUp(() async { - debugEmulateFlutterTesterEnvironment = true; - }); - - setUpStableTestFonts(); + setUpUnitTests(); test('Paints image', () async { final RecordingCanvas rc = diff --git a/lib/web_ui/test/html/drawing/canvas_draw_picture_golden_test.dart b/lib/web_ui/test/html/drawing/canvas_draw_picture_golden_test.dart index a2cfffb29e7b2..36d30c288ac89 100644 --- a/lib/web_ui/test/html/drawing/canvas_draw_picture_golden_test.dart +++ b/lib/web_ui/test/html/drawing/canvas_draw_picture_golden_test.dart @@ -7,6 +7,7 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart'; +import '../../common/test_initialization.dart'; import '../screenshot.dart'; const Rect region = Rect.fromLTWH(0, 0, 500, 100); @@ -18,11 +19,10 @@ void main() { SurfacePaint makePaint() => Paint() as SurfacePaint; Future testMain() async { + setUpUnitTests(); + setUpAll(() async { debugShowClipLayers = true; - await webOnlyInitializePlatform(); - await renderer.fontCollection.debugDownloadTestFonts(); - renderer.fontCollection.registerDownloadedFonts(); }); setUp(() async { diff --git a/lib/web_ui/test/html/drawing/draw_vertices_golden_test.dart b/lib/web_ui/test/html/drawing/draw_vertices_golden_test.dart index 4790ff9bd4e43..2dd36fb5e1279 100644 --- a/lib/web_ui/test/html/drawing/draw_vertices_golden_test.dart +++ b/lib/web_ui/test/html/drawing/draw_vertices_golden_test.dart @@ -11,6 +11,7 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' hide ImageShader, TextStyle; +import '../../common/test_initialization.dart'; import '../screenshot.dart'; void main() { @@ -22,12 +23,7 @@ Future testMain() async { const double screenHeight = 800.0; const Rect screenRect = Rect.fromLTWH(0, 0, screenWidth, screenHeight); - setUpAll(() async { - debugEmulateFlutterTesterEnvironment = true; - await webOnlyInitializePlatform(); - await renderer.fontCollection.debugDownloadTestFonts(); - renderer.fontCollection.registerDownloadedFonts(); - }); + setUpUnitTests(); setUp(() { GlContextCache.dispose(); diff --git a/lib/web_ui/test/html/paragraph/bidi_golden_test.dart b/lib/web_ui/test/html/paragraph/bidi_golden_test.dart index 8f1c6f2060568..378aba443a37f 100644 --- a/lib/web_ui/test/html/paragraph/bidi_golden_test.dart +++ b/lib/web_ui/test/html/paragraph/bidi_golden_test.dart @@ -7,7 +7,7 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' hide window; -import '../screenshot.dart'; +import '../../common/test_initialization.dart'; import 'helper.dart'; const String _rtlWord1 = 'واحد'; @@ -18,7 +18,7 @@ void main() { } Future testMain() async { - setUpStableTestFonts(); + setUpUnitTests(); void paintBasicBidiStartingWithLtr( EngineCanvas canvas, diff --git a/lib/web_ui/test/html/paragraph/general_golden_test.dart b/lib/web_ui/test/html/paragraph/general_golden_test.dart index 82d2e4da230f0..c5ca7f71fba16 100644 --- a/lib/web_ui/test/html/paragraph/general_golden_test.dart +++ b/lib/web_ui/test/html/paragraph/general_golden_test.dart @@ -10,7 +10,7 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' hide window; -import '../screenshot.dart'; +import '../../common/test_initialization.dart'; import 'helper.dart'; const Rect bounds = Rect.fromLTWH(0, 0, 800, 600); @@ -20,7 +20,7 @@ void main() { } Future testMain() async { - setUpStableTestFonts(); + setUpUnitTests(); test('paints spans and lines correctly', () { final BitmapCanvas canvas = BitmapCanvas(bounds, RenderStrategy()); diff --git a/lib/web_ui/test/html/paragraph/justify_golden_test.dart b/lib/web_ui/test/html/paragraph/justify_golden_test.dart index 00a0033df3b0a..414ca6436f6ea 100644 --- a/lib/web_ui/test/html/paragraph/justify_golden_test.dart +++ b/lib/web_ui/test/html/paragraph/justify_golden_test.dart @@ -9,7 +9,7 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' hide window; -import '../screenshot.dart'; +import '../../common/test_initialization.dart'; import 'helper.dart'; void main() { @@ -17,7 +17,7 @@ void main() { } Future testMain() async { - setUpStableTestFonts(); + setUpUnitTests(); void testJustifyWithMultipleSpans(EngineCanvas canvas) { void build(CanvasParagraphBuilder builder) { diff --git a/lib/web_ui/test/html/paragraph/overflow_golden_test.dart b/lib/web_ui/test/html/paragraph/overflow_golden_test.dart index eebfde0c1489e..00667adcb6893 100644 --- a/lib/web_ui/test/html/paragraph/overflow_golden_test.dart +++ b/lib/web_ui/test/html/paragraph/overflow_golden_test.dart @@ -9,7 +9,7 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' hide window; -import '../screenshot.dart'; +import '../../common/test_initialization.dart'; import 'helper.dart'; void main() { @@ -17,7 +17,7 @@ void main() { } Future testMain() async { - setUpStableTestFonts(); + setUpUnitTests(); void testEllipsis(EngineCanvas canvas) { Offset offset = Offset.zero; diff --git a/lib/web_ui/test/html/paragraph/placeholders_golden_test.dart b/lib/web_ui/test/html/paragraph/placeholders_golden_test.dart index 7f90cde8a3243..18f483e2b10e9 100644 --- a/lib/web_ui/test/html/paragraph/placeholders_golden_test.dart +++ b/lib/web_ui/test/html/paragraph/placeholders_golden_test.dart @@ -9,7 +9,7 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' hide window; -import '../screenshot.dart'; +import '../../common/test_initialization.dart'; import 'helper.dart'; const Rect bounds = Rect.fromLTWH(0, 0, 800, 600); @@ -19,7 +19,7 @@ void main() { } Future testMain() async { - setUpStableTestFonts(); + setUpUnitTests(); test('draws paragraphs with placeholders', () { final BitmapCanvas canvas = BitmapCanvas(bounds, RenderStrategy()); diff --git a/lib/web_ui/test/html/paragraph/shadows_golden_test.dart b/lib/web_ui/test/html/paragraph/shadows_golden_test.dart index 3c6f30fec8fcd..79c0eb85cd4b5 100644 --- a/lib/web_ui/test/html/paragraph/shadows_golden_test.dart +++ b/lib/web_ui/test/html/paragraph/shadows_golden_test.dart @@ -7,7 +7,7 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' hide window; -import '../screenshot.dart'; +import '../../common/test_initialization.dart'; import 'helper.dart'; const Rect bounds = Rect.fromLTWH(0, 0, 800, 600); @@ -17,7 +17,7 @@ void main() { } Future testMain() async { - setUpStableTestFonts(); + setUpUnitTests(); test('paints multiple shadows', () { final BitmapCanvas canvas = BitmapCanvas(bounds, RenderStrategy()); diff --git a/lib/web_ui/test/html/paragraph/text_multiline_clipping_golden_test.dart b/lib/web_ui/test/html/paragraph/text_multiline_clipping_golden_test.dart index a4164b2dd6b35..a7a164ffaf5c5 100644 --- a/lib/web_ui/test/html/paragraph/text_multiline_clipping_golden_test.dart +++ b/lib/web_ui/test/html/paragraph/text_multiline_clipping_golden_test.dart @@ -8,7 +8,7 @@ import 'package:test/bootstrap/browser.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart'; -import '../screenshot.dart'; +import '../../common/test_initialization.dart'; import 'text_scuba.dart'; typedef PaintTest = void Function(RecordingCanvas recordingCanvas); @@ -23,7 +23,7 @@ Future testMain() async { viewportSize: const Size(600, 600), ); - setUpStableTestFonts(); + setUpUnitTests(); void paintTest(EngineCanvas canvas, PaintTest painter) { const Rect screenRect = Rect.fromLTWH(0, 0, 600, 600); diff --git a/lib/web_ui/test/html/paragraph/text_overflow_golden_test.dart b/lib/web_ui/test/html/paragraph/text_overflow_golden_test.dart index a97bce79940f6..50b413c3cdd0f 100644 --- a/lib/web_ui/test/html/paragraph/text_overflow_golden_test.dart +++ b/lib/web_ui/test/html/paragraph/text_overflow_golden_test.dart @@ -8,7 +8,7 @@ import 'package:test/bootstrap/browser.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' hide window; -import '../screenshot.dart'; +import '../../common/test_initialization.dart'; import 'text_scuba.dart'; const String threeLines = 'First\nSecond\nThird'; @@ -25,7 +25,7 @@ Future testMain() async { viewportSize: const Size(800, 800), ); - setUpStableTestFonts(); + setUpUnitTests(); testEachCanvas('maxLines clipping', (EngineCanvas canvas) { Offset offset = Offset.zero; diff --git a/lib/web_ui/test/html/paragraph/text_placeholders_golden_test.dart b/lib/web_ui/test/html/paragraph/text_placeholders_golden_test.dart index 4474bba0b9f33..f3f0328f4bba6 100644 --- a/lib/web_ui/test/html/paragraph/text_placeholders_golden_test.dart +++ b/lib/web_ui/test/html/paragraph/text_placeholders_golden_test.dart @@ -6,7 +6,7 @@ import 'package:test/bootstrap/browser.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart'; -import '../screenshot.dart'; +import '../../common/test_initialization.dart'; import 'helper.dart'; import 'text_scuba.dart'; @@ -19,8 +19,7 @@ Future testMain() async { viewportSize: const Size(600, 600), ); - - setUpStableTestFonts(); + setUpUnitTests(); testEachCanvas('draws paragraphs with placeholders', (EngineCanvas canvas) { const Rect screenRect = Rect.fromLTWH(0, 0, 600, 600); diff --git a/lib/web_ui/test/html/path_metrics_golden_test.dart b/lib/web_ui/test/html/path_metrics_golden_test.dart index 4a3ea96f7288d..29a1d0dd60238 100644 --- a/lib/web_ui/test/html/path_metrics_golden_test.dart +++ b/lib/web_ui/test/html/path_metrics_golden_test.dart @@ -8,6 +8,7 @@ import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' hide TextStyle; import '../common/matchers.dart'; +import '../common/test_initialization.dart'; import 'screenshot.dart'; void main() { @@ -22,12 +23,7 @@ Future testMain() async { const Color redAccentColor = Color(0xFFFF1744); const double kDashLength = 5.0; - setUpAll(() async { - debugEmulateFlutterTesterEnvironment = true; - await webOnlyInitializePlatform(); - await renderer.fontCollection.debugDownloadTestFonts(); - renderer.fontCollection.registerDownloadedFonts(); - }); + setUpUnitTests(); test('Should calculate tangent on line', () async { final Path path = Path(); diff --git a/lib/web_ui/test/html/path_transform_golden_test.dart b/lib/web_ui/test/html/path_transform_golden_test.dart index cb5b398169540..820e5eae40f3e 100644 --- a/lib/web_ui/test/html/path_transform_golden_test.dart +++ b/lib/web_ui/test/html/path_transform_golden_test.dart @@ -9,6 +9,7 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' hide TextStyle; +import '../common/test_initialization.dart'; import 'screenshot.dart'; void main() { @@ -20,12 +21,7 @@ Future testMain() async { const double screenHeight = 800.0; const Rect screenRect = Rect.fromLTWH(0, 0, screenWidth, screenHeight); - setUpAll(() async { - debugEmulateFlutterTesterEnvironment = true; - await webOnlyInitializePlatform(); - await renderer.fontCollection.debugDownloadTestFonts(); - renderer.fontCollection.registerDownloadedFonts(); - }); + setUpUnitTests(); test('Should draw transformed line.', () async { final RecordingCanvas rc = diff --git a/lib/web_ui/test/html/recording_canvas_golden_test.dart b/lib/web_ui/test/html/recording_canvas_golden_test.dart index 3a32e02830ed7..12675cce4b90c 100644 --- a/lib/web_ui/test/html/recording_canvas_golden_test.dart +++ b/lib/web_ui/test/html/recording_canvas_golden_test.dart @@ -12,18 +12,14 @@ import 'package:ui/ui.dart' hide TextStyle; import 'package:web_engine_tester/golden_tester.dart'; import '../common/matchers.dart'; -import 'screenshot.dart'; +import '../common/test_initialization.dart'; void main() { internalBootstrapBrowserTest(() => testMain); } Future testMain() async { - setUpAll(() async { - debugEmulateFlutterTesterEnvironment = true; - }); - - setUpStableTestFonts(); + setUpUnitTests(); const double screenWidth = 600.0; const double screenHeight = 800.0; diff --git a/lib/web_ui/test/html/screenshot.dart b/lib/web_ui/test/html/screenshot.dart index 3e2226ae68803..445744c51cfb4 100644 --- a/lib/web_ui/test/html/screenshot.dart +++ b/lib/web_ui/test/html/screenshot.dart @@ -3,7 +3,6 @@ // found in the LICENSE file. import 'dart:async'; -import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; import 'package:web_engine_tester/golden_tester.dart'; @@ -70,14 +69,3 @@ Future sceneScreenshot(SurfaceSceneBuilder sceneBuilder, String fileName, sceneElement?.remove(); } } - - -/// Configures the test to use bundled Roboto and Ahem fonts to avoid golden -/// screenshot differences due to differences in the preinstalled system fonts. -void setUpStableTestFonts() { - setUpAll(() async { - await ui.webOnlyInitializePlatform(); - await renderer.fontCollection.debugDownloadTestFonts(); - renderer.fontCollection.registerDownloadedFonts(); - }); -} diff --git a/lib/web_ui/test/html/shaders/gradient_golden_test.dart b/lib/web_ui/test/html/shaders/gradient_golden_test.dart index 5aebc78ef0070..8dfa8fc66503f 100644 --- a/lib/web_ui/test/html/shaders/gradient_golden_test.dart +++ b/lib/web_ui/test/html/shaders/gradient_golden_test.dart @@ -10,6 +10,7 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart'; +import '../../common/test_initialization.dart'; import '../screenshot.dart'; // TODO(yjbanov): unskip Firefox tests when Firefox implements WebGL in headless mode. @@ -25,11 +26,7 @@ Future testMain() async { const Rect screenRect = Rect.fromLTWH(0, 0, screenWidth, screenHeight); const Rect region = Rect.fromLTWH(0, 0, 500, 240); - setUp(() async { - debugEmulateFlutterTesterEnvironment = true; - }); - - setUpStableTestFonts(); + setUpUnitTests(); test('Paints sweep gradient rectangles', () async { final RecordingCanvas canvas = diff --git a/lib/web_ui/test/html/shaders/image_shader_golden_test.dart b/lib/web_ui/test/html/shaders/image_shader_golden_test.dart index 405250062d462..018276b309bad 100644 --- a/lib/web_ui/test/html/shaders/image_shader_golden_test.dart +++ b/lib/web_ui/test/html/shaders/image_shader_golden_test.dart @@ -9,6 +9,7 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' hide TextStyle; +import '../../common/test_initialization.dart'; import '../screenshot.dart'; // TODO(yjbanov): unskip Firefox tests when Firefox implements WebGL in headless mode. @@ -24,12 +25,7 @@ Future testMain() async { const Rect screenRect = Rect.fromLTWH(0, 0, screenWidth, screenHeight); final HtmlImage testImage = createTestImage(); - setUpAll(() async { - debugEmulateFlutterTesterEnvironment = true; - await webOnlyInitializePlatform(); - await renderer.fontCollection.debugDownloadTestFonts(); - renderer.fontCollection.registerDownloadedFonts(); - }); + setUpUnitTests(); void drawShapes(RecordingCanvas rc, SurfacePaint paint, Rect shaderRect) { /// Rect. diff --git a/lib/web_ui/test/html/shaders/linear_gradient_golden_test.dart b/lib/web_ui/test/html/shaders/linear_gradient_golden_test.dart index 742067e4914e0..876327a946099 100644 --- a/lib/web_ui/test/html/shaders/linear_gradient_golden_test.dart +++ b/lib/web_ui/test/html/shaders/linear_gradient_golden_test.dart @@ -8,6 +8,7 @@ import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' hide TextStyle; +import '../../common/test_initialization.dart'; import '../screenshot.dart'; // TODO(yjbanov): unskip Firefox tests when Firefox implements WebGL in headless mode. @@ -18,12 +19,7 @@ void main() { } Future testMain() async { - setUpAll(() async { - debugEmulateFlutterTesterEnvironment = true; - await webOnlyInitializePlatform(); - await renderer.fontCollection.debugDownloadTestFonts(); - renderer.fontCollection.registerDownloadedFonts(); - }); + setUpUnitTests(); test('Should draw linear gradient using rectangle.', () async { final RecordingCanvas rc = diff --git a/lib/web_ui/test/html/shaders/radial_gradient_golden_test.dart b/lib/web_ui/test/html/shaders/radial_gradient_golden_test.dart index 51bfab70965a1..c736ba98fffa2 100644 --- a/lib/web_ui/test/html/shaders/radial_gradient_golden_test.dart +++ b/lib/web_ui/test/html/shaders/radial_gradient_golden_test.dart @@ -6,6 +6,7 @@ import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' hide TextStyle; +import '../../common/test_initialization.dart'; import '../screenshot.dart'; void main() { @@ -13,13 +14,7 @@ void main() { } Future testMain() async { - - setUpAll(() async { - debugEmulateFlutterTesterEnvironment = true; - await webOnlyInitializePlatform(); - await renderer.fontCollection.debugDownloadTestFonts(); - renderer.fontCollection.registerDownloadedFonts(); - }); + setUpUnitTests(); Future testGradient(String fileName, Shader shader, {Rect paintRect = const Rect.fromLTRB(50, 50, 300, 300), diff --git a/lib/web_ui/test/html/shaders/shader_mask_golden_test.dart b/lib/web_ui/test/html/shaders/shader_mask_golden_test.dart index 6c11494b9f8f0..4d06883f3d01b 100644 --- a/lib/web_ui/test/html/shaders/shader_mask_golden_test.dart +++ b/lib/web_ui/test/html/shaders/shader_mask_golden_test.dart @@ -10,6 +10,8 @@ import 'package:ui/ui.dart'; import 'package:web_engine_tester/golden_tester.dart'; +import '../../common/test_initialization.dart'; + /// To debug compositing failures on browsers, set this flag to true and run /// flutter run -d chrome --web-renderer=html /// test/golden_tests/engine/shader_mask_golden_test.dart --profile @@ -29,9 +31,10 @@ Future main() async { // https://github.com/flutter/flutter/issues/86623 Future testMain() async { + setUpUnitTests(); + setUpAll(() async { debugShowClipLayers = true; - await webOnlyInitializePlatform(); }); setUp(() async { @@ -41,8 +44,6 @@ Future testMain() async { scene.remove(); } initWebGl(); - await renderer.fontCollection.debugDownloadTestFonts(); - renderer.fontCollection.registerDownloadedFonts(); }); /// Should render the picture unmodified. diff --git a/lib/web_ui/test/html/shadow_golden_test.dart b/lib/web_ui/test/html/shadow_golden_test.dart index 4ca020c030b52..e0041b0cb0872 100644 --- a/lib/web_ui/test/html/shadow_golden_test.dart +++ b/lib/web_ui/test/html/shadow_golden_test.dart @@ -9,7 +9,7 @@ import 'package:ui/ui.dart'; import 'package:web_engine_tester/golden_tester.dart'; -import 'screenshot.dart'; +import '../common/test_initialization.dart'; const Color _kShadowColor = Color.fromARGB(255, 0, 0, 0); @@ -22,7 +22,7 @@ Future testMain() async { late SurfaceSceneBuilder builder; - setUpStableTestFonts(); + setUpUnitTests(); setUp(() { builder = SurfaceSceneBuilder(); diff --git a/lib/web_ui/test/html/text/canvas_paragraph_builder_test.dart b/lib/web_ui/test/html/text/canvas_paragraph_builder_test.dart index 0d1e8bbc1e873..7d51f2b4964f6 100644 --- a/lib/web_ui/test/html/text/canvas_paragraph_builder_test.dart +++ b/lib/web_ui/test/html/text/canvas_paragraph_builder_test.dart @@ -7,7 +7,7 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart'; -import '../../common/initialize_view_embedder.dart'; +import '../../common/test_initialization.dart'; import '../paragraph/helper.dart'; /// Some text measurements are sensitive to browser implementations. Position @@ -32,7 +32,7 @@ void main() { } Future testMain() async { - await initializeTestFlutterViewEmbedder(); + setUpUnitTests(); test('empty paragraph', () { final CanvasParagraph paragraph1 = rich( diff --git a/lib/web_ui/test/html/text/canvas_paragraph_test.dart b/lib/web_ui/test/html/text/canvas_paragraph_test.dart index f4e4096c87ff2..0133174fa2b41 100644 --- a/lib/web_ui/test/html/text/canvas_paragraph_test.dart +++ b/lib/web_ui/test/html/text/canvas_paragraph_test.dart @@ -7,7 +7,7 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; -import '../../common/initialize_view_embedder.dart'; +import '../../common/test_initialization.dart'; import '../paragraph/helper.dart'; void main() { @@ -15,7 +15,7 @@ void main() { } Future testMain() async { - await initializeTestFlutterViewEmbedder(); + setUpUnitTests() group('$CanvasParagraph.getBoxesForRange', () { test('return empty list for invalid ranges', () { diff --git a/lib/web_ui/test/html/text/font_collection_test.dart b/lib/web_ui/test/html/text/font_collection_test.dart index caf27b9c722cf..96ec11596d19c 100644 --- a/lib/web_ui/test/html/text/font_collection_test.dart +++ b/lib/web_ui/test/html/text/font_collection_test.dart @@ -7,32 +7,43 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; +import '../../common/fake_asset_manager.dart'; +import '../../common/test_initialization.dart'; + void main() { internalBootstrapBrowserTest(() => testMain); } void testMain() { - group('$FontManager', () { - late FontManager fontManager; + group('$HtmlFontCollection', () { + setUpUnitTests(); + const String testFontUrl = '/assets/fonts/ahem.ttf'; + late FakeAssetScope testScope; setUp(() { - fontManager = FontManager(); + testScope = fakeAssetManager.pushAssetScope(); + testScope.setAssetPassthrough(testFontUrl); + + // Clear the fonts before the test begins to wipe out the fonts from the + // test initialization. + domDocument.fonts!.clear(); }); tearDown(() { - domDocument.fonts!.clear(); + fakeAssetManager.popAssetScope(testScope); }); group('regular special characters', () { test('Register Asset with no special characters', () async { const String testFontFamily = 'Ahem'; final List fontFamilyList = []; - - fontManager.downloadAsset( - testFontFamily, 'url($testFontUrl)', const {}); - await fontManager.downloadAllFonts(); - fontManager.registerDownloadedFonts(); + final HtmlFontCollection collection = HtmlFontCollection(); + await collection.loadAssetFonts(FontManifest([ + FontFamily(testFontFamily, [ + FontAsset('url($testFontUrl)', {}) + ]) + ])); domDocument.fonts! .forEach((DomFontFace f, DomFontFace f2, DomFontFaceSet s) { fontFamilyList.add(f.family!); @@ -46,10 +57,12 @@ void testMain() { const String testFontFamily = 'Ahem ahem ahem'; final List fontFamilyList = []; - fontManager.downloadAsset( - testFontFamily, 'url($testFontUrl)', const {}); - await fontManager.downloadAllFonts(); - fontManager.registerDownloadedFonts(); + final HtmlFontCollection collection = HtmlFontCollection(); + await collection.loadAssetFonts(FontManifest([ + FontFamily(testFontFamily, [ + FontAsset('url($testFontUrl)', {}) + ]) + ])); domDocument.fonts! .forEach((DomFontFace f, DomFontFace f2, DomFontFaceSet s) { fontFamilyList.add(f.family!); @@ -65,10 +78,12 @@ void testMain() { const String testFontFamily = 'AhEm'; final List fontFamilyList = []; - fontManager.downloadAsset( - testFontFamily, 'url($testFontUrl)', const {}); - await fontManager.downloadAllFonts(); - fontManager.registerDownloadedFonts(); + final HtmlFontCollection collection = HtmlFontCollection(); + await collection.loadAssetFonts(FontManifest([ + FontFamily(testFontFamily, [ + FontAsset('url($testFontUrl)', {}) + ]) + ])); domDocument.fonts! .forEach((DomFontFace f, DomFontFace f2, DomFontFaceSet s) { fontFamilyList.add(f.family!); @@ -81,13 +96,15 @@ void testMain() { test('Register Asset with descriptor', () async { const String testFontFamily = 'Ahem'; final List fontFamilyList = []; + final HtmlFontCollection collection = HtmlFontCollection(); + await collection.loadAssetFonts(FontManifest([ + FontFamily(testFontFamily, [ + FontAsset('url($testFontUrl)', { + 'weight': 'bold' + }) + ]) + ])); - fontManager.downloadAsset( - testFontFamily, 'url($testFontUrl)', const { - 'weight': 'bold', - }); - await fontManager.downloadAllFonts(); - fontManager.registerDownloadedFonts(); domDocument.fonts! .forEach((DomFontFace f, DomFontFace f2, DomFontFaceSet s) { expect(f.weight, 'bold'); @@ -105,10 +122,12 @@ void testMain() { const String testFontFamily = '/Ahem'; final List fontFamilyList = []; - fontManager.downloadAsset( - testFontFamily, 'url($testFontUrl)', const {}); - await fontManager.downloadAllFonts(); - fontManager.registerDownloadedFonts(); + final HtmlFontCollection collection = HtmlFontCollection(); + await collection.loadAssetFonts(FontManifest([ + FontFamily(testFontFamily, [ + FontAsset('url($testFontUrl)', {}) + ]) + ])); domDocument.fonts! .forEach((DomFontFace f, DomFontFace f2, DomFontFaceSet s) { fontFamilyList.add(f.family!); @@ -130,10 +149,12 @@ void testMain() { const String testFontFamily = 'Ahem!!ahem'; final List fontFamilyList = []; - fontManager.downloadAsset( - testFontFamily, 'url($testFontUrl)', const {}); - await fontManager.downloadAllFonts(); - fontManager.registerDownloadedFonts(); + final HtmlFontCollection collection = HtmlFontCollection(); + await collection.loadAssetFonts(FontManifest([ + FontFamily(testFontFamily, [ + FontAsset('url($testFontUrl)', {}) + ]) + ])); domDocument.fonts! .forEach((DomFontFace f, DomFontFace f2, DomFontFaceSet s) { fontFamilyList.add(f.family!); @@ -155,10 +176,12 @@ void testMain() { const String testFontFamily = 'Ahem ,ahem'; final List fontFamilyList = []; - fontManager.downloadAsset( - testFontFamily, 'url($testFontUrl)', const {}); - await fontManager.downloadAllFonts(); - fontManager.registerDownloadedFonts(); + final HtmlFontCollection collection = HtmlFontCollection(); + await collection.loadAssetFonts(FontManifest([ + FontFamily(testFontFamily, [ + FontAsset('url($testFontUrl)', {}) + ]) + ])); domDocument.fonts! .forEach((DomFontFace f, DomFontFace f2, DomFontFaceSet s) { fontFamilyList.add(f.family!); @@ -181,10 +204,12 @@ void testMain() { const String testFontFamily = 'Ahem 1998'; final List fontFamilyList = []; - fontManager.downloadAsset( - testFontFamily, 'url($testFontUrl)', const {}); - await fontManager.downloadAllFonts(); - fontManager.registerDownloadedFonts(); + final HtmlFontCollection collection = HtmlFontCollection(); + await collection.loadAssetFonts(FontManifest([ + FontFamily(testFontFamily, [ + FontAsset('url($testFontUrl)', {}) + ]) + ])); domDocument.fonts! .forEach((DomFontFace f, DomFontFace f2, DomFontFaceSet s) { fontFamilyList.add(f.family!); diff --git a/lib/web_ui/test/html/text/font_loading_test.dart b/lib/web_ui/test/html/text/font_loading_test.dart index c7686bd1a7beb..608d78dbb2b43 100644 --- a/lib/web_ui/test/html/text/font_loading_test.dart +++ b/lib/web_ui/test/html/text/font_loading_test.dart @@ -11,14 +11,14 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; -import '../../common/initialize_view_embedder.dart'; +import '../../common/test_initialization.dart'; void main() { internalBootstrapBrowserTest(() => testMain); } Future testMain() async { - await initializeTestFlutterViewEmbedder(); + setUpUnitTests(); group('loadFontFromList', () { const String testFontUrl = '/assets/fonts/ahem.ttf'; @@ -26,10 +26,10 @@ Future testMain() async { domDocument.fonts!.clear(); }); - test('surfaces error from invalid font buffer', () async { + test('returns normally from invalid font buffer', () async { await expectLater( ui.loadFontFromList(Uint8List(0), fontFamily: 'test-font'), - throwsA(const TypeMatcher())); + returnsNormally); }, // TODO(hterkelsen): https://github.com/flutter/flutter/issues/56702 skip: browserEngine == BrowserEngine.webkit); diff --git a/lib/web_ui/test/html/text/layout_service_plain_test.dart b/lib/web_ui/test/html/text/layout_service_plain_test.dart index 961bf8e309965..d08d88b15e493 100644 --- a/lib/web_ui/test/html/text/layout_service_plain_test.dart +++ b/lib/web_ui/test/html/text/layout_service_plain_test.dart @@ -7,7 +7,7 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; -import '../../common/initialize_view_embedder.dart'; +import '../../common/test_initialization.dart'; import '../paragraph/helper.dart'; import 'layout_service_helper.dart'; @@ -18,7 +18,7 @@ void main() { } Future testMain() async { - await initializeTestFlutterViewEmbedder(); + setUpUnitTests(); test('no text', () { final CanvasParagraph paragraph = CanvasParagraphBuilder(ahemStyle).build(); diff --git a/lib/web_ui/test/html/text/layout_service_rich_test.dart b/lib/web_ui/test/html/text/layout_service_rich_test.dart index b714c90a3bb4e..2d6173caa0ad1 100644 --- a/lib/web_ui/test/html/text/layout_service_rich_test.dart +++ b/lib/web_ui/test/html/text/layout_service_rich_test.dart @@ -8,7 +8,7 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; -import '../../common/initialize_view_embedder.dart'; +import '../../common/test_initialization.dart'; import '../paragraph/helper.dart'; import 'layout_service_helper.dart'; @@ -17,7 +17,7 @@ void main() { } Future testMain() async { - await initializeTestFlutterViewEmbedder(); + setUpUnitTests(); test('does not crash on empty spans', () { final CanvasParagraph paragraph = rich(ahemStyle, (CanvasParagraphBuilder builder) { diff --git a/lib/web_ui/test/html/text_test.dart b/lib/web_ui/test/html/text_test.dart index d6ea701421779..72a624a6335c0 100644 --- a/lib/web_ui/test/html/text_test.dart +++ b/lib/web_ui/test/html/text_test.dart @@ -7,12 +7,11 @@ import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; - import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart'; -import '../common/initialize_view_embedder.dart'; import '../common/matchers.dart'; +import '../common/test_initialization.dart'; import 'paragraph/helper.dart'; void main() { @@ -22,7 +21,7 @@ void main() { Future testMain() async { const double baselineRatio = 1.1662499904632568; - await initializeTestFlutterViewEmbedder(); + setUpUnitTests(); late String fallback; setUp(() { diff --git a/lib/web_ui/test/ui/README.md b/lib/web_ui/test/ui/README.md index acd49655295e0..9ce5ea6d15f44 100644 --- a/lib/web_ui/test/ui/README.md +++ b/lib/web_ui/test/ui/README.md @@ -8,5 +8,5 @@ In practice, this means these tests should only use `dart:ui` APIs or ## Notes -These tests should call `setUpUiTest()` at the top level to initialize the +These tests should call `setUpUnitTests()` at the top level to initialize the renderer they are expected to run. diff --git a/lib/web_ui/test/ui/canvas_curves_golden_test.dart b/lib/web_ui/test/ui/canvas_curves_golden_test.dart index e067e9f944b8f..5d41caf2ef190 100644 --- a/lib/web_ui/test/ui/canvas_curves_golden_test.dart +++ b/lib/web_ui/test/ui/canvas_curves_golden_test.dart @@ -9,6 +9,7 @@ import 'package:test/test.dart'; import 'package:ui/ui.dart'; import 'package:web_engine_tester/golden_tester.dart'; +import '../common/test_initialization.dart'; import 'utils.dart'; void main() { @@ -16,7 +17,7 @@ void main() { } Future testMain() async { - setUpUiTest(); + setUpUnitTests(); const Rect region = Rect.fromLTWH(0, 0, 300, 300); diff --git a/lib/web_ui/test/ui/canvas_lines_golden_test.dart b/lib/web_ui/test/ui/canvas_lines_golden_test.dart index df3c00bee99a0..e5d96a84a8789 100644 --- a/lib/web_ui/test/ui/canvas_lines_golden_test.dart +++ b/lib/web_ui/test/ui/canvas_lines_golden_test.dart @@ -7,6 +7,7 @@ import 'package:test/test.dart'; import 'package:ui/ui.dart'; import 'package:web_engine_tester/golden_tester.dart'; +import '../common/test_initialization.dart'; import 'utils.dart'; void main() { @@ -14,7 +15,7 @@ void main() { } Future testMain() async { - setUpUiTest(); + setUpUnitTests(); const Rect region = Rect.fromLTWH(0, 0, 300, 300); diff --git a/lib/web_ui/test/ui/canvas_test.dart b/lib/web_ui/test/ui/canvas_test.dart index 1cb3db0ac3a99..86100b9055f8a 100644 --- a/lib/web_ui/test/ui/canvas_test.dart +++ b/lib/web_ui/test/ui/canvas_test.dart @@ -11,14 +11,14 @@ import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; import '../common/matchers.dart'; -import 'utils.dart'; +import '../common/test_initialization.dart'; void main() { internalBootstrapBrowserTest(() => testMain); } Future testMain() async { - setUpUiTest(); + setUpUnitTests(); final bool deviceClipRoundsOut = renderer is! HtmlRenderer; runCanvasTests(deviceClipRoundsOut: deviceClipRoundsOut); diff --git a/lib/web_ui/test/ui/color_test.dart b/lib/web_ui/test/ui/color_test.dart index 7236628b1f6cf..2ac2df7595d02 100644 --- a/lib/web_ui/test/ui/color_test.dart +++ b/lib/web_ui/test/ui/color_test.dart @@ -6,7 +6,7 @@ import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/ui.dart'; -import 'utils.dart'; +import '../common/test_initialization.dart'; void main() { internalBootstrapBrowserTest(() => testMain); @@ -17,7 +17,7 @@ class NotAColor extends Color { } Future testMain() async { - setUpUiTest(); + setUpUnitTests(); test('color accessors should work', () { const Color foo = Color(0x12345678); diff --git a/lib/web_ui/test/ui/font_collection_test.dart b/lib/web_ui/test/ui/font_collection_test.dart index a04c94872cb11..6bed4450ca06c 100644 --- a/lib/web_ui/test/ui/font_collection_test.dart +++ b/lib/web_ui/test/ui/font_collection_test.dart @@ -9,6 +9,7 @@ import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; +import '../common/test_initialization.dart'; import 'utils.dart'; void main() { @@ -16,32 +17,32 @@ void main() { } Future testMain() async { - setUpUiTest(); + setUpUnitTests(); test('Loading valid font from data succeeds without family name', () async { final FlutterFontCollection collection = renderer.fontCollection; final ByteBuffer ahemData = await httpFetchByteBuffer('/assets/fonts/ahem.ttf'); - await expectLater( - collection.loadFontFromList(ahemData.asUint8List()), - returnsNormally + expect( + await collection.loadFontFromList(ahemData.asUint8List()), + true ); }, skip: isHtml); // HtmlFontCollection requires family name test('Loading valid font from data succeeds with family name', () async { final FlutterFontCollection collection = renderer.fontCollection; final ByteBuffer ahemData = await httpFetchByteBuffer('/assets/fonts/ahem.ttf'); - await expectLater( - collection.loadFontFromList(ahemData.asUint8List(), fontFamily: 'FamilyName'), - returnsNormally + expect( + await collection.loadFontFromList(ahemData.asUint8List(), fontFamily: 'FamilyName'), + true ); }); test('Loading invalid font from data throws', () async { final FlutterFontCollection collection = renderer.fontCollection; final List invalidFontData = utf8.encode('This is not valid font data'); - await expectLater( - collection.loadFontFromList(Uint8List.fromList(invalidFontData), fontFamily: 'FamilyName'), - throwsException + expect( + await collection.loadFontFromList(Uint8List.fromList(invalidFontData), fontFamily: 'FamilyName'), + false ); }); } diff --git a/lib/web_ui/test/ui/fragment_shader_test.dart b/lib/web_ui/test/ui/fragment_shader_test.dart index 1fef73e8e0f55..60a8ebc81517d 100644 --- a/lib/web_ui/test/ui/fragment_shader_test.dart +++ b/lib/web_ui/test/ui/fragment_shader_test.dart @@ -11,6 +11,8 @@ import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; import 'package:web_engine_tester/golden_tester.dart'; +import '../common/fake_asset_manager.dart'; +import '../common/test_initialization.dart'; import 'utils.dart'; void main() { @@ -40,7 +42,7 @@ const String kVoronoiShaderSksl = r''' '''; Future testMain() async { - setUpUiTest(); + setUpUnitTests(); const ui.Rect region = ui.Rect.fromLTWH(0, 0, 300, 300); diff --git a/lib/web_ui/test/ui/gradient_golden_test.dart b/lib/web_ui/test/ui/gradient_golden_test.dart index 96ba0f7d7fd20..425dd14ee8180 100644 --- a/lib/web_ui/test/ui/gradient_golden_test.dart +++ b/lib/web_ui/test/ui/gradient_golden_test.dart @@ -10,6 +10,7 @@ import 'package:ui/src/engine/browser_detection.dart'; import 'package:ui/ui.dart'; import 'package:web_engine_tester/golden_tester.dart'; +import '../common/test_initialization.dart'; import 'utils.dart'; void main() { @@ -17,7 +18,7 @@ void main() { } Future testMain() async { - setUpUiTest(); + setUpUnitTests(); const Rect region = Rect.fromLTWH(0, 0, 300, 300); diff --git a/lib/web_ui/test/ui/gradient_test.dart b/lib/web_ui/test/ui/gradient_test.dart index 69d0ba9d7aa08..968d4bc661663 100644 --- a/lib/web_ui/test/ui/gradient_test.dart +++ b/lib/web_ui/test/ui/gradient_test.dart @@ -7,6 +7,7 @@ import 'package:test/test.dart'; import 'package:ui/ui.dart'; +import '../common/test_initialization.dart'; import 'utils.dart'; void main() { @@ -14,7 +15,7 @@ void main() { } Future testMain() async { - setUpUiTest(); + setUpUnitTests(); test('Gradient.radial with no focal point', () { expect( diff --git a/lib/web_ui/test/ui/paragraph_builder_test.dart b/lib/web_ui/test/ui/paragraph_builder_test.dart index 51db06b23e719..a2e8e73fb3751 100644 --- a/lib/web_ui/test/ui/paragraph_builder_test.dart +++ b/lib/web_ui/test/ui/paragraph_builder_test.dart @@ -6,6 +6,7 @@ import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/ui.dart'; +import '../common/test_initialization.dart'; import 'utils.dart'; void main() { @@ -13,7 +14,7 @@ void main() { } Future testMain() async { - setUpUiTest(); + setUpUnitTests(); test('Should be able to build and layout a paragraph', () { final ParagraphBuilder builder = ParagraphBuilder(ParagraphStyle()); diff --git a/lib/web_ui/test/ui/path_metrics_test.dart b/lib/web_ui/test/ui/path_metrics_test.dart index f211b8a6b3219..ba820f7590c59 100644 --- a/lib/web_ui/test/ui/path_metrics_test.dart +++ b/lib/web_ui/test/ui/path_metrics_test.dart @@ -9,7 +9,7 @@ import 'package:test/test.dart'; import 'package:ui/ui.dart'; import '../common/matchers.dart'; -import 'utils.dart'; +import '../common/test_initialization.dart'; const double kTolerance = 0.1; @@ -18,7 +18,7 @@ void main() { } Future testMain() async { - setUpUiTest(); + setUpUnitTests(); group('PathMetric length', () { test('empty path', () { final Path path = Path(); diff --git a/lib/web_ui/test/ui/path_test.dart b/lib/web_ui/test/ui/path_test.dart index 5b78add83b697..94094a03b50ba 100644 --- a/lib/web_ui/test/ui/path_test.dart +++ b/lib/web_ui/test/ui/path_test.dart @@ -8,6 +8,7 @@ import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/ui.dart'; +import '../common/test_initialization.dart'; import 'utils.dart'; void main() { @@ -15,7 +16,7 @@ void main() { } Future testMain() async { - setUpUiTest(); + setUpUnitTests(); test('path getBounds', () { const Rect r = Rect.fromLTRB(1.0, 3.0, 5.0, 7.0); final Path p = Path()..addRect(r); diff --git a/lib/web_ui/test/ui/picture_test.dart b/lib/web_ui/test/ui/picture_test.dart index daa9f9d8075c9..297d8b50f403a 100644 --- a/lib/web_ui/test/ui/picture_test.dart +++ b/lib/web_ui/test/ui/picture_test.dart @@ -6,14 +6,14 @@ import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/ui.dart' as ui; -import 'utils.dart'; +import '../common/test_initialization.dart'; void main() { internalBootstrapBrowserTest(() => testMain); } Future testMain() async { - setUpUiTest(); + setUpUnitTests(); test('Picture construction invokes onCreate once', () async { int onCreateInvokedCount = 0; diff --git a/lib/web_ui/test/ui/rect_test.dart b/lib/web_ui/test/ui/rect_test.dart index d25c7af56fa82..3fa4eb0d14d01 100644 --- a/lib/web_ui/test/ui/rect_test.dart +++ b/lib/web_ui/test/ui/rect_test.dart @@ -6,14 +6,14 @@ import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/ui.dart'; -import 'utils.dart'; +import '../common/test_initialization.dart'; void main() { internalBootstrapBrowserTest(() => testMain); } Future testMain() async { - setUpUiTest(); + setUpUnitTests(); test('rect accessors', () { const Rect r = Rect.fromLTRB(1.0, 3.0, 5.0, 7.0); expect(r.left, equals(1.0)); diff --git a/lib/web_ui/test/ui/rrect_test.dart b/lib/web_ui/test/ui/rrect_test.dart index 00f8750e6a048..958c7aa137cfa 100644 --- a/lib/web_ui/test/ui/rrect_test.dart +++ b/lib/web_ui/test/ui/rrect_test.dart @@ -6,14 +6,14 @@ import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart' hide TypeMatcher, isInstanceOf; import 'package:ui/ui.dart'; -import 'utils.dart'; +import '../common/test_initialization.dart'; void main() { internalBootstrapBrowserTest(() => testMain); } Future testMain() async { - setUpUiTest(); + setUpUnitTests(); test('RRect.contains()', () { final RRect rrect = RRect.fromRectAndCorners( const Rect.fromLTRB(1.0, 1.0, 2.0, 2.0), diff --git a/lib/web_ui/test/ui/scene_builder_test.dart b/lib/web_ui/test/ui/scene_builder_test.dart index 18bb6a4ab7076..6953b60f18b8d 100644 --- a/lib/web_ui/test/ui/scene_builder_test.dart +++ b/lib/web_ui/test/ui/scene_builder_test.dart @@ -10,6 +10,7 @@ import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; import 'package:web_engine_tester/golden_tester.dart'; +import '../common/test_initialization.dart'; import 'utils.dart'; void main() { @@ -17,7 +18,7 @@ void main() { } Future testMain() async { - setUpUiTest(); + setUpUnitTests(); group('${ui.SceneBuilder}', () { const ui.Rect region = ui.Rect.fromLTWH(0, 0, 300, 300); diff --git a/lib/web_ui/test/ui/shadow_test.dart b/lib/web_ui/test/ui/shadow_test.dart index b1bb65ad0c924..5658a519affdd 100644 --- a/lib/web_ui/test/ui/shadow_test.dart +++ b/lib/web_ui/test/ui/shadow_test.dart @@ -7,6 +7,7 @@ import 'package:test/test.dart'; import 'package:ui/ui.dart' as ui; import 'package:web_engine_tester/golden_tester.dart'; +import '../common/test_initialization.dart'; import 'utils.dart'; void main() { @@ -16,7 +17,7 @@ void main() { Future testMain() async { const ui.Rect region = ui.Rect.fromLTWH(0, 0, 300, 300); - setUpUiTest(); + setUpUnitTests(); test('Test drawing a shadow of an opaque object', () async { final ui.Picture picture = drawPicture((ui.Canvas canvas) { diff --git a/lib/web_ui/test/ui/title_test.dart b/lib/web_ui/test/ui/title_test.dart index 13ac803f7e14e..129d83e961477 100644 --- a/lib/web_ui/test/ui/title_test.dart +++ b/lib/web_ui/test/ui/title_test.dart @@ -7,14 +7,14 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; -import 'utils.dart'; +import '../common/test_initialization.dart'; void main() { internalBootstrapBrowserTest(() => testMain); } Future testMain() async { - setUpUiTest(); + setUpUnitTests(); const MethodCodec codec = JSONMethodCodec(); diff --git a/lib/web_ui/test/ui/utils.dart b/lib/web_ui/test/ui/utils.dart index 4ce4f515c5612..511130cb50a7c 100644 --- a/lib/web_ui/test/ui/utils.dart +++ b/lib/web_ui/test/ui/utils.dart @@ -5,21 +5,10 @@ import 'dart:async'; import 'dart:js_interop'; -import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import 'package:ui/src/engine/skwasm/skwasm_stub.dart' if (dart.library.ffi) 'package:ui/src/engine/skwasm/skwasm_impl.dart'; import 'package:ui/ui.dart'; -import '../common/fake_asset_manager.dart'; - -/// Initializes the renderer for this test. -void setUpUiTest() { - setUpTestFonts(); - setUpAll(() { - debugEmulateFlutterTesterEnvironment = true; - }); -} - Picture drawPicture(void Function(Canvas) drawCommands) { final PictureRecorder recorder = PictureRecorder(); final Canvas canvas = Canvas(recorder); From 65afc9ba0b104ab356105859d9540b5ae3952460 Mon Sep 17 00:00:00 2001 From: Jackson Gardner Date: Fri, 21 Apr 2023 17:20:19 -0700 Subject: [PATCH 16/30] More unit test fixes. --- lib/web_ui/lib/src/engine/dom.dart | 4 +++ .../src/engine/js_interop/js_typed_data.dart | 2 +- lib/web_ui/lib/src/engine/renderer.dart | 25 ++++++++++--------- .../skwasm/skwasm_impl/font_collection.dart | 12 ++++++++- .../lib/src/engine/text/font_collection.dart | 7 +++++- lib/web_ui/skwasm/fonts.cpp | 7 +++--- .../test/common/test_initialization.dart | 9 ++++--- .../test/html/text/canvas_paragraph_test.dart | 2 +- .../test/html/text/font_loading_test.dart | 5 ++-- lib/web_ui/test/ui/font_collection_test.dart | 8 +++--- 10 files changed, 52 insertions(+), 29 deletions(-) diff --git a/lib/web_ui/lib/src/engine/dom.dart b/lib/web_ui/lib/src/engine/dom.dart index a62dbea2908f1..7fc11366f206a 100644 --- a/lib/web_ui/lib/src/engine/dom.dart +++ b/lib/web_ui/lib/src/engine/dom.dart @@ -1922,6 +1922,10 @@ extension DomFontFaceExtension on DomFontFace { @JS('weight') external JSString? get _weight; String? get weight => _weight?.toDart; + + @JS('status') + external JSString? get _status; + String? get status => _status?.toDart; } @JS() diff --git a/lib/web_ui/lib/src/engine/js_interop/js_typed_data.dart b/lib/web_ui/lib/src/engine/js_interop/js_typed_data.dart index 43f526f7afbc6..4ca98084d5a9b 100644 --- a/lib/web_ui/lib/src/engine/js_interop/js_typed_data.dart +++ b/lib/web_ui/lib/src/engine/js_interop/js_typed_data.dart @@ -23,5 +23,5 @@ class Uint8Array extends TypedArray { external factory Uint8Array._(JSAny bufferOrLength); } -Uint8Array createUint8ArrayFromBuffer(ArrayBuffer buffer) => Uint8Array._(buffer.toJS); +Uint8Array createUint8ArrayFromBuffer(ArrayBuffer buffer) => Uint8Array._(buffer as JSAny); Uint8Array createUint8ArrayFromLength(int length) => Uint8Array._(length.toJS); diff --git a/lib/web_ui/lib/src/engine/renderer.dart b/lib/web_ui/lib/src/engine/renderer.dart index bdb1d0169b7ce..5dbaaad432bfb 100644 --- a/lib/web_ui/lib/src/engine/renderer.dart +++ b/lib/web_ui/lib/src/engine/renderer.dart @@ -29,21 +29,22 @@ abstract class Renderer { factory Renderer._internal() { if (FlutterConfiguration.flutterWebUseSkwasm) { return SkwasmRenderer(); - } - bool useCanvasKit; - if (FlutterConfiguration.flutterWebAutoDetect) { - if (configuration.requestedRendererType != null) { - useCanvasKit = configuration.requestedRendererType == 'canvaskit'; + } else { + bool useCanvasKit; + if (FlutterConfiguration.flutterWebAutoDetect) { + if (configuration.requestedRendererType != null) { + useCanvasKit = configuration.requestedRendererType == 'canvaskit'; + } else { + // If requestedRendererType is not specified, use CanvasKit for desktop and + // html for mobile. + useCanvasKit = isDesktop; + } } else { - // If requestedRendererType is not specified, use CanvasKit for desktop and - // html for mobile. - useCanvasKit = isDesktop; + useCanvasKit = FlutterConfiguration.useSkia; } - } else { - useCanvasKit = FlutterConfiguration.useSkia; - } - return useCanvasKit ? CanvasKitRenderer() : HtmlRenderer(); + return useCanvasKit ? CanvasKitRenderer() : HtmlRenderer(); + } } String get rendererTag; diff --git a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/font_collection.dart b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/font_collection.dart index cd121acb37547..2bc91e9243b7d 100644 --- a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/font_collection.dart +++ b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/font_collection.dart @@ -28,6 +28,10 @@ class SkwasmFontCollection implements FlutterFontCollection { final List> fontFutures = >[]; final List loadedFonts = []; final Map fontFailures = {}; + + // We can't restore the pointers directly due to a bug in dart2wasm + // https://github.com/dart-lang/sdk/issues/52142 + final List familyHandles = []; for (final FontFamily family in manifest.families) { final List rawUtf8Bytes = utf8.encode(family.name); final SkStringHandle stringHandle = skStringAllocate(rawUtf8Bytes.length); @@ -35,6 +39,7 @@ class SkwasmFontCollection implements FlutterFontCollection { for (int i = 0; i < rawUtf8Bytes.length; i++) { stringDataPointer[i] = rawUtf8Bytes[i]; } + familyHandles.add(stringHandle.address); for (final FontAsset fontAsset in family.fontAssets) { fontFutures.add(() async { final FontLoadError? error = await _downloadFontAsset(fontAsset, stringHandle); @@ -45,9 +50,14 @@ class SkwasmFontCollection implements FlutterFontCollection { } }()); } - skStringFree(stringHandle); } await Future.wait(fontFutures); + + // Wait until all the downloading and registering is complete before + // freeing the handles to the family name strings. + familyHandles + .map((int address) => SkStringHandle.fromAddress(address)) + .forEach(skStringFree); return AssetFontsResult(loadedFonts, fontFailures); } diff --git a/lib/web_ui/lib/src/engine/text/font_collection.dart b/lib/web_ui/lib/src/engine/text/font_collection.dart index d7995efc7f086..c6666183a3fbf 100644 --- a/lib/web_ui/lib/src/engine/text/font_collection.dart +++ b/lib/web_ui/lib/src/engine/text/font_collection.dart @@ -153,9 +153,14 @@ class HtmlFontCollection implements FlutterFontCollection { Future _loadFontFaceBytes(String family, Uint8List list) async { // Since these fonts are loaded by user code, surface the error // through the returned future. - final DomFontFace fontFace = createDomFontFace(family, list); try { + final DomFontFace fontFace = createDomFontFace(family, list); + if (fontFace.status == 'error') { + // Font failed to load. + return false; + } domDocument.fonts!.add(fontFace); + // There might be paragraph measurements for this new font before it is // loaded. They were measured using fallback font, so we should clear the // cache. diff --git a/lib/web_ui/skwasm/fonts.cpp b/lib/web_ui/skwasm/fonts.cpp index 53fbc08a8c559..55b60679fab21 100644 --- a/lib/web_ui/skwasm/fonts.cpp +++ b/lib/web_ui/skwasm/fonts.cpp @@ -34,12 +34,13 @@ SKWASM_EXPORT bool fontCollection_registerFont( SkData* fontData, SkString* fontName) { fontData->ref(); - auto typeFace = collection->provider->makeFromData(sk_sp(fontData)); + auto typeFace = SkFontMgr::RefDefault()->makeFromData(sk_sp(fontData)); if (!typeFace) { return false; } - if (fontName != nullptr) { - collection->provider->registerTypeface(std::move(typeFace), *fontName); + if (fontName) { + SkString alias = *fontName; + collection->provider->registerTypeface(std::move(typeFace), alias); } else { collection->provider->registerTypeface(std::move(typeFace)); } diff --git a/lib/web_ui/test/common/test_initialization.dart b/lib/web_ui/test/common/test_initialization.dart index 9483be637a945..2ec8cbd446186 100644 --- a/lib/web_ui/test/common/test_initialization.dart +++ b/lib/web_ui/test/common/test_initialization.dart @@ -11,6 +11,11 @@ import 'fake_asset_manager.dart'; void setUpUnitTests() { late final FakeAssetScope debugFontsScope; setUpAll(() async { + ui.debugEmulateFlutterTesterEnvironment = true; + + debugFontsScope = configureDebugFontsAssetScope(fakeAssetManager); + await engine.initializeEngine(assetManager: fakeAssetManager); + // Force-initialize FlutterViewEmbedder so it doesn't overwrite test pixel ratio. engine.ensureFlutterViewEmbedderInitialized(); @@ -22,10 +27,6 @@ void setUpUnitTests() { engine.window.webOnlyDebugPhysicalSizeOverride = const ui.Size(800 * devicePixelRatio, 600 * devicePixelRatio); engine.scheduleFrameCallback = () {}; - ui.debugEmulateFlutterTesterEnvironment = true; - - debugFontsScope = configureDebugFontsAssetScope(fakeAssetManager); - await engine.initializeEngine(assetManager: fakeAssetManager); }); tearDownAll(() async { diff --git a/lib/web_ui/test/html/text/canvas_paragraph_test.dart b/lib/web_ui/test/html/text/canvas_paragraph_test.dart index 0133174fa2b41..dd652d32d82f7 100644 --- a/lib/web_ui/test/html/text/canvas_paragraph_test.dart +++ b/lib/web_ui/test/html/text/canvas_paragraph_test.dart @@ -15,7 +15,7 @@ void main() { } Future testMain() async { - setUpUnitTests() + setUpUnitTests(); group('$CanvasParagraph.getBoxesForRange', () { test('return empty list for invalid ranges', () { diff --git a/lib/web_ui/test/html/text/font_loading_test.dart b/lib/web_ui/test/html/text/font_loading_test.dart index 608d78dbb2b43..a7fcf718fc504 100644 --- a/lib/web_ui/test/html/text/font_loading_test.dart +++ b/lib/web_ui/test/html/text/font_loading_test.dart @@ -28,8 +28,9 @@ Future testMain() async { test('returns normally from invalid font buffer', () async { await expectLater( - ui.loadFontFromList(Uint8List(0), fontFamily: 'test-font'), - returnsNormally); + ui.loadFontFromList(Uint8List(0), fontFamily: 'test-font'), + returnsNormally + ); }, // TODO(hterkelsen): https://github.com/flutter/flutter/issues/56702 skip: browserEngine == BrowserEngine.webkit); diff --git a/lib/web_ui/test/ui/font_collection_test.dart b/lib/web_ui/test/ui/font_collection_test.dart index 6bed4450ca06c..efec58eee7116 100644 --- a/lib/web_ui/test/ui/font_collection_test.dart +++ b/lib/web_ui/test/ui/font_collection_test.dart @@ -19,14 +19,14 @@ void main() { Future testMain() async { setUpUnitTests(); - test('Loading valid font from data succeeds without family name', () async { + test('Loading valid font from data succeeds without family name (except in HTML renderer)', () async { final FlutterFontCollection collection = renderer.fontCollection; final ByteBuffer ahemData = await httpFetchByteBuffer('/assets/fonts/ahem.ttf'); expect( await collection.loadFontFromList(ahemData.asUint8List()), - true + !isHtml, // HtmlFontCollection requires family name ); - }, skip: isHtml); // HtmlFontCollection requires family name + }); test('Loading valid font from data succeeds with family name', () async { final FlutterFontCollection collection = renderer.fontCollection; @@ -37,7 +37,7 @@ Future testMain() async { ); }); - test('Loading invalid font from data throws', () async { + test('Loading invalid font from data returns false', () async { final FlutterFontCollection collection = renderer.fontCollection; final List invalidFontData = utf8.encode('This is not valid font data'); expect( From 58877c3c2c5f102fc2f235614fceae5e7df61835 Mon Sep 17 00:00:00 2001 From: Jackson Gardner Date: Fri, 21 Apr 2023 17:37:57 -0700 Subject: [PATCH 17/30] More unit test fixes. --- .../test/html/text/font_collection_test.dart | 16 ++++++++-------- lib/web_ui/test/html/text/font_loading_test.dart | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/web_ui/test/html/text/font_collection_test.dart b/lib/web_ui/test/html/text/font_collection_test.dart index 96ec11596d19c..3f7485ff71c40 100644 --- a/lib/web_ui/test/html/text/font_collection_test.dart +++ b/lib/web_ui/test/html/text/font_collection_test.dart @@ -41,7 +41,7 @@ void testMain() { final HtmlFontCollection collection = HtmlFontCollection(); await collection.loadAssetFonts(FontManifest([ FontFamily(testFontFamily, [ - FontAsset('url($testFontUrl)', {}) + FontAsset(testFontUrl, {}) ]) ])); domDocument.fonts! @@ -60,7 +60,7 @@ void testMain() { final HtmlFontCollection collection = HtmlFontCollection(); await collection.loadAssetFonts(FontManifest([ FontFamily(testFontFamily, [ - FontAsset('url($testFontUrl)', {}) + FontAsset(testFontUrl, {}) ]) ])); domDocument.fonts! @@ -81,7 +81,7 @@ void testMain() { final HtmlFontCollection collection = HtmlFontCollection(); await collection.loadAssetFonts(FontManifest([ FontFamily(testFontFamily, [ - FontAsset('url($testFontUrl)', {}) + FontAsset(testFontUrl, {}) ]) ])); domDocument.fonts! @@ -99,7 +99,7 @@ void testMain() { final HtmlFontCollection collection = HtmlFontCollection(); await collection.loadAssetFonts(FontManifest([ FontFamily(testFontFamily, [ - FontAsset('url($testFontUrl)', { + FontAsset(testFontUrl, { 'weight': 'bold' }) ]) @@ -125,7 +125,7 @@ void testMain() { final HtmlFontCollection collection = HtmlFontCollection(); await collection.loadAssetFonts(FontManifest([ FontFamily(testFontFamily, [ - FontAsset('url($testFontUrl)', {}) + FontAsset(testFontUrl, {}) ]) ])); domDocument.fonts! @@ -152,7 +152,7 @@ void testMain() { final HtmlFontCollection collection = HtmlFontCollection(); await collection.loadAssetFonts(FontManifest([ FontFamily(testFontFamily, [ - FontAsset('url($testFontUrl)', {}) + FontAsset(testFontUrl, {}) ]) ])); domDocument.fonts! @@ -179,7 +179,7 @@ void testMain() { final HtmlFontCollection collection = HtmlFontCollection(); await collection.loadAssetFonts(FontManifest([ FontFamily(testFontFamily, [ - FontAsset('url($testFontUrl)', {}) + FontAsset(testFontUrl, {}) ]) ])); domDocument.fonts! @@ -207,7 +207,7 @@ void testMain() { final HtmlFontCollection collection = HtmlFontCollection(); await collection.loadAssetFonts(FontManifest([ FontFamily(testFontFamily, [ - FontAsset('url($testFontUrl)', {}) + FontAsset(testFontUrl, {}) ]) ])); domDocument.fonts! diff --git a/lib/web_ui/test/html/text/font_loading_test.dart b/lib/web_ui/test/html/text/font_loading_test.dart index a7fcf718fc504..702c70b66ff3d 100644 --- a/lib/web_ui/test/html/text/font_loading_test.dart +++ b/lib/web_ui/test/html/text/font_loading_test.dart @@ -28,7 +28,7 @@ Future testMain() async { test('returns normally from invalid font buffer', () async { await expectLater( - ui.loadFontFromList(Uint8List(0), fontFamily: 'test-font'), + () async => ui.loadFontFromList(Uint8List(0), fontFamily: 'test-font'), returnsNormally ); }, From b443e65c0126dfa05ef07f1c69ab6516e1893970 Mon Sep 17 00:00:00 2001 From: Jackson Gardner Date: Fri, 21 Apr 2023 23:24:41 -0700 Subject: [PATCH 18/30] Fix some more unit tests. --- lib/web_ui/test/canvaskit/common.dart | 5 ++- .../canvaskit/skia_font_collection_test.dart | 4 +-- .../test/common/test_initialization.dart | 33 +++++++++++-------- lib/web_ui/test/engine/text_editing_test.dart | 7 ++-- 4 files changed, 31 insertions(+), 18 deletions(-) diff --git a/lib/web_ui/test/canvaskit/common.dart b/lib/web_ui/test/canvaskit/common.dart index dfd230dac9e95..955df8caf7671 100644 --- a/lib/web_ui/test/canvaskit/common.dart +++ b/lib/web_ui/test/canvaskit/common.dart @@ -17,7 +17,10 @@ const MethodCodec codec = StandardMethodCodec(); /// Common test setup for all CanvasKit unit-tests. void setUpCanvasKitTest() { - setUpUnitTests(); + setUpUnitTests( + emulateTesterEnvironment: false, + setUpTestViewDimensions: false, + ); setUpAll(() { // Ahem must be added to font fallbacks list regardless of where it was diff --git a/lib/web_ui/test/canvaskit/skia_font_collection_test.dart b/lib/web_ui/test/canvaskit/skia_font_collection_test.dart index a46c812742d3a..84147cce3db5d 100644 --- a/lib/web_ui/test/canvaskit/skia_font_collection_test.dart +++ b/lib/web_ui/test/canvaskit/skia_font_collection_test.dart @@ -10,6 +10,7 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; import '../common/fake_asset_manager.dart'; +import '../common/test_initialization.dart'; import 'common.dart'; void main() { @@ -18,14 +19,13 @@ void main() { void testMain() { group('$SkiaFontCollection', () { - setUpCanvasKitTest(); + setUpUnitTests(); final List warnings = []; late void Function(String) oldPrintWarning; late FakeAssetScope testAssetScope; setUpAll(() async { - ensureFlutterViewEmbedderInitialized(); oldPrintWarning = printWarning; printWarning = (String warning) { warnings.add(warning); diff --git a/lib/web_ui/test/common/test_initialization.dart b/lib/web_ui/test/common/test_initialization.dart index 2ec8cbd446186..1a781322f2bd5 100644 --- a/lib/web_ui/test/common/test_initialization.dart +++ b/lib/web_ui/test/common/test_initialization.dart @@ -8,25 +8,32 @@ import 'package:ui/ui.dart' as ui; import 'fake_asset_manager.dart'; -void setUpUnitTests() { +void setUpUnitTests({ + bool emulateTesterEnvironment = true, + bool setUpTestViewDimensions = true, +}) { late final FakeAssetScope debugFontsScope; setUpAll(() async { - ui.debugEmulateFlutterTesterEnvironment = true; + if (emulateTesterEnvironment) { + ui.debugEmulateFlutterTesterEnvironment = true; + } debugFontsScope = configureDebugFontsAssetScope(fakeAssetManager); await engine.initializeEngine(assetManager: fakeAssetManager); - // Force-initialize FlutterViewEmbedder so it doesn't overwrite test pixel ratio. - engine.ensureFlutterViewEmbedderInitialized(); - - // The following parameters are hard-coded in Flutter's test embedder. Since - // we don't have an embedder yet this is the lowest-most layer we can put - // this stuff in. - const double devicePixelRatio = 3.0; - engine.window.debugOverrideDevicePixelRatio(devicePixelRatio); - engine.window.webOnlyDebugPhysicalSizeOverride = - const ui.Size(800 * devicePixelRatio, 600 * devicePixelRatio); - engine.scheduleFrameCallback = () {}; + if (setUpTestViewDimensions) { + // Force-initialize FlutterViewEmbedder so it doesn't overwrite test pixel ratio. + engine.ensureFlutterViewEmbedderInitialized(); + + // The following parameters are hard-coded in Flutter's test embedder. Since + // we don't have an embedder yet this is the lowest-most layer we can put + // this stuff in. + const double devicePixelRatio = 3.0; + engine.window.debugOverrideDevicePixelRatio(devicePixelRatio); + engine.window.webOnlyDebugPhysicalSizeOverride = + const ui.Size(800 * devicePixelRatio, 600 * devicePixelRatio); + engine.scheduleFrameCallback = () {}; + } }); tearDownAll(() async { diff --git a/lib/web_ui/test/engine/text_editing_test.dart b/lib/web_ui/test/engine/text_editing_test.dart index 830be7b916b8a..5031cca1d00b7 100644 --- a/lib/web_ui/test/engine/text_editing_test.dart +++ b/lib/web_ui/test/engine/text_editing_test.dart @@ -12,7 +12,6 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart' show flutterViewEmbedder; import 'package:ui/src/engine/browser_detection.dart'; import 'package:ui/src/engine/dom.dart'; -import 'package:ui/src/engine/initialization.dart'; import 'package:ui/src/engine/services.dart'; import 'package:ui/src/engine/text_editing/autofill_hint.dart'; import 'package:ui/src/engine/text_editing/input_type.dart'; @@ -21,6 +20,7 @@ import 'package:ui/src/engine/util.dart'; import 'package:ui/src/engine/vector_math.dart'; import '../common/spy.dart'; +import '../common/test_initialization.dart'; /// The `keyCode` of the "Enter" key. const int _kReturnKeyCode = 13; @@ -60,7 +60,10 @@ void main() { } Future testMain() async { - await initializeEngine(); + setUpUnitTests( + emulateTesterEnvironment: false, + setUpTestViewDimensions: false + ); tearDown(() { lastEditingState = null; From eeaa29c0af80fda9942c745d85dd647c0ff943b0 Mon Sep 17 00:00:00 2001 From: Jackson Gardner Date: Fri, 21 Apr 2023 23:35:42 -0700 Subject: [PATCH 19/30] Fix some formatting. --- lib/web_ui/lib/src/engine/fonts.dart | 4 ++-- .../lib/src/engine/skwasm/skwasm_impl/font_collection.dart | 2 +- lib/web_ui/skwasm/fonts.cpp | 3 ++- lib/web_ui/test/common/test_initialization.dart | 2 +- .../test/html/drawing/canvas_draw_color_golden_test.dart | 2 +- .../test/html/drawing/canvas_draw_picture_golden_test.dart | 2 +- lib/web_ui/test/html/shaders/shader_mask_golden_test.dart | 2 +- 7 files changed, 9 insertions(+), 8 deletions(-) diff --git a/lib/web_ui/lib/src/engine/fonts.dart b/lib/web_ui/lib/src/engine/fonts.dart index 933685e52f793..2fe0a8766196f 100644 --- a/lib/web_ui/lib/src/engine/fonts.dart +++ b/lib/web_ui/lib/src/engine/fonts.dart @@ -101,7 +101,7 @@ class FontDownloadError extends FontLoadError { class FontInvalidDataError extends FontLoadError { FontInvalidDataError(super.url); - + @override String get message => 'Invalid data for font asset at url $url.'; } @@ -112,7 +112,7 @@ class AssetFontsResult { /// A list of asset keys for fonts that were successfully loaded. final List loadedFonts; - /// A map of the asset keys to failures for fonts that failed to load. + /// A map of the asset keys to failures for fonts that failed to load. final Map fontFailures; } diff --git a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/font_collection.dart b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/font_collection.dart index 2bc91e9243b7d..63fd3f448fe86 100644 --- a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/font_collection.dart +++ b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/font_collection.dart @@ -62,7 +62,7 @@ class SkwasmFontCollection implements FlutterFontCollection { } Future _downloadFontAsset(FontAsset asset, SkStringHandle familyNameHandle) async { - final HttpFetchResponse response; + final HttpFetchResponse response; try { response = await assetManager.loadAsset(asset.asset); } catch (error) { diff --git a/lib/web_ui/skwasm/fonts.cpp b/lib/web_ui/skwasm/fonts.cpp index 55b60679fab21..22b66419cf8e9 100644 --- a/lib/web_ui/skwasm/fonts.cpp +++ b/lib/web_ui/skwasm/fonts.cpp @@ -34,7 +34,8 @@ SKWASM_EXPORT bool fontCollection_registerFont( SkData* fontData, SkString* fontName) { fontData->ref(); - auto typeFace = SkFontMgr::RefDefault()->makeFromData(sk_sp(fontData)); + auto typeFace = + SkFontMgr::RefDefault()->makeFromData(sk_sp(fontData)); if (!typeFace) { return false; } diff --git a/lib/web_ui/test/common/test_initialization.dart b/lib/web_ui/test/common/test_initialization.dart index 1a781322f2bd5..b422c6c174ee2 100644 --- a/lib/web_ui/test/common/test_initialization.dart +++ b/lib/web_ui/test/common/test_initialization.dart @@ -9,7 +9,7 @@ import 'package:ui/ui.dart' as ui; import 'fake_asset_manager.dart'; void setUpUnitTests({ - bool emulateTesterEnvironment = true, + bool emulateTesterEnvironment = true, bool setUpTestViewDimensions = true, }) { late final FakeAssetScope debugFontsScope; diff --git a/lib/web_ui/test/html/drawing/canvas_draw_color_golden_test.dart b/lib/web_ui/test/html/drawing/canvas_draw_color_golden_test.dart index 0d5b82916f292..025007ea9f115 100644 --- a/lib/web_ui/test/html/drawing/canvas_draw_color_golden_test.dart +++ b/lib/web_ui/test/html/drawing/canvas_draw_color_golden_test.dart @@ -16,7 +16,7 @@ void main() { Future testMain() async { setUpUnitTests(); - + setUp(() async { debugShowClipLayers = true; SurfaceSceneBuilder.debugForgetFrameScene(); diff --git a/lib/web_ui/test/html/drawing/canvas_draw_picture_golden_test.dart b/lib/web_ui/test/html/drawing/canvas_draw_picture_golden_test.dart index 36d30c288ac89..0a3dc74209535 100644 --- a/lib/web_ui/test/html/drawing/canvas_draw_picture_golden_test.dart +++ b/lib/web_ui/test/html/drawing/canvas_draw_picture_golden_test.dart @@ -20,7 +20,7 @@ SurfacePaint makePaint() => Paint() as SurfacePaint; Future testMain() async { setUpUnitTests(); - + setUpAll(() async { debugShowClipLayers = true; }); diff --git a/lib/web_ui/test/html/shaders/shader_mask_golden_test.dart b/lib/web_ui/test/html/shaders/shader_mask_golden_test.dart index 4d06883f3d01b..4ec74f01b6fd8 100644 --- a/lib/web_ui/test/html/shaders/shader_mask_golden_test.dart +++ b/lib/web_ui/test/html/shaders/shader_mask_golden_test.dart @@ -32,7 +32,7 @@ Future main() async { Future testMain() async { setUpUnitTests(); - + setUpAll(() async { debugShowClipLayers = true; }); From e06b8853a35b4ce4ee2b655e6e8cb62197405c06 Mon Sep 17 00:00:00 2001 From: Jackson Gardner Date: Sun, 23 Apr 2023 10:56:35 -0700 Subject: [PATCH 20/30] Use a cast that works on all backends. --- lib/web_ui/lib/src/engine/js_interop/js_typed_data.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/web_ui/lib/src/engine/js_interop/js_typed_data.dart b/lib/web_ui/lib/src/engine/js_interop/js_typed_data.dart index 4ca98084d5a9b..1748f6513e05b 100644 --- a/lib/web_ui/lib/src/engine/js_interop/js_typed_data.dart +++ b/lib/web_ui/lib/src/engine/js_interop/js_typed_data.dart @@ -23,5 +23,5 @@ class Uint8Array extends TypedArray { external factory Uint8Array._(JSAny bufferOrLength); } -Uint8Array createUint8ArrayFromBuffer(ArrayBuffer buffer) => Uint8Array._(buffer as JSAny); +Uint8Array createUint8ArrayFromBuffer(ArrayBuffer buffer) => Uint8Array._(buffer as JSObject); Uint8Array createUint8ArrayFromLength(int length) => Uint8Array._(length.toJS); From be4d95b24b6dc1816cb94e4cd784092ef388d209 Mon Sep 17 00:00:00 2001 From: Jackson Gardner Date: Sun, 23 Apr 2023 15:43:15 -0700 Subject: [PATCH 21/30] Added font collection tests for asset loaded fonts. --- lib/web_ui/lib/src/engine/dom.dart | 7 +- lib/web_ui/test/ui/font_collection_test.dart | 108 +++++++++++++++++++ 2 files changed, 113 insertions(+), 2 deletions(-) diff --git a/lib/web_ui/lib/src/engine/dom.dart b/lib/web_ui/lib/src/engine/dom.dart index 7fc11366f206a..25f2925dfc59e 100644 --- a/lib/web_ui/lib/src/engine/dom.dart +++ b/lib/web_ui/lib/src/engine/dom.dart @@ -1398,7 +1398,7 @@ class DomXMLHttpRequestEventTarget extends DomEventTarget {} Future<_DomResponse> _rawHttpGet(String url) => js_util.promiseToFuture<_DomResponse>(domWindow._fetch1(url.toJS)); -typedef MockHttpFetchResponseFactory = Future Function( +typedef MockHttpFetchResponseFactory = Future Function( String url); MockHttpFetchResponseFactory? mockHttpFetchResponseFactory; @@ -1418,7 +1418,10 @@ MockHttpFetchResponseFactory? mockHttpFetchResponseFactory; /// [httpFetchText] instead. Future httpFetch(String url) async { if (mockHttpFetchResponseFactory != null) { - return mockHttpFetchResponseFactory!(url); + final MockHttpFetchResponse? response = await mockHttpFetchResponseFactory!(url); + if (response != null) { + return response; + } } try { final _DomResponse domResponse = await _rawHttpGet(url); diff --git a/lib/web_ui/test/ui/font_collection_test.dart b/lib/web_ui/test/ui/font_collection_test.dart index efec58eee7116..a999bedd15b4d 100644 --- a/lib/web_ui/test/ui/font_collection_test.dart +++ b/lib/web_ui/test/ui/font_collection_test.dart @@ -9,6 +9,7 @@ import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; +import '../common/fake_asset_manager.dart'; import '../common/test_initialization.dart'; import 'utils.dart'; @@ -19,6 +20,16 @@ void main() { Future testMain() async { setUpUnitTests(); + late FakeAssetScope testScope; + setUp(() { + mockHttpFetchResponseFactory = null; + testScope = fakeAssetManager.pushAssetScope(); + }); + + tearDown(() { + fakeAssetManager.popAssetScope(testScope); + }); + test('Loading valid font from data succeeds without family name (except in HTML renderer)', () async { final FlutterFontCollection collection = renderer.fontCollection; final ByteBuffer ahemData = await httpFetchByteBuffer('/assets/fonts/ahem.ttf'); @@ -45,4 +56,101 @@ Future testMain() async { false ); }); + + test('Loading valid asset fonts succeds', () async { + testScope.setAssetPassthrough(robotoVariableFontUrl); + testScope.setAssetPassthrough(robotoTestFontUrl); + testScope.setAssetPassthrough(ahemFontUrl); + + final FlutterFontCollection collection = renderer.fontCollection; + final AssetFontsResult result = await collection.loadAssetFonts(FontManifest([ + FontFamily(robotoFontFamily, [ + FontAsset(robotoVariableFontUrl, {}), + FontAsset(robotoTestFontUrl, {'weight': 'bold'}), + ]), + FontFamily(ahemFontFamily, [ + FontAsset(ahemFontUrl, {}) + ]), + ])); + expect(result.loadedFonts, [ + robotoVariableFontUrl, + robotoTestFontUrl, + ahemFontUrl, + ]); + expect(result.fontFailures, isEmpty); + }); + + test('Loading asset fonts reports when font not found', () async { + testScope.setAssetPassthrough(robotoVariableFontUrl); + testScope.setAssetPassthrough(robotoTestFontUrl); + + const String invalidFontUrl = 'assets/invalid_font_url.ttf'; + + final FlutterFontCollection collection = renderer.fontCollection; + final AssetFontsResult result = await collection.loadAssetFonts(FontManifest([ + FontFamily(robotoFontFamily, [ + FontAsset(robotoVariableFontUrl, {}), + FontAsset(robotoTestFontUrl, {'weight': 'bold'}), + ]), + FontFamily(ahemFontFamily, [ + FontAsset(invalidFontUrl, {}) + ]), + ])); + expect(result.loadedFonts, [ + robotoVariableFontUrl, + robotoTestFontUrl, + ]); + expect(result.fontFailures, hasLength(1)); + if (isHtml) { + // The HTML renderer doesn't have a way to differentiate 404's from other + // download errors. + expect(result.fontFailures[invalidFontUrl], isA()); + } else { + expect(result.fontFailures[invalidFontUrl], isA()); + } + }); + + test('Loading asset fonts reports when a font has invalid data', () async { + const String invalidFontUrl = 'assets/invalid_font_data.ttf'; + + testScope.setAssetPassthrough(robotoVariableFontUrl); + testScope.setAssetPassthrough(robotoTestFontUrl); + testScope.setAssetPassthrough(invalidFontUrl); + + mockHttpFetchResponseFactory = (String url) async { + if (url == invalidFontUrl) { + return MockHttpFetchResponse( + url: url, + status: 200, + payload: MockHttpFetchPayload( + byteBuffer: stringAsUtf8Data('this is invalid data').buffer + ), + ); + } + return null; + }; + + final FlutterFontCollection collection = renderer.fontCollection; + final AssetFontsResult result = await collection.loadAssetFonts(FontManifest([ + FontFamily(robotoFontFamily, [ + FontAsset(robotoVariableFontUrl, {}), + FontAsset(robotoTestFontUrl, {'weight': 'bold'}), + ]), + FontFamily(ahemFontFamily, [ + FontAsset(invalidFontUrl, {}) + ]), + ])); + expect(result.loadedFonts, [ + robotoVariableFontUrl, + robotoTestFontUrl, + ]); + expect(result.fontFailures, hasLength(1)); + if (isHtml) { + // The HTML renderer doesn't have a way to differentiate invalid data + // from other download errors. + expect(result.fontFailures[invalidFontUrl], isA()); + } else { + expect(result.fontFailures[invalidFontUrl], isA()); + } + }); } From 823eabb030411a6cd34360b59e8cacd037398fb7 Mon Sep 17 00:00:00 2001 From: Jackson Gardner Date: Sun, 23 Apr 2023 15:48:52 -0700 Subject: [PATCH 22/30] Removed unused initialization function. --- .../test/common/test_initialization.dart | 23 ------------------- 1 file changed, 23 deletions(-) diff --git a/lib/web_ui/test/common/test_initialization.dart b/lib/web_ui/test/common/test_initialization.dart index b422c6c174ee2..3a8b464f87969 100644 --- a/lib/web_ui/test/common/test_initialization.dart +++ b/lib/web_ui/test/common/test_initialization.dart @@ -40,26 +40,3 @@ void setUpUnitTests({ fakeAssetManager.popAssetScope(debugFontsScope); }); } - -Future? _platformInitializedFuture; - -Future initializeTestFlutterViewEmbedder({double devicePixelRatio = 3.0}) { - // Force-initialize FlutterViewEmbedder so it doesn't overwrite test pixel ratio. - engine.ensureFlutterViewEmbedderInitialized(); - - // The following parameters are hard-coded in Flutter's test embedder. Since - // we don't have an embedder yet this is the lowest-most layer we can put - // this stuff in. - engine.window.debugOverrideDevicePixelRatio(devicePixelRatio); - engine.window.webOnlyDebugPhysicalSizeOverride = - ui.Size(800 * devicePixelRatio, 600 * devicePixelRatio); - engine.scheduleFrameCallback = () {}; - ui.debugEmulateFlutterTesterEnvironment = true; - - // Initialize platform once and reuse across all tests. - if (_platformInitializedFuture != null) { - return _platformInitializedFuture!; - } - return _platformInitializedFuture = - engine.initializeEngine(assetManager: fakeAssetManager); -} From c4efba5176b427a9b4769fedb056c2e55ff101c0 Mon Sep 17 00:00:00 2001 From: Jackson Gardner Date: Sun, 23 Apr 2023 18:08:51 -0700 Subject: [PATCH 23/30] Changed some test setups. --- lib/web_ui/test/html/bitmap_canvas_golden_test.dart | 5 ++++- lib/web_ui/test/html/paragraph/bidi_golden_test.dart | 5 ++++- lib/web_ui/test/html/paragraph/general_golden_test.dart | 5 ++++- lib/web_ui/test/html/paragraph/justify_golden_test.dart | 5 ++++- lib/web_ui/test/html/paragraph/overflow_golden_test.dart | 5 ++++- lib/web_ui/test/html/paragraph/placeholders_golden_test.dart | 5 ++++- lib/web_ui/test/html/paragraph/shadows_golden_test.dart | 5 ++++- .../html/paragraph/text_multiline_clipping_golden_test.dart | 5 ++++- .../test/html/paragraph/text_overflow_golden_test.dart | 5 ++++- .../test/html/paragraph/text_placeholders_golden_test.dart | 5 ++++- 10 files changed, 40 insertions(+), 10 deletions(-) diff --git a/lib/web_ui/test/html/bitmap_canvas_golden_test.dart b/lib/web_ui/test/html/bitmap_canvas_golden_test.dart index ce5862358d65e..1ede2389e02ba 100644 --- a/lib/web_ui/test/html/bitmap_canvas_golden_test.dart +++ b/lib/web_ui/test/html/bitmap_canvas_golden_test.dart @@ -35,7 +35,10 @@ Future testMain() async { flutterViewEmbedder.glassPaneShadow.querySelector('flt-scene-host')!.append(testScene); } - setUpUnitTests(); + setUpUnitTests( + emulateTesterEnvironment: false, + setUpTestViewDimensions: false, + ); tearDown(() { flutterViewEmbedder.glassPaneShadow.querySelector('flt-scene')?.remove(); diff --git a/lib/web_ui/test/html/paragraph/bidi_golden_test.dart b/lib/web_ui/test/html/paragraph/bidi_golden_test.dart index 378aba443a37f..07a7f91c49f1d 100644 --- a/lib/web_ui/test/html/paragraph/bidi_golden_test.dart +++ b/lib/web_ui/test/html/paragraph/bidi_golden_test.dart @@ -18,7 +18,10 @@ void main() { } Future testMain() async { - setUpUnitTests(); + setUpUnitTests( + emulateTesterEnvironment: false, + setUpTestViewDimensions: false, + ); void paintBasicBidiStartingWithLtr( EngineCanvas canvas, diff --git a/lib/web_ui/test/html/paragraph/general_golden_test.dart b/lib/web_ui/test/html/paragraph/general_golden_test.dart index c5ca7f71fba16..34325eb7b7ab1 100644 --- a/lib/web_ui/test/html/paragraph/general_golden_test.dart +++ b/lib/web_ui/test/html/paragraph/general_golden_test.dart @@ -20,7 +20,10 @@ void main() { } Future testMain() async { - setUpUnitTests(); + setUpUnitTests( + emulateTesterEnvironment: false, + setUpTestViewDimensions: false, + ); test('paints spans and lines correctly', () { final BitmapCanvas canvas = BitmapCanvas(bounds, RenderStrategy()); diff --git a/lib/web_ui/test/html/paragraph/justify_golden_test.dart b/lib/web_ui/test/html/paragraph/justify_golden_test.dart index 414ca6436f6ea..148274ea4f01e 100644 --- a/lib/web_ui/test/html/paragraph/justify_golden_test.dart +++ b/lib/web_ui/test/html/paragraph/justify_golden_test.dart @@ -17,7 +17,10 @@ void main() { } Future testMain() async { - setUpUnitTests(); + setUpUnitTests( + emulateTesterEnvironment: false, + setUpTestViewDimensions: false, + ); void testJustifyWithMultipleSpans(EngineCanvas canvas) { void build(CanvasParagraphBuilder builder) { diff --git a/lib/web_ui/test/html/paragraph/overflow_golden_test.dart b/lib/web_ui/test/html/paragraph/overflow_golden_test.dart index 00667adcb6893..ee787940ef557 100644 --- a/lib/web_ui/test/html/paragraph/overflow_golden_test.dart +++ b/lib/web_ui/test/html/paragraph/overflow_golden_test.dart @@ -17,7 +17,10 @@ void main() { } Future testMain() async { - setUpUnitTests(); + setUpUnitTests( + emulateTesterEnvironment: false, + setUpTestViewDimensions: false, + ); void testEllipsis(EngineCanvas canvas) { Offset offset = Offset.zero; diff --git a/lib/web_ui/test/html/paragraph/placeholders_golden_test.dart b/lib/web_ui/test/html/paragraph/placeholders_golden_test.dart index 18f483e2b10e9..cf9cdc8372166 100644 --- a/lib/web_ui/test/html/paragraph/placeholders_golden_test.dart +++ b/lib/web_ui/test/html/paragraph/placeholders_golden_test.dart @@ -19,7 +19,10 @@ void main() { } Future testMain() async { - setUpUnitTests(); + setUpUnitTests( + emulateTesterEnvironment: false, + setUpTestViewDimensions: false, + ); test('draws paragraphs with placeholders', () { final BitmapCanvas canvas = BitmapCanvas(bounds, RenderStrategy()); diff --git a/lib/web_ui/test/html/paragraph/shadows_golden_test.dart b/lib/web_ui/test/html/paragraph/shadows_golden_test.dart index 79c0eb85cd4b5..f5119e1c62209 100644 --- a/lib/web_ui/test/html/paragraph/shadows_golden_test.dart +++ b/lib/web_ui/test/html/paragraph/shadows_golden_test.dart @@ -17,7 +17,10 @@ void main() { } Future testMain() async { - setUpUnitTests(); + setUpUnitTests( + emulateTesterEnvironment: false, + setUpTestViewDimensions: false, + ); test('paints multiple shadows', () { final BitmapCanvas canvas = BitmapCanvas(bounds, RenderStrategy()); diff --git a/lib/web_ui/test/html/paragraph/text_multiline_clipping_golden_test.dart b/lib/web_ui/test/html/paragraph/text_multiline_clipping_golden_test.dart index a7a164ffaf5c5..3350c212c97a3 100644 --- a/lib/web_ui/test/html/paragraph/text_multiline_clipping_golden_test.dart +++ b/lib/web_ui/test/html/paragraph/text_multiline_clipping_golden_test.dart @@ -23,7 +23,10 @@ Future testMain() async { viewportSize: const Size(600, 600), ); - setUpUnitTests(); + setUpUnitTests( + emulateTesterEnvironment: false, + setUpTestViewDimensions: false, + ); void paintTest(EngineCanvas canvas, PaintTest painter) { const Rect screenRect = Rect.fromLTWH(0, 0, 600, 600); diff --git a/lib/web_ui/test/html/paragraph/text_overflow_golden_test.dart b/lib/web_ui/test/html/paragraph/text_overflow_golden_test.dart index 50b413c3cdd0f..6d922396d99fe 100644 --- a/lib/web_ui/test/html/paragraph/text_overflow_golden_test.dart +++ b/lib/web_ui/test/html/paragraph/text_overflow_golden_test.dart @@ -25,7 +25,10 @@ Future testMain() async { viewportSize: const Size(800, 800), ); - setUpUnitTests(); + setUpUnitTests( + emulateTesterEnvironment: false, + setUpTestViewDimensions: false, + ); testEachCanvas('maxLines clipping', (EngineCanvas canvas) { Offset offset = Offset.zero; diff --git a/lib/web_ui/test/html/paragraph/text_placeholders_golden_test.dart b/lib/web_ui/test/html/paragraph/text_placeholders_golden_test.dart index f3f0328f4bba6..15a961ced6343 100644 --- a/lib/web_ui/test/html/paragraph/text_placeholders_golden_test.dart +++ b/lib/web_ui/test/html/paragraph/text_placeholders_golden_test.dart @@ -19,7 +19,10 @@ Future testMain() async { viewportSize: const Size(600, 600), ); - setUpUnitTests(); + setUpUnitTests( + emulateTesterEnvironment: false, + setUpTestViewDimensions: false, + ); testEachCanvas('draws paragraphs with placeholders', (EngineCanvas canvas) { const Rect screenRect = Rect.fromLTWH(0, 0, 600, 600); From 3ab2e661f810fe72d3e1218535eff26a168ea81a Mon Sep 17 00:00:00 2001 From: Jackson Gardner Date: Sun, 23 Apr 2023 22:21:46 -0700 Subject: [PATCH 24/30] Fixed some test initialization stuff. --- lib/web_ui/test/engine/recording_canvas_test.dart | 4 +++- lib/web_ui/test/html/canvas_clip_path_golden_test.dart | 8 ++++---- lib/web_ui/test/html/canvas_context_golden_test.dart | 8 ++++---- lib/web_ui/test/html/clip_op_golden_test.dart | 5 ++++- .../html/compositing/backdrop_filter_golden_test.dart | 5 ++++- .../test/html/compositing/canvas_blend_golden_test.dart | 4 +++- .../compositing/canvas_image_blend_mode_golden_test.dart | 4 +++- .../html/compositing/canvas_mask_filter_golden_test.dart | 4 +++- .../test/html/compositing/color_filter_golden_test.dart | 5 ++++- .../test/html/compositing/compositing_golden_test.dart | 5 ++++- .../html/compositing/dom_mask_filter_golden_test.dart | 4 +++- .../test/html/drawing/canvas_draw_color_golden_test.dart | 5 ++++- .../test/html/drawing/canvas_draw_image_golden_test.dart | 4 +++- .../html/drawing/canvas_draw_picture_golden_test.dart | 5 ++++- .../test/html/drawing/draw_vertices_golden_test.dart | 4 +++- lib/web_ui/test/html/path_metrics_golden_test.dart | 4 +++- lib/web_ui/test/html/path_transform_golden_test.dart | 4 +++- lib/web_ui/test/html/recording_canvas_golden_test.dart | 4 +++- .../test/html/shaders/image_shader_golden_test.dart | 4 +++- .../test/html/shaders/linear_gradient_golden_test.dart | 4 +++- .../test/html/shaders/radial_gradient_golden_test.dart | 4 +++- .../test/html/shaders/shader_mask_golden_test.dart | 5 ++++- lib/web_ui/test/html/shadow_golden_test.dart | 5 ++++- lib/web_ui/test/ui/canvas_curves_golden_test.dart | 4 +++- lib/web_ui/test/ui/canvas_lines_golden_test.dart | 4 +++- lib/web_ui/test/ui/canvas_test.dart | 4 +++- lib/web_ui/test/ui/fragment_shader_test.dart | 4 +++- lib/web_ui/test/ui/gradient_golden_test.dart | 4 +++- lib/web_ui/test/ui/gradient_test.dart | 9 ++++----- lib/web_ui/test/ui/paragraph_builder_test.dart | 5 ++++- lib/web_ui/test/ui/scene_builder_test.dart | 5 ++++- lib/web_ui/test/ui/shadow_test.dart | 5 ++++- 32 files changed, 110 insertions(+), 42 deletions(-) diff --git a/lib/web_ui/test/engine/recording_canvas_test.dart b/lib/web_ui/test/engine/recording_canvas_test.dart index 6571a374b4a8f..6ff41a2bff902 100644 --- a/lib/web_ui/test/engine/recording_canvas_test.dart +++ b/lib/web_ui/test/engine/recording_canvas_test.dart @@ -15,7 +15,9 @@ void main() { } void testMain() { - setUpUnitTests(); + setUpUnitTests( + setUpTestViewDimensions: false, + ); late RecordingCanvas underTest; late MockEngineCanvas mockCanvas; diff --git a/lib/web_ui/test/html/canvas_clip_path_golden_test.dart b/lib/web_ui/test/html/canvas_clip_path_golden_test.dart index ce575898e7d5f..25b3b62a4b0d8 100644 --- a/lib/web_ui/test/html/canvas_clip_path_golden_test.dart +++ b/lib/web_ui/test/html/canvas_clip_path_golden_test.dart @@ -11,6 +11,7 @@ import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' hide TextStyle; import '../common/fake_asset_manager.dart'; +import '../common/test_initialization.dart'; import 'screenshot.dart'; void main() { @@ -18,10 +19,9 @@ void main() { } Future testMain() async { - setUpAll(() async { - debugEmulateFlutterTesterEnvironment = true; - await initializeEngine(assetManager: fakeAssetManager); - }); + setUpUnitTests( + setUpTestViewDimensions: false, + ); // Regression test for https://github.com/flutter/flutter/issues/48683 // Should clip image with oval. diff --git a/lib/web_ui/test/html/canvas_context_golden_test.dart b/lib/web_ui/test/html/canvas_context_golden_test.dart index e44d3339909fd..3978fc51f5ac8 100644 --- a/lib/web_ui/test/html/canvas_context_golden_test.dart +++ b/lib/web_ui/test/html/canvas_context_golden_test.dart @@ -8,6 +8,7 @@ import 'package:ui/src/engine.dart' as engine; import 'package:ui/ui.dart' hide TextStyle; import '../common/fake_asset_manager.dart'; +import '../common/test_initialization.dart'; import 'screenshot.dart'; void main() { @@ -20,10 +21,9 @@ Future testMain() async { const double screenHeight = 800.0; const Rect screenRect = Rect.fromLTWH(0, 0, screenWidth, screenHeight); - setUpAll(() async { - debugEmulateFlutterTesterEnvironment = true; - await engine.initializeEngine(assetManager: fakeAssetManager); - }); + setUpUnitTests( + setUpTestViewDimensions: false, + ); // Regression test for https://github.com/flutter/flutter/issues/49429 // Should clip with correct transform. diff --git a/lib/web_ui/test/html/clip_op_golden_test.dart b/lib/web_ui/test/html/clip_op_golden_test.dart index 91ee1766c7b2f..9153643f944d3 100644 --- a/lib/web_ui/test/html/clip_op_golden_test.dart +++ b/lib/web_ui/test/html/clip_op_golden_test.dart @@ -16,7 +16,10 @@ void main() { } Future testMain() async { - setUpUnitTests(); + setUpUnitTests( + emulateTesterEnvironment: false, + setUpTestViewDimensions: false, + ); /// Regression test for https://github.com/flutter/flutter/issues/64734. test('Clips using difference', () async { diff --git a/lib/web_ui/test/html/compositing/backdrop_filter_golden_test.dart b/lib/web_ui/test/html/compositing/backdrop_filter_golden_test.dart index 6e38f7506a286..dd7d329f2ac83 100644 --- a/lib/web_ui/test/html/compositing/backdrop_filter_golden_test.dart +++ b/lib/web_ui/test/html/compositing/backdrop_filter_golden_test.dart @@ -16,7 +16,10 @@ void main() { } Future testMain() async { - setUpUnitTests(); + setUpUnitTests( + emulateTesterEnvironment: false, + setUpTestViewDimensions: false, + ); setUp(() async { debugShowClipLayers = true; diff --git a/lib/web_ui/test/html/compositing/canvas_blend_golden_test.dart b/lib/web_ui/test/html/compositing/canvas_blend_golden_test.dart index b7322ad9c171a..816219f879e7e 100644 --- a/lib/web_ui/test/html/compositing/canvas_blend_golden_test.dart +++ b/lib/web_ui/test/html/compositing/canvas_blend_golden_test.dart @@ -17,7 +17,9 @@ void main() { } Future testMain() async { - setUpUnitTests(); + setUpUnitTests( + setUpTestViewDimensions: false, + ); test('Blend circles with difference and color', () async { final RecordingCanvas rc = diff --git a/lib/web_ui/test/html/compositing/canvas_image_blend_mode_golden_test.dart b/lib/web_ui/test/html/compositing/canvas_image_blend_mode_golden_test.dart index 857d5a50952be..69a92c88a0689 100644 --- a/lib/web_ui/test/html/compositing/canvas_image_blend_mode_golden_test.dart +++ b/lib/web_ui/test/html/compositing/canvas_image_blend_mode_golden_test.dart @@ -18,7 +18,9 @@ void main() { SurfacePaint makePaint() => Paint() as SurfacePaint; Future testMain() async { - setUpUnitTests(); + setUpUnitTests( + setUpTestViewDimensions: false, + ); const Color red = Color(0xFFFF0000); const Color green = Color(0xFF00FF00); diff --git a/lib/web_ui/test/html/compositing/canvas_mask_filter_golden_test.dart b/lib/web_ui/test/html/compositing/canvas_mask_filter_golden_test.dart index 844890a03af2a..2dda8c5d48009 100644 --- a/lib/web_ui/test/html/compositing/canvas_mask_filter_golden_test.dart +++ b/lib/web_ui/test/html/compositing/canvas_mask_filter_golden_test.dart @@ -18,7 +18,9 @@ void main() { } Future testMain() async { - setUpUnitTests(); + setUpUnitTests( + setUpTestViewDimensions: false, + ); tearDown(() { ContextStateHandle.debugEmulateWebKitMaskFilter = false; diff --git a/lib/web_ui/test/html/compositing/color_filter_golden_test.dart b/lib/web_ui/test/html/compositing/color_filter_golden_test.dart index 23caec7dc29af..33fcbf9bca674 100644 --- a/lib/web_ui/test/html/compositing/color_filter_golden_test.dart +++ b/lib/web_ui/test/html/compositing/color_filter_golden_test.dart @@ -20,7 +20,10 @@ void main() { } Future testMain() async { - setUpUnitTests(); + setUpUnitTests( + emulateTesterEnvironment: false, + setUpTestViewDimensions: false, + ); setUp(() async { debugShowClipLayers = true; diff --git a/lib/web_ui/test/html/compositing/compositing_golden_test.dart b/lib/web_ui/test/html/compositing/compositing_golden_test.dart index 9c475f86d6b30..2302a49eeaa87 100644 --- a/lib/web_ui/test/html/compositing/compositing_golden_test.dart +++ b/lib/web_ui/test/html/compositing/compositing_golden_test.dart @@ -20,7 +20,10 @@ void main() { } Future testMain() async { - setUpUnitTests(); + setUpUnitTests( + emulateTesterEnvironment: false, + setUpTestViewDimensions: false, + ); setUp(() async { // To debug test failures uncomment the following to visualize clipping diff --git a/lib/web_ui/test/html/compositing/dom_mask_filter_golden_test.dart b/lib/web_ui/test/html/compositing/dom_mask_filter_golden_test.dart index a651f84e9d06a..db41df3e346ad 100644 --- a/lib/web_ui/test/html/compositing/dom_mask_filter_golden_test.dart +++ b/lib/web_ui/test/html/compositing/dom_mask_filter_golden_test.dart @@ -14,7 +14,9 @@ void main() { } Future testMain() async { - setUpUnitTests(); + setUpUnitTests( + setUpTestViewDimensions: false, + ); test('Should blur rectangles based on sigma.', () async { final RecordingCanvas rc = diff --git a/lib/web_ui/test/html/drawing/canvas_draw_color_golden_test.dart b/lib/web_ui/test/html/drawing/canvas_draw_color_golden_test.dart index 025007ea9f115..14be3d83c1914 100644 --- a/lib/web_ui/test/html/drawing/canvas_draw_color_golden_test.dart +++ b/lib/web_ui/test/html/drawing/canvas_draw_color_golden_test.dart @@ -15,7 +15,10 @@ void main() { } Future testMain() async { - setUpUnitTests(); + setUpUnitTests( + emulateTesterEnvironment: false, + setUpTestViewDimensions: false, + ); setUp(() async { debugShowClipLayers = true; diff --git a/lib/web_ui/test/html/drawing/canvas_draw_image_golden_test.dart b/lib/web_ui/test/html/drawing/canvas_draw_image_golden_test.dart index 647e2f221af6f..a3bfcca3e633c 100644 --- a/lib/web_ui/test/html/drawing/canvas_draw_image_golden_test.dart +++ b/lib/web_ui/test/html/drawing/canvas_draw_image_golden_test.dart @@ -22,7 +22,9 @@ void main() { } Future testMain() async { - setUpUnitTests(); + setUpUnitTests( + setUpTestViewDimensions: false, + ); test('Paints image', () async { final RecordingCanvas rc = diff --git a/lib/web_ui/test/html/drawing/canvas_draw_picture_golden_test.dart b/lib/web_ui/test/html/drawing/canvas_draw_picture_golden_test.dart index 0a3dc74209535..6b6974b937ceb 100644 --- a/lib/web_ui/test/html/drawing/canvas_draw_picture_golden_test.dart +++ b/lib/web_ui/test/html/drawing/canvas_draw_picture_golden_test.dart @@ -19,7 +19,10 @@ void main() { SurfacePaint makePaint() => Paint() as SurfacePaint; Future testMain() async { - setUpUnitTests(); + setUpUnitTests( + emulateTesterEnvironment: false, + setUpTestViewDimensions: false, + ); setUpAll(() async { debugShowClipLayers = true; diff --git a/lib/web_ui/test/html/drawing/draw_vertices_golden_test.dart b/lib/web_ui/test/html/drawing/draw_vertices_golden_test.dart index 2dd36fb5e1279..94548a1745aad 100644 --- a/lib/web_ui/test/html/drawing/draw_vertices_golden_test.dart +++ b/lib/web_ui/test/html/drawing/draw_vertices_golden_test.dart @@ -23,7 +23,9 @@ Future testMain() async { const double screenHeight = 800.0; const Rect screenRect = Rect.fromLTWH(0, 0, screenWidth, screenHeight); - setUpUnitTests(); + setUpUnitTests( + setUpTestViewDimensions: false, + ); setUp(() { GlContextCache.dispose(); diff --git a/lib/web_ui/test/html/path_metrics_golden_test.dart b/lib/web_ui/test/html/path_metrics_golden_test.dart index 29a1d0dd60238..6ce6bd660da06 100644 --- a/lib/web_ui/test/html/path_metrics_golden_test.dart +++ b/lib/web_ui/test/html/path_metrics_golden_test.dart @@ -23,7 +23,9 @@ Future testMain() async { const Color redAccentColor = Color(0xFFFF1744); const double kDashLength = 5.0; - setUpUnitTests(); + setUpUnitTests( + setUpTestViewDimensions: false, + ); test('Should calculate tangent on line', () async { final Path path = Path(); diff --git a/lib/web_ui/test/html/path_transform_golden_test.dart b/lib/web_ui/test/html/path_transform_golden_test.dart index 820e5eae40f3e..68a2b417c0a22 100644 --- a/lib/web_ui/test/html/path_transform_golden_test.dart +++ b/lib/web_ui/test/html/path_transform_golden_test.dart @@ -21,7 +21,9 @@ Future testMain() async { const double screenHeight = 800.0; const Rect screenRect = Rect.fromLTWH(0, 0, screenWidth, screenHeight); - setUpUnitTests(); + setUpUnitTests( + setUpTestViewDimensions: false, + ); test('Should draw transformed line.', () async { final RecordingCanvas rc = diff --git a/lib/web_ui/test/html/recording_canvas_golden_test.dart b/lib/web_ui/test/html/recording_canvas_golden_test.dart index 12675cce4b90c..47fa8dabd0f5b 100644 --- a/lib/web_ui/test/html/recording_canvas_golden_test.dart +++ b/lib/web_ui/test/html/recording_canvas_golden_test.dart @@ -19,7 +19,9 @@ void main() { } Future testMain() async { - setUpUnitTests(); + setUpUnitTests( + setUpTestViewDimensions: false, + ); const double screenWidth = 600.0; const double screenHeight = 800.0; diff --git a/lib/web_ui/test/html/shaders/image_shader_golden_test.dart b/lib/web_ui/test/html/shaders/image_shader_golden_test.dart index 018276b309bad..ba7d7fc52ab23 100644 --- a/lib/web_ui/test/html/shaders/image_shader_golden_test.dart +++ b/lib/web_ui/test/html/shaders/image_shader_golden_test.dart @@ -25,7 +25,9 @@ Future testMain() async { const Rect screenRect = Rect.fromLTWH(0, 0, screenWidth, screenHeight); final HtmlImage testImage = createTestImage(); - setUpUnitTests(); + setUpUnitTests( + setUpTestViewDimensions: false, + ); void drawShapes(RecordingCanvas rc, SurfacePaint paint, Rect shaderRect) { /// Rect. diff --git a/lib/web_ui/test/html/shaders/linear_gradient_golden_test.dart b/lib/web_ui/test/html/shaders/linear_gradient_golden_test.dart index 876327a946099..bf1ab3752cebd 100644 --- a/lib/web_ui/test/html/shaders/linear_gradient_golden_test.dart +++ b/lib/web_ui/test/html/shaders/linear_gradient_golden_test.dart @@ -19,7 +19,9 @@ void main() { } Future testMain() async { - setUpUnitTests(); + setUpUnitTests( + setUpTestViewDimensions: false, + ); test('Should draw linear gradient using rectangle.', () async { final RecordingCanvas rc = diff --git a/lib/web_ui/test/html/shaders/radial_gradient_golden_test.dart b/lib/web_ui/test/html/shaders/radial_gradient_golden_test.dart index c736ba98fffa2..27f64b3022a7a 100644 --- a/lib/web_ui/test/html/shaders/radial_gradient_golden_test.dart +++ b/lib/web_ui/test/html/shaders/radial_gradient_golden_test.dart @@ -14,7 +14,9 @@ void main() { } Future testMain() async { - setUpUnitTests(); + setUpUnitTests( + setUpTestViewDimensions: false, + ); Future testGradient(String fileName, Shader shader, {Rect paintRect = const Rect.fromLTRB(50, 50, 300, 300), diff --git a/lib/web_ui/test/html/shaders/shader_mask_golden_test.dart b/lib/web_ui/test/html/shaders/shader_mask_golden_test.dart index 4ec74f01b6fd8..b2fd11110fd59 100644 --- a/lib/web_ui/test/html/shaders/shader_mask_golden_test.dart +++ b/lib/web_ui/test/html/shaders/shader_mask_golden_test.dart @@ -31,7 +31,10 @@ Future main() async { // https://github.com/flutter/flutter/issues/86623 Future testMain() async { - setUpUnitTests(); + setUpUnitTests( + emulateTesterEnvironment: false, + setUpTestViewDimensions: false, + ); setUpAll(() async { debugShowClipLayers = true; diff --git a/lib/web_ui/test/html/shadow_golden_test.dart b/lib/web_ui/test/html/shadow_golden_test.dart index e0041b0cb0872..3662620f80d68 100644 --- a/lib/web_ui/test/html/shadow_golden_test.dart +++ b/lib/web_ui/test/html/shadow_golden_test.dart @@ -22,7 +22,10 @@ Future testMain() async { late SurfaceSceneBuilder builder; - setUpUnitTests(); + setUpUnitTests( + emulateTesterEnvironment: false, + setUpTestViewDimensions: false, + ); setUp(() { builder = SurfaceSceneBuilder(); diff --git a/lib/web_ui/test/ui/canvas_curves_golden_test.dart b/lib/web_ui/test/ui/canvas_curves_golden_test.dart index 5d41caf2ef190..f96de710c13ba 100644 --- a/lib/web_ui/test/ui/canvas_curves_golden_test.dart +++ b/lib/web_ui/test/ui/canvas_curves_golden_test.dart @@ -17,7 +17,9 @@ void main() { } Future testMain() async { - setUpUnitTests(); + setUpUnitTests( + setUpTestViewDimensions: false, + ); const Rect region = Rect.fromLTWH(0, 0, 300, 300); diff --git a/lib/web_ui/test/ui/canvas_lines_golden_test.dart b/lib/web_ui/test/ui/canvas_lines_golden_test.dart index e5d96a84a8789..58c7abe6d7689 100644 --- a/lib/web_ui/test/ui/canvas_lines_golden_test.dart +++ b/lib/web_ui/test/ui/canvas_lines_golden_test.dart @@ -15,7 +15,9 @@ void main() { } Future testMain() async { - setUpUnitTests(); + setUpUnitTests( + setUpTestViewDimensions: false, + ); const Rect region = Rect.fromLTWH(0, 0, 300, 300); diff --git a/lib/web_ui/test/ui/canvas_test.dart b/lib/web_ui/test/ui/canvas_test.dart index 86100b9055f8a..484a40f1be63b 100644 --- a/lib/web_ui/test/ui/canvas_test.dart +++ b/lib/web_ui/test/ui/canvas_test.dart @@ -18,7 +18,9 @@ void main() { } Future testMain() async { - setUpUnitTests(); + setUpUnitTests( + setUpTestViewDimensions: false, + ); final bool deviceClipRoundsOut = renderer is! HtmlRenderer; runCanvasTests(deviceClipRoundsOut: deviceClipRoundsOut); diff --git a/lib/web_ui/test/ui/fragment_shader_test.dart b/lib/web_ui/test/ui/fragment_shader_test.dart index 60a8ebc81517d..da69653d0a237 100644 --- a/lib/web_ui/test/ui/fragment_shader_test.dart +++ b/lib/web_ui/test/ui/fragment_shader_test.dart @@ -42,7 +42,9 @@ const String kVoronoiShaderSksl = r''' '''; Future testMain() async { - setUpUnitTests(); + setUpUnitTests( + setUpTestViewDimensions: false, + ); const ui.Rect region = ui.Rect.fromLTWH(0, 0, 300, 300); diff --git a/lib/web_ui/test/ui/gradient_golden_test.dart b/lib/web_ui/test/ui/gradient_golden_test.dart index 425dd14ee8180..f678f4d4dbb82 100644 --- a/lib/web_ui/test/ui/gradient_golden_test.dart +++ b/lib/web_ui/test/ui/gradient_golden_test.dart @@ -18,7 +18,9 @@ void main() { } Future testMain() async { - setUpUnitTests(); + setUpUnitTests( + setUpTestViewDimensions: false, + ); const Rect region = Rect.fromLTWH(0, 0, 300, 300); diff --git a/lib/web_ui/test/ui/gradient_test.dart b/lib/web_ui/test/ui/gradient_test.dart index 968d4bc661663..ae13bb05a9355 100644 --- a/lib/web_ui/test/ui/gradient_test.dart +++ b/lib/web_ui/test/ui/gradient_test.dart @@ -8,7 +8,6 @@ import 'package:test/test.dart'; import 'package:ui/ui.dart'; import '../common/test_initialization.dart'; -import 'utils.dart'; void main() { internalBootstrapBrowserTest(() => testMain); @@ -27,7 +26,7 @@ Future testMain() async { TileMode.mirror), isNotNull, ); - }, skip: isSkwasm); + }); // this is just a radial gradient, focal point is discarded. test('radial center and focal == Offset.zero and focalRadius == 0.0 is ok', @@ -43,7 +42,7 @@ Future testMain() async { Offset.zero, ), isNotNull); - }, skip: isSkwasm); + }); test('radial center != focal and focalRadius == 0.0 is ok', () { expect( @@ -57,7 +56,7 @@ Future testMain() async { const Offset(2.0, 2.0), ), isNotNull); - }, skip: isSkwasm); + }); // this would result in div/0 on skia side. test('radial center and focal == Offset.zero and focalRadius != 0.0 assert', @@ -75,5 +74,5 @@ Future testMain() async { ), throwsA(const TypeMatcher()), ); - }, skip: isSkwasm); + }); } diff --git a/lib/web_ui/test/ui/paragraph_builder_test.dart b/lib/web_ui/test/ui/paragraph_builder_test.dart index a2e8e73fb3751..fe31eed072861 100644 --- a/lib/web_ui/test/ui/paragraph_builder_test.dart +++ b/lib/web_ui/test/ui/paragraph_builder_test.dart @@ -14,7 +14,10 @@ void main() { } Future testMain() async { - setUpUnitTests(); + setUpUnitTests( + emulateTesterEnvironment: false, + setUpTestViewDimensions: false, + ); test('Should be able to build and layout a paragraph', () { final ParagraphBuilder builder = ParagraphBuilder(ParagraphStyle()); diff --git a/lib/web_ui/test/ui/scene_builder_test.dart b/lib/web_ui/test/ui/scene_builder_test.dart index 6953b60f18b8d..640b916b3b0c0 100644 --- a/lib/web_ui/test/ui/scene_builder_test.dart +++ b/lib/web_ui/test/ui/scene_builder_test.dart @@ -18,7 +18,10 @@ void main() { } Future testMain() async { - setUpUnitTests(); + setUpUnitTests( + emulateTesterEnvironment: false, + setUpTestViewDimensions: false, + ); group('${ui.SceneBuilder}', () { const ui.Rect region = ui.Rect.fromLTWH(0, 0, 300, 300); diff --git a/lib/web_ui/test/ui/shadow_test.dart b/lib/web_ui/test/ui/shadow_test.dart index 5658a519affdd..eb6b364a76947 100644 --- a/lib/web_ui/test/ui/shadow_test.dart +++ b/lib/web_ui/test/ui/shadow_test.dart @@ -17,7 +17,10 @@ void main() { Future testMain() async { const ui.Rect region = ui.Rect.fromLTWH(0, 0, 300, 300); - setUpUnitTests(); + setUpUnitTests( + emulateTesterEnvironment: false, + setUpTestViewDimensions: false, + ); test('Test drawing a shadow of an opaque object', () async { final ui.Picture picture = drawPicture((ui.Canvas canvas) { From 7cfe6fdcd7c364d5d5bd2a35f73910dcb2965c6a Mon Sep 17 00:00:00 2001 From: Jackson Gardner Date: Sun, 23 Apr 2023 23:17:42 -0700 Subject: [PATCH 25/30] Remove unused imports. --- lib/web_ui/test/html/canvas_clip_path_golden_test.dart | 1 - lib/web_ui/test/html/canvas_context_golden_test.dart | 1 - 2 files changed, 2 deletions(-) diff --git a/lib/web_ui/test/html/canvas_clip_path_golden_test.dart b/lib/web_ui/test/html/canvas_clip_path_golden_test.dart index 25b3b62a4b0d8..a0ea6e9c4adf4 100644 --- a/lib/web_ui/test/html/canvas_clip_path_golden_test.dart +++ b/lib/web_ui/test/html/canvas_clip_path_golden_test.dart @@ -10,7 +10,6 @@ import 'package:ui/src/engine.dart' as engine; import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' hide TextStyle; -import '../common/fake_asset_manager.dart'; import '../common/test_initialization.dart'; import 'screenshot.dart'; diff --git a/lib/web_ui/test/html/canvas_context_golden_test.dart b/lib/web_ui/test/html/canvas_context_golden_test.dart index 3978fc51f5ac8..282bd2590d712 100644 --- a/lib/web_ui/test/html/canvas_context_golden_test.dart +++ b/lib/web_ui/test/html/canvas_context_golden_test.dart @@ -7,7 +7,6 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart' as engine; import 'package:ui/ui.dart' hide TextStyle; -import '../common/fake_asset_manager.dart'; import '../common/test_initialization.dart'; import 'screenshot.dart'; From 7a6c015deb63470c15e59e19924515d8e8c23003 Mon Sep 17 00:00:00 2001 From: Jackson Gardner Date: Mon, 24 Apr 2023 14:08:48 -0700 Subject: [PATCH 26/30] Fix screenshot timing. --- lib/web_ui/test/common/utils.dart | 14 ++++++++++++++ lib/web_ui/test/html/screenshot.dart | 4 ++++ lib/web_ui/test/ui/scene_builder_test.dart | 1 + lib/web_ui/test/ui/utils.dart | 9 ++------- 4 files changed, 21 insertions(+), 7 deletions(-) create mode 100644 lib/web_ui/test/common/utils.dart diff --git a/lib/web_ui/test/common/utils.dart b/lib/web_ui/test/common/utils.dart new file mode 100644 index 0000000000000..0b39531bb7d3f --- /dev/null +++ b/lib/web_ui/test/common/utils.dart @@ -0,0 +1,14 @@ +// 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:async'; +import 'dart:js_interop'; + +import 'package:ui/src/engine.dart'; + +Future awaitNextFrame() { + final Completer completer = Completer(); + domWindow.requestAnimationFrame((JSNumber time) => completer.complete()); + return completer.future; +} diff --git a/lib/web_ui/test/html/screenshot.dart b/lib/web_ui/test/html/screenshot.dart index 445744c51cfb4..8f031dd950ced 100644 --- a/lib/web_ui/test/html/screenshot.dart +++ b/lib/web_ui/test/html/screenshot.dart @@ -7,6 +7,8 @@ import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; import 'package:web_engine_tester/golden_tester.dart'; +import '../common/utils.dart'; + /// Commit a recording canvas to a bitmap, and compare with the expected. /// /// [region] specifies the area of the canvas that will be included in the @@ -44,6 +46,7 @@ Future canvasScreenshot( } sceneElement.append(engineCanvas.rootElement); domDocument.body!.append(sceneElement); + await awaitNextFrame(); await matchGoldenFile('$fileName.png', region: region); } finally { @@ -61,6 +64,7 @@ Future sceneScreenshot(SurfaceSceneBuilder sceneBuilder, String fileName, .build() .webOnlyRootElement; domDocument.body!.append(sceneElement!); + await awaitNextFrame(); await matchGoldenFile('$fileName.png', region: region); } finally { diff --git a/lib/web_ui/test/ui/scene_builder_test.dart b/lib/web_ui/test/ui/scene_builder_test.dart index 640b916b3b0c0..c143c4ca236be 100644 --- a/lib/web_ui/test/ui/scene_builder_test.dart +++ b/lib/web_ui/test/ui/scene_builder_test.dart @@ -11,6 +11,7 @@ import 'package:ui/ui.dart' as ui; import 'package:web_engine_tester/golden_tester.dart'; import '../common/test_initialization.dart'; +import '../common/utils.dart'; import 'utils.dart'; void main() { diff --git a/lib/web_ui/test/ui/utils.dart b/lib/web_ui/test/ui/utils.dart index 511130cb50a7c..d6571402cc107 100644 --- a/lib/web_ui/test/ui/utils.dart +++ b/lib/web_ui/test/ui/utils.dart @@ -3,12 +3,13 @@ // found in the LICENSE file. import 'dart:async'; -import 'dart:js_interop'; import 'package:ui/src/engine.dart'; import 'package:ui/src/engine/skwasm/skwasm_stub.dart' if (dart.library.ffi) 'package:ui/src/engine/skwasm/skwasm_impl.dart'; import 'package:ui/ui.dart'; +import '../common/utils.dart'; + Picture drawPicture(void Function(Canvas) drawCommands) { final PictureRecorder recorder = PictureRecorder(); final Canvas canvas = Canvas(recorder); @@ -25,12 +26,6 @@ Future drawPictureUsingCurrentRenderer(Picture picture) async { await awaitNextFrame(); } -Future awaitNextFrame() { - final Completer completer = Completer(); - domWindow.requestAnimationFrame((JSNumber time) => completer.complete()); - return completer.future; -} - /// Returns [true] if this test is running in the CanvasKit renderer. bool get isCanvasKit => renderer is CanvasKitRenderer; From 255f475fe0ae6c5a28a2fb37da52f93db7142aa5 Mon Sep 17 00:00:00 2001 From: Jackson Gardner Date: Mon, 1 May 2023 11:06:06 -0700 Subject: [PATCH 27/30] Fix a few minor things found while setting up text. --- lib/web_ui/lib/src/engine/canvaskit/fonts.dart | 2 +- lib/web_ui/lib/src/engine/canvaskit/image.dart | 4 ++-- .../src/engine/canvaskit/image_web_codecs.dart | 18 +++--------------- .../src/engine/js_interop/js_typed_data.dart | 15 +++++++++------ .../skwasm/skwasm_impl/font_collection.dart | 8 ++++---- 5 files changed, 19 insertions(+), 28 deletions(-) diff --git a/lib/web_ui/lib/src/engine/canvaskit/fonts.dart b/lib/web_ui/lib/src/engine/canvaskit/fonts.dart index cc329a3cdb47b..5f4fbabb0a723 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/fonts.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/fonts.dart @@ -113,7 +113,7 @@ class SkiaFontCollection implements FlutterFontCollection { /// Roboto to match Android. if (!loadedRoboto) { // Download Roboto and add it to the font buffers. - pendingDownloads.add(_downloadFont('RobotoFallback', _robotoUrl, 'Roboto')); + pendingDownloads.add(_downloadFont('Roboto', _robotoUrl, 'Roboto')); } final Map fontFailures = {}; diff --git a/lib/web_ui/lib/src/engine/canvaskit/image.dart b/lib/web_ui/lib/src/engine/canvaskit/image.dart index c9b83254b3cc0..d100f5a83c5c1 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/image.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/image.dart @@ -203,10 +203,10 @@ Future fetchImage(String url, WebOnlyImageCodecChunkCallback? chunkCa /// /// See: https://developer.mozilla.org/en-US/docs/Web/API/Streams_API Future readChunked(HttpFetchPayload payload, int contentLength, WebOnlyImageCodecChunkCallback chunkCallback) async { - final Uint8Array result = createUint8ArrayFromLength(contentLength); + final JSUint8Array1 result = createUint8ArrayFromLength(contentLength); int position = 0; int cumulativeBytesLoaded = 0; - await payload.read((Uint8Array chunk) { + await payload.read((JSUint8Array1 chunk) { cumulativeBytesLoaded += chunk.length.toDart.toInt(); chunkCallback(cumulativeBytesLoaded, contentLength); result.set(chunk, position.toJS); 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 604ac004c8980..bf96471ff1f8a 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 @@ -15,15 +15,9 @@ import 'dart:math' as math; import 'dart:typed_data'; import 'package:meta/meta.dart'; +import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; -import '../alarm_clock.dart'; -import '../dom.dart'; -import '../safe_browser_api.dart'; -import '../util.dart'; -import 'canvaskit_api.dart'; -import 'image.dart'; - Duration _kDefaultWebDecoderExpireDuration = const Duration(seconds: 3); Duration _kWebDecoderExpireDuration = _kDefaultWebDecoderExpireDuration; @@ -439,24 +433,18 @@ bool _shouldReadPixelsUnmodified(VideoFrame videoFrame, ui.ImageByteFormat forma return format == ui.ImageByteFormat.rawRgba && isRgbFrame; } -@JS('Uint8Array') -@staticInterop -class _JSUint8Array { - external factory _JSUint8Array(JSNumber length); -} - Future readVideoFramePixelsUnmodified(VideoFrame videoFrame) async { final int size = videoFrame.allocationSize().toInt(); // In dart2wasm, Uint8List is not the same as a JS Uint8Array. So we // explicitly construct the JS object here. - final JSUint8Array destination = _JSUint8Array(size.toJS) as JSUint8Array; + final JSUint8Array1 destination = createUint8ArrayFromLength(size); final JsPromise copyPromise = videoFrame.copyTo(destination); await promiseToFuture(copyPromise); // In dart2wasm, `toDart` incurs a copy here. On JS backends, this is a // no-op. - return destination.toDart.buffer; + return (destination as JSUint8Array).toDart.buffer; } Future encodeVideoFrameAsPng(VideoFrame videoFrame) async { diff --git a/lib/web_ui/lib/src/engine/js_interop/js_typed_data.dart b/lib/web_ui/lib/src/engine/js_interop/js_typed_data.dart index 1748f6513e05b..a6bb9e2041485 100644 --- a/lib/web_ui/lib/src/engine/js_interop/js_typed_data.dart +++ b/lib/web_ui/lib/src/engine/js_interop/js_typed_data.dart @@ -13,15 +13,18 @@ class ArrayBuffer {} class TypedArray {} extension TypedArrayExtension on TypedArray { - external void set(Uint8Array source, JSNumber start); + external void set(JSUint8Array1 source, JSNumber start); external JSNumber get length; } -@JS() +// Due to some differences between wasm and JS backends, we can't use the +// JSUint8Array object provided by the dart sdk. So for now, we can define this +// as an opaque JS object. +@JS('Uint8Array') @staticInterop -class Uint8Array extends TypedArray { - external factory Uint8Array._(JSAny bufferOrLength); +class JSUint8Array1 extends TypedArray { + external factory JSUint8Array1._(JSAny bufferOrLength); } -Uint8Array createUint8ArrayFromBuffer(ArrayBuffer buffer) => Uint8Array._(buffer as JSObject); -Uint8Array createUint8ArrayFromLength(int length) => Uint8Array._(length.toJS); +JSUint8Array1 createUint8ArrayFromBuffer(ArrayBuffer buffer) => JSUint8Array1._(buffer as JSObject); +JSUint8Array1 createUint8ArrayFromLength(int length) => JSUint8Array1._(length.toJS); diff --git a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/font_collection.dart b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/font_collection.dart index 63fd3f448fe86..f99c01f484e65 100644 --- a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/font_collection.dart +++ b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/font_collection.dart @@ -72,15 +72,15 @@ class SkwasmFontCollection implements FlutterFontCollection { return FontNotFoundError(assetManager.getAssetUrl(asset.asset)); } int length = 0; - final List chunks = []; - await response.read((Uint8Array chunk) { + final List chunks = []; + await response.read((JSUint8Array1 chunk) { length += chunk.length.toDart.toInt(); chunks.add(chunk); }); final SkDataHandle fontData = skDataCreate(length); int dataAddress = skDataGetPointer(fontData).cast().address; - final Uint8Array wasmMemory = createUint8ArrayFromBuffer(skwasmInstance.wasmMemory.buffer); - for (final Uint8Array chunk in chunks) { + final JSUint8Array1 wasmMemory = createUint8ArrayFromBuffer(skwasmInstance.wasmMemory.buffer); + for (final JSUint8Array1 chunk in chunks) { wasmMemory.set(chunk, dataAddress.toJS); dataAddress += chunk.length.toDart.toInt(); } From 0c7fd60d62e16b03bf5aef49b5b16a6236b787fa Mon Sep 17 00:00:00 2001 From: Jackson Gardner Date: Wed, 3 May 2023 22:25:55 -0700 Subject: [PATCH 28/30] Consolidate initialization of fallbacks stuff. --- lib/web_ui/test/canvaskit/canvas_golden_test.dart | 9 --------- .../test/canvaskit/fallback_fonts_golden_test.dart | 8 -------- lib/web_ui/test/common/test_initialization.dart | 11 +++++++++++ 3 files changed, 11 insertions(+), 17 deletions(-) diff --git a/lib/web_ui/test/canvaskit/canvas_golden_test.dart b/lib/web_ui/test/canvaskit/canvas_golden_test.dart index f581af87035d3..85dd68ebf91b1 100644 --- a/lib/web_ui/test/canvaskit/canvas_golden_test.dart +++ b/lib/web_ui/test/canvaskit/canvas_golden_test.dart @@ -29,15 +29,6 @@ void testMain() { expect(notoDownloadQueue.downloader.debugActiveDownloadCount, 0); expect(notoDownloadQueue.isPending, isFalse); - // We render some color emojis in this test. - final FlutterConfiguration config = FlutterConfiguration() - ..setUserConfiguration( - js_util.jsify({ - 'useColorEmoji': true, - }) as JsFlutterConfiguration); - debugSetConfiguration(config); - - FontFallbackData.debugReset(); notoDownloadQueue.downloader.fallbackFontUrlPrefixOverride = 'assets/fallback_fonts/'; }); 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 e720fdbf2d5e5..4292ed7555635 100644 --- a/lib/web_ui/test/canvaskit/fallback_fonts_golden_test.dart +++ b/lib/web_ui/test/canvaskit/fallback_fonts_golden_test.dart @@ -33,14 +33,6 @@ void testMain() { ui.PlatformMessageCallback? savedCallback; setUp(() { - // We render some color emojis in this test. - final FlutterConfiguration config = FlutterConfiguration() - ..setUserConfiguration( - js_util.jsify({ - 'useColorEmoji': true, - }) as JsFlutterConfiguration); - debugSetConfiguration(config); - FontFallbackData.debugReset(); notoDownloadQueue.downloader.fallbackFontUrlPrefixOverride = 'assets/fallback_fonts/'; savedCallback = ui.window.onPlatformMessage; diff --git a/lib/web_ui/test/common/test_initialization.dart b/lib/web_ui/test/common/test_initialization.dart index 3a8b464f87969..812210624111e 100644 --- a/lib/web_ui/test/common/test_initialization.dart +++ b/lib/web_ui/test/common/test_initialization.dart @@ -2,6 +2,8 @@ // 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:test/test.dart'; import 'package:ui/src/engine.dart' as engine; import 'package:ui/ui.dart' as ui; @@ -18,6 +20,15 @@ void setUpUnitTests({ ui.debugEmulateFlutterTesterEnvironment = true; } + // Some of our tests rely on color emoji + final engine.FlutterConfiguration config = engine.FlutterConfiguration() + ..setUserConfiguration( + js_util.jsify({ + 'useColorEmoji': true, + }) as engine.JsFlutterConfiguration); + engine.debugSetConfiguration(config); + engine.notoDownloadQueue.downloader.fallbackFontUrlPrefixOverride = 'assets/fallback_fonts/'; + debugFontsScope = configureDebugFontsAssetScope(fakeAssetManager); await engine.initializeEngine(assetManager: fakeAssetManager); From b4785f1165a076b710b430c370459eb079d55afa Mon Sep 17 00:00:00 2001 From: Jackson Gardner Date: Wed, 3 May 2023 22:45:31 -0700 Subject: [PATCH 29/30] Pump 15 frames before taking screenshots at the recommendation of the Chrome team. --- .../src/engine/skwasm/skwasm_impl/renderer.dart | 3 --- .../test/canvaskit/canvas_golden_test.dart | 1 - .../canvaskit/fallback_fonts_golden_test.dart | 1 - lib/web_ui/test/common/utils.dart | 6 ------ lib/web_ui/test/html/screenshot.dart | 2 -- lib/web_ui/test/ui/scene_builder_test.dart | 7 ------- lib/web_ui/test/ui/utils.dart | 1 - web_sdk/web_engine_tester/lib/golden_tester.dart | 16 ++++++++++++++++ 8 files changed, 16 insertions(+), 21 deletions(-) diff --git a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/renderer.dart b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/renderer.dart index 4740a2f4e9724..73b8e4e21fc83 100644 --- a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/renderer.dart +++ b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/renderer.dart @@ -283,9 +283,6 @@ class SkwasmRenderer implements Renderer { } final SkwasmPicture picture = (scene as SkwasmScene).picture as SkwasmPicture; await surface.renderPicture(picture); - - // TODO(jacksongardner): Remove this hack. See https://github.com/flutter/flutter/issues/124616 - await Future.delayed(const Duration(milliseconds: 100)); } @override diff --git a/lib/web_ui/test/canvaskit/canvas_golden_test.dart b/lib/web_ui/test/canvaskit/canvas_golden_test.dart index 85dd68ebf91b1..f58485f1f0124 100644 --- a/lib/web_ui/test/canvaskit/canvas_golden_test.dart +++ b/lib/web_ui/test/canvaskit/canvas_golden_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:math' as math; import 'dart:typed_data'; 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 4292ed7555635..f8bff49380d7f 100644 --- a/lib/web_ui/test/canvaskit/fallback_fonts_golden_test.dart +++ b/lib/web_ui/test/canvaskit/fallback_fonts_golden_test.dart @@ -3,7 +3,6 @@ // found in the LICENSE file. import 'dart:async'; -import 'dart:js_util' as js_util; import 'dart:math' as math; import 'dart:typed_data'; diff --git a/lib/web_ui/test/common/utils.dart b/lib/web_ui/test/common/utils.dart index 0b39531bb7d3f..0a338e711992f 100644 --- a/lib/web_ui/test/common/utils.dart +++ b/lib/web_ui/test/common/utils.dart @@ -6,9 +6,3 @@ import 'dart:async'; import 'dart:js_interop'; import 'package:ui/src/engine.dart'; - -Future awaitNextFrame() { - final Completer completer = Completer(); - domWindow.requestAnimationFrame((JSNumber time) => completer.complete()); - return completer.future; -} diff --git a/lib/web_ui/test/html/screenshot.dart b/lib/web_ui/test/html/screenshot.dart index 8f031dd950ced..29495d762df2c 100644 --- a/lib/web_ui/test/html/screenshot.dart +++ b/lib/web_ui/test/html/screenshot.dart @@ -46,7 +46,6 @@ Future canvasScreenshot( } sceneElement.append(engineCanvas.rootElement); domDocument.body!.append(sceneElement); - await awaitNextFrame(); await matchGoldenFile('$fileName.png', region: region); } finally { @@ -64,7 +63,6 @@ Future sceneScreenshot(SurfaceSceneBuilder sceneBuilder, String fileName, .build() .webOnlyRootElement; domDocument.body!.append(sceneElement!); - await awaitNextFrame(); await matchGoldenFile('$fileName.png', region: region); } finally { diff --git a/lib/web_ui/test/ui/scene_builder_test.dart b/lib/web_ui/test/ui/scene_builder_test.dart index c143c4ca236be..9882a4248ca4b 100644 --- a/lib/web_ui/test/ui/scene_builder_test.dart +++ b/lib/web_ui/test/ui/scene_builder_test.dart @@ -38,7 +38,6 @@ Future testMain() async { })); await renderer.renderScene(sceneBuilder.build()); - await awaitNextFrame(); await matchGoldenFile('scene_builder_centered_circle.png', region: region); }); @@ -63,7 +62,6 @@ Future testMain() async { })); await renderer.renderScene(sceneBuilder.build()); - await awaitNextFrame(); await matchGoldenFile('scene_builder_rotated_rounded_square.png', region: region); }); @@ -79,7 +77,6 @@ Future testMain() async { })); await renderer.renderScene(sceneBuilder.build()); - await awaitNextFrame(); await matchGoldenFile('scene_builder_circle_clip_rect.png', region: region); }); @@ -98,7 +95,6 @@ Future testMain() async { })); await renderer.renderScene(sceneBuilder.build()); - await awaitNextFrame(); await matchGoldenFile('scene_builder_circle_clip_rrect.png', region: region); }); @@ -115,7 +111,6 @@ Future testMain() async { })); await renderer.renderScene(sceneBuilder.build()); - await awaitNextFrame(); await matchGoldenFile('scene_builder_rectangle_clip_circular_path.png', region: region); }); @@ -144,7 +139,6 @@ Future testMain() async { })); await renderer.renderScene(sceneBuilder.build()); - await awaitNextFrame(); await matchGoldenFile('scene_builder_opacity_circles_on_square.png', region: region); }); @@ -185,7 +179,6 @@ Future testMain() async { })); await renderer.renderScene(sceneBuilder.build()); - await awaitNextFrame(); await matchGoldenFile('scene_builder_shader_mask.png', region: region); }, skip: isFirefox && isHtml); // https://github.com/flutter/flutter/issues/86623 }); diff --git a/lib/web_ui/test/ui/utils.dart b/lib/web_ui/test/ui/utils.dart index d6571402cc107..b3fcb2ddaacac 100644 --- a/lib/web_ui/test/ui/utils.dart +++ b/lib/web_ui/test/ui/utils.dart @@ -23,7 +23,6 @@ Future drawPictureUsingCurrentRenderer(Picture picture) async { sb.pushOffset(0, 0); sb.addPicture(Offset.zero, picture); await renderer.renderScene(sb.build()); - await awaitNextFrame(); } /// Returns [true] if this test is running in the CanvasKit renderer. diff --git a/web_sdk/web_engine_tester/lib/golden_tester.dart b/web_sdk/web_engine_tester/lib/golden_tester.dart index 904a7eb91ed28..5e743b4ab7fc6 100644 --- a/web_sdk/web_engine_tester/lib/golden_tester.dart +++ b/web_sdk/web_engine_tester/lib/golden_tester.dart @@ -4,6 +4,7 @@ import 'dart:async'; import 'dart:convert'; +import 'dart:js_interop'; import 'package:test/test.dart'; // ignore: implementation_imports @@ -49,6 +50,14 @@ enum PixelComparison { /// [pixelComparison] determines the algorithm used to compare pixels. Uses /// fuzzy comparison by default. Future matchGoldenFile(String filename, {Rect? region}) async { + // It is difficult to deterministically tell when rendered content is actually + // visible to the user, so we pump 15 frames to make sure that the content is + // has reached the screen. This is at the recommendation of the Chrome team, + // and they use this same thing in their screenshot unit tests. + for (int i = 0; i < 15; i++) { + await awaitNextFrame(); + } + if (!filename.endsWith('.png')) { throw ArgumentError('Filename must end in .png or SkiaGold will ignore it.'); } @@ -76,3 +85,10 @@ Future matchGoldenFile(String filename, {Rect? region}) async { } fail(response); } + +/// Waits for one frame to complete rendering +Future awaitNextFrame() { + final Completer completer = Completer(); + domWindow.requestAnimationFrame((JSNumber time) => completer.complete()); + return completer.future; +} From 7d6e6495b8cc4a6dfcc8fe0af6306562624a23dc Mon Sep 17 00:00:00 2001 From: Jackson Gardner Date: Thu, 4 May 2023 10:33:50 -0700 Subject: [PATCH 30/30] Remove some unused stuff and add a few `final`s --- lib/web_ui/lib/src/engine/fonts.dart | 10 +++++----- lib/web_ui/test/common/utils.dart | 8 -------- lib/web_ui/test/html/screenshot.dart | 2 -- lib/web_ui/test/ui/scene_builder_test.dart | 1 - lib/web_ui/test/ui/utils.dart | 2 -- 5 files changed, 5 insertions(+), 18 deletions(-) delete mode 100644 lib/web_ui/test/common/utils.dart diff --git a/lib/web_ui/lib/src/engine/fonts.dart b/lib/web_ui/lib/src/engine/fonts.dart index 2fe0a8766196f..41dac23c68470 100644 --- a/lib/web_ui/lib/src/engine/fonts.dart +++ b/lib/web_ui/lib/src/engine/fonts.dart @@ -12,21 +12,21 @@ import 'package:ui/src/engine.dart'; class FontAsset { FontAsset(this.asset, this.descriptors); - String asset; - Map descriptors; + final String asset; + final Map descriptors; } class FontFamily { FontFamily(this.name, this.fontAssets); - String name; - List fontAssets; + final String name; + final List fontAssets; } class FontManifest { FontManifest(this.families); - List families; + final List families; } Future fetchFontManifest(AssetManager assetManager) async { diff --git a/lib/web_ui/test/common/utils.dart b/lib/web_ui/test/common/utils.dart deleted file mode 100644 index 0a338e711992f..0000000000000 --- a/lib/web_ui/test/common/utils.dart +++ /dev/null @@ -1,8 +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:async'; -import 'dart:js_interop'; - -import 'package:ui/src/engine.dart'; diff --git a/lib/web_ui/test/html/screenshot.dart b/lib/web_ui/test/html/screenshot.dart index 29495d762df2c..445744c51cfb4 100644 --- a/lib/web_ui/test/html/screenshot.dart +++ b/lib/web_ui/test/html/screenshot.dart @@ -7,8 +7,6 @@ import 'package:ui/src/engine.dart'; import 'package:ui/ui.dart' as ui; import 'package:web_engine_tester/golden_tester.dart'; -import '../common/utils.dart'; - /// Commit a recording canvas to a bitmap, and compare with the expected. /// /// [region] specifies the area of the canvas that will be included in the diff --git a/lib/web_ui/test/ui/scene_builder_test.dart b/lib/web_ui/test/ui/scene_builder_test.dart index 9882a4248ca4b..b8f59b67f3522 100644 --- a/lib/web_ui/test/ui/scene_builder_test.dart +++ b/lib/web_ui/test/ui/scene_builder_test.dart @@ -11,7 +11,6 @@ import 'package:ui/ui.dart' as ui; import 'package:web_engine_tester/golden_tester.dart'; import '../common/test_initialization.dart'; -import '../common/utils.dart'; import 'utils.dart'; void main() { diff --git a/lib/web_ui/test/ui/utils.dart b/lib/web_ui/test/ui/utils.dart index b3fcb2ddaacac..38f976ad91f3f 100644 --- a/lib/web_ui/test/ui/utils.dart +++ b/lib/web_ui/test/ui/utils.dart @@ -8,8 +8,6 @@ import 'package:ui/src/engine.dart'; import 'package:ui/src/engine/skwasm/skwasm_stub.dart' if (dart.library.ffi) 'package:ui/src/engine/skwasm/skwasm_impl.dart'; import 'package:ui/ui.dart'; -import '../common/utils.dart'; - Picture drawPicture(void Function(Canvas) drawCommands) { final PictureRecorder recorder = PictureRecorder(); final Canvas canvas = Canvas(recorder);