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 258c1fc253fd0..ecb0dd42fa032 100644 --- a/lib/web_ui/lib/src/engine/text/font_collection.dart +++ b/lib/web_ui/lib/src/engine/text/font_collection.dart @@ -200,6 +200,10 @@ class FontManager { final html.FontFace fontFace = html.FontFace(family, list); return fontFace.load().then((_) { html.document.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. + TextMeasurementService.clearCache(); }, onError: (dynamic exception) { // Failures here will throw an html.DomException which confusingly // does not implement Exception or Error. Rethrow an Exception so it can diff --git a/lib/web_ui/lib/src/engine/text/measurement.dart b/lib/web_ui/lib/src/engine/text/measurement.dart index ccd05f5eab336..43f6078d2e98c 100644 --- a/lib/web_ui/lib/src/engine/text/measurement.dart +++ b/lib/web_ui/lib/src/engine/text/measurement.dart @@ -168,7 +168,8 @@ abstract class TextMeasurementService { /// Initializes the text measurement service with a specific /// [rulerCacheCapacity] that gets passed to the [RulerManager]. static void initialize({@required int rulerCacheCapacity}) { - clearCache(); + rulerManager?.dispose(); + rulerManager = null; rulerManager = RulerManager(rulerCacheCapacity: rulerCacheCapacity); } @@ -211,11 +212,10 @@ abstract class TextMeasurementService { return domInstance; } - /// Clears the cache of paragraph rulers. - @visibleForTesting + /// Clears the cache of paragraph rulers that are used for measuring paragraph + /// metrics. static void clearCache() { - rulerManager?.dispose(); - rulerManager = null; + rulerManager?._evictAllRulers(); } static bool _canUseCanvasMeasurement(EngineParagraph paragraph) { diff --git a/lib/web_ui/test/text/font_loading_test.dart b/lib/web_ui/test/text/font_loading_test.dart index a2d5945c0cde1..8bae6d21d240f 100644 --- a/lib/web_ui/test/text/font_loading_test.dart +++ b/lib/web_ui/test/text/font_loading_test.dart @@ -7,6 +7,7 @@ import 'dart:typed_data'; import 'package:test/test.dart'; import 'package:ui/ui.dart' as ui; +import 'package:ui/src/engine.dart'; Future main() async { await ui.webOnlyInitializeTestDomRenderer(); @@ -34,6 +35,29 @@ Future main() async { expect(_containsFontFamily('Blehm'), true); }); + + test('loads font should clear measurement caches', () async { + final ui.ParagraphStyle style = ui.ParagraphStyle(); + final ui.ParagraphBuilder builder = ui.ParagraphBuilder(style); + final ui.ParagraphConstraints constraints = ui.ParagraphConstraints(width: 30.0); + builder.addText('test'); + final ui.Paragraph paragraph = builder.build(); + // Triggers the measuring and verifies the result has been cached. + paragraph.layout(constraints); + expect(TextMeasurementService.rulerManager.rulers.length, 1); + + // Now, loads a new font using loadFontFromList. This should clear the + // cache + final html.HttpRequest response = await html.HttpRequest.request( + _testFontUrl, + responseType: 'arraybuffer'); + await ui.loadFontFromList(Uint8List.view(response.response), + fontFamily: 'Blehm'); + + // Verifies the font is loaded, and the cache is cleaned. + expect(_containsFontFamily('Blehm'), true); + expect(TextMeasurementService.rulerManager.rulers.length, 0); + }); }); }