From 00904dd9671f89a98f16125c58459e0a311288bf Mon Sep 17 00:00:00 2001 From: Harry Terkelsen Date: Thu, 6 Feb 2020 14:51:12 -0800 Subject: [PATCH] Various fixes in CanvasKit (#16433) - Enable dynamically loaded fonts - Fix addOval - Fix getBoxesForRange for negative ranges --- .../lib/src/engine/compositor/fonts.dart | 16 ++++++++++++++++ .../src/engine/compositor/initialization.dart | 6 +++++- .../lib/src/engine/compositor/painting.dart | 1 + .../lib/src/engine/compositor/path.dart | 2 +- .../lib/src/engine/compositor/text.dart | 19 +++++++++++++++++-- lib/web_ui/lib/src/ui/text.dart | 12 +++++++++--- 6 files changed, 49 insertions(+), 7 deletions(-) diff --git a/lib/web_ui/lib/src/engine/compositor/fonts.dart b/lib/web_ui/lib/src/engine/compositor/fonts.dart index eda41b497c750..0f36077e1f843 100644 --- a/lib/web_ui/lib/src/engine/compositor/fonts.dart +++ b/lib/web_ui/lib/src/engine/compositor/fonts.dart @@ -4,11 +4,18 @@ part of engine; +// 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 +// this, list out all of the fonts and find the URL for the regular +// Roboto font. The API reference is here: +// https://developers.google.com/fonts/docs/developer_api const String _robotoUrl = 'https://fonts.gstatic.com/s/roboto/v20/KFOmCnqEu92Fr1Me5WZLCzYlKw.ttf'; +/// Manages the fonts used in the Skia-based backend. class SkiaFontCollection { final List> _loadingFontBuffers = >[]; + final List _dynamicallyLoadedFonts = []; final Set registeredFamilies = {}; @@ -17,9 +24,18 @@ class SkiaFontCollection { (await Future.wait(_loadingFontBuffers)) .map((ByteBuffer buffer) => buffer.asUint8List()) .toList(); + fontBuffers.addAll(_dynamicallyLoadedFonts); skFontMgr = canvasKit['SkFontMgr'].callMethod('FromData', fontBuffers); } + Future loadFontFromList(Uint8List list, {String fontFamily}) async { + _dynamicallyLoadedFonts.add(list); + if (fontFamily != null) { + registeredFamilies.add(fontFamily); + } + await ensureFontsLoaded(); + } + Future registerFonts(AssetManager assetManager) async { ByteData byteData; diff --git a/lib/web_ui/lib/src/engine/compositor/initialization.dart b/lib/web_ui/lib/src/engine/compositor/initialization.dart index 6d54273ebabfc..feed32db9cc47 100644 --- a/lib/web_ui/lib/src/engine/compositor/initialization.dart +++ b/lib/web_ui/lib/src/engine/compositor/initialization.dart @@ -9,7 +9,11 @@ const bool experimentalUseSkia = bool.fromEnvironment('FLUTTER_WEB_USE_SKIA', defaultValue: false); /// The URL to use when downloading the CanvasKit script and associated wasm. -const String canvasKitBaseUrl = 'https://unpkg.com/canvaskit-wasm@0.11.0/bin/'; +/// +/// When CanvasKit pushes a new release to NPM, update this URL to reflect the +/// most recent version. For example, if CanvasKit releases version 0.34.0 to +/// NPM, update this URL to `https://unpkg.com/canvaskit-wasm@0.34.0/bin/`. +const String canvasKitBaseUrl = 'https://unpkg.com/canvaskit-wasm@0.12.0/bin/'; /// Initialize the Skia backend. /// diff --git a/lib/web_ui/lib/src/engine/compositor/painting.dart b/lib/web_ui/lib/src/engine/compositor/painting.dart index 883ab2f9e6c62..b1eb01b460727 100644 --- a/lib/web_ui/lib/src/engine/compositor/painting.dart +++ b/lib/web_ui/lib/src/engine/compositor/painting.dart @@ -30,6 +30,7 @@ class SkPaint extends SkiaObject implements ui.Paint { @override ui.PaintingStyle get style => _style; + @override set style(ui.PaintingStyle value) { _style = value; diff --git a/lib/web_ui/lib/src/engine/compositor/path.dart b/lib/web_ui/lib/src/engine/compositor/path.dart index b8b17190cf2a8..4c3d89d90ea96 100644 --- a/lib/web_ui/lib/src/engine/compositor/path.dart +++ b/lib/web_ui/lib/src/engine/compositor/path.dart @@ -56,7 +56,7 @@ class SkPath implements ui.Path { @override void addOval(ui.Rect oval) { - _skPath.callMethod('addOval', [makeSkRect(oval), true, 0]); + _skPath.callMethod('addOval', [makeSkRect(oval), false, 1]); } @override diff --git a/lib/web_ui/lib/src/engine/compositor/text.dart b/lib/web_ui/lib/src/engine/compositor/text.dart index a9cf6578f5c96..99713e0807622 100644 --- a/lib/web_ui/lib/src/engine/compositor/text.dart +++ b/lib/web_ui/lib/src/engine/compositor/text.dart @@ -218,7 +218,7 @@ class SkTextStyle implements ui.TextStyle { } List fontFamilies = [fontFamily]; if (fontFamilyFallback != null) { - fontFamilies.addAll(fontFamilies); + fontFamilies.addAll(fontFamilyFallback); } style['fontFamilies'] = fontFamilies; @@ -343,6 +343,10 @@ class SkParagraph implements ui.Paragraph { ui.BoxHeightStyle boxHeightStyle: ui.BoxHeightStyle.tight, ui.BoxWidthStyle boxWidthStyle: ui.BoxWidthStyle.tight, }) { + if (start < 0 || end < 0) { + return const []; + } + js.JsObject heightStyle; switch (boxHeightStyle) { case ui.BoxHeightStyle.tight: @@ -413,10 +417,21 @@ class SkParagraph implements ui.Paragraph { @override void layout(ui.ParagraphConstraints constraints) { assert(constraints.width != null); + + // Infinite width breaks layout, just use a very large number instead. + // TODO(het): Remove this once https://bugs.chromium.org/p/skia/issues/detail?id=9874 + // is fixed. + double width; + const double largeFiniteWidth = 1000000; + if (constraints.width.isInfinite) { + width = largeFiniteWidth; + } else { + width = constraints.width; + } // TODO(het): CanvasKit throws an exception when laid out with // a font that wasn't registered. try { - skParagraph.callMethod('layout', [constraints.width]); + skParagraph.callMethod('layout', [width]); } catch (e) { html.window.console.warn('CanvasKit threw an exception while laying ' 'out the paragraph. The font was "$_fontFamily". Exception:\n$e'); diff --git a/lib/web_ui/lib/src/ui/text.dart b/lib/web_ui/lib/src/ui/text.dart index b479db85c51c7..592b163616b0a 100644 --- a/lib/web_ui/lib/src/ui/text.dart +++ b/lib/web_ui/lib/src/ui/text.dart @@ -1587,9 +1587,15 @@ abstract class ParagraphBuilder { /// * `fontFamily`: The family name used to identify the font in text styles. /// If this is not provided, then the family name will be extracted from the font file. Future loadFontFromList(Uint8List list, {String fontFamily}) { - return _fontCollection.loadFontFromList(list, fontFamily: fontFamily).then( - (_) => _sendFontChangeMessage() - ); + if (engine.experimentalUseSkia) { + return engine.skiaFontCollection.loadFontFromList(list, fontFamily: fontFamily).then( + (_) => _sendFontChangeMessage() + ); + } else { + return _fontCollection.loadFontFromList(list, fontFamily: fontFamily).then( + (_) => _sendFontChangeMessage() + ); + } } final ByteData _fontChangeMessage = engine.JSONMessageCodec().encodeMessage({'type': 'fontsChange'});