diff --git a/third_party/packages/flutter_svg/CHANGELOG.md b/third_party/packages/flutter_svg/CHANGELOG.md index e28b584672a..7a21197a20e 100644 --- a/third_party/packages/flutter_svg/CHANGELOG.md +++ b/third_party/packages/flutter_svg/CHANGELOG.md @@ -1,5 +1,6 @@ -## NEXT +## 2.2.0 +* Exposes `renderingStrategy` in `SvgPicture` constructors. * Updates minimum supported SDK version to Flutter 3.27/Dart 3.6. ## 2.1.0 diff --git a/third_party/packages/flutter_svg/README.md b/third_party/packages/flutter_svg/README.md index e25ca450bfa..e08e10a8a49 100644 --- a/third_party/packages/flutter_svg/README.md +++ b/third_party/packages/flutter_svg/README.md @@ -130,10 +130,15 @@ import 'dart:ui' as ui; ``` The `SvgPicture` helps to automate this logic, and it provides some convenience -wrappers for getting assets from multiple sources. Unlike the `vector_graphics` -package, this package _does not render the data to an `Image` at any point_. -This carries a performance penalty for some common use cases, but also allows -for more flexibility around scaling. +wrappers for getting assets from multiple sources. + +This package now supports a render strategy setting, allowing certain +applications to achieve better performance when needed. By default, the +rendering uses the original `picture` mode, which retains full flexibility in +scaling. Alternatively, when using the `raster` strategy, the SVG data is +rendered into an `Image`, which is then drawn using drawImage. This approach may +sacrifice some flexibility—especially around resolution scaling—but can +significantly improve rendering performance in specific use cases. ## Precompiling and Optimizing SVGs diff --git a/third_party/packages/flutter_svg/lib/svg.dart b/third_party/packages/flutter_svg/lib/svg.dart index b1343f47b8e..9df47f20151 100644 --- a/third_party/packages/flutter_svg/lib/svg.dart +++ b/third_party/packages/flutter_svg/lib/svg.dart @@ -100,6 +100,7 @@ class SvgPicture extends StatelessWidget { 'The SVG theme must be set on the bytesLoader.') SvgTheme? theme, @Deprecated('This no longer does anything.') bool cacheColorFilter = false, + this.renderingStrategy = RenderingStrategy.picture, }); /// Instantiates a widget that renders an SVG picture from an [AssetBundle]. @@ -201,6 +202,7 @@ class SvgPicture extends StatelessWidget { @Deprecated('Use colorFilter instead.') ui.BlendMode colorBlendMode = ui.BlendMode.srcIn, @Deprecated('This no longer does anything.') bool cacheColorFilter = false, + this.renderingStrategy = RenderingStrategy.picture, }) : bytesLoader = SvgAssetLoader( assetName, packageName: package, @@ -265,6 +267,7 @@ class SvgPicture extends StatelessWidget { SvgTheme? theme, ColorMapper? colorMapper, http.Client? httpClient, + this.renderingStrategy = RenderingStrategy.picture, }) : bytesLoader = SvgNetworkLoader( url, headers: headers, @@ -325,6 +328,7 @@ class SvgPicture extends StatelessWidget { SvgTheme? theme, ColorMapper? colorMapper, @Deprecated('This no longer does anything.') bool cacheColorFilter = false, + this.renderingStrategy = RenderingStrategy.picture, }) : bytesLoader = SvgFileLoader( file, theme: theme, @@ -380,6 +384,7 @@ class SvgPicture extends StatelessWidget { SvgTheme? theme, ColorMapper? colorMapper, @Deprecated('This no longer does anything.') bool cacheColorFilter = false, + this.renderingStrategy = RenderingStrategy.picture, }) : bytesLoader = SvgBytesLoader( bytes, theme: theme, @@ -435,6 +440,7 @@ class SvgPicture extends StatelessWidget { SvgTheme? theme, ColorMapper? colorMapper, @Deprecated('This no longer does anything.') bool cacheColorFilter = false, + this.renderingStrategy = RenderingStrategy.picture, }) : bytesLoader = SvgStringLoader( string, theme: theme, @@ -526,6 +532,14 @@ class SvgPicture extends StatelessWidget { /// The color filter, if any, to apply to this widget. final ColorFilter? colorFilter; + /// Widget rendering strategy used to balance flexibility and performance. + /// + /// See the enum [RenderingStrategy] for details of all possible options and their common + /// use cases. + /// + /// Defaults to [RenderingStrategy.picture]. + final RenderingStrategy renderingStrategy; + @override Widget build(BuildContext context) { return createCompatVectorGraphic( @@ -540,6 +554,7 @@ class SvgPicture extends StatelessWidget { errorBuilder: errorBuilder, colorFilter: colorFilter, placeholderBuilder: placeholderBuilder, + strategy: renderingStrategy, clipViewbox: !allowDrawingOutsideViewBox, matchTextDirection: matchTextDirection, ); diff --git a/third_party/packages/flutter_svg/pubspec.yaml b/third_party/packages/flutter_svg/pubspec.yaml index d5dedf2a9c9..96d4f62b4e7 100644 --- a/third_party/packages/flutter_svg/pubspec.yaml +++ b/third_party/packages/flutter_svg/pubspec.yaml @@ -2,7 +2,7 @@ name: flutter_svg description: An SVG rendering and widget library for Flutter, which allows painting and displaying Scalable Vector Graphics 1.1 files. repository: https://github.com/flutter/packages/tree/main/third_party/packages/flutter_svg issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+flutter_svg%22 -version: 2.1.0 +version: 2.2.0 environment: sdk: ^3.6.0 diff --git a/third_party/packages/flutter_svg/test/widget_svg_test.dart b/third_party/packages/flutter_svg/test/widget_svg_test.dart index d0f60ad65c7..9d7c9a98174 100644 --- a/third_party/packages/flutter_svg/test/widget_svg_test.dart +++ b/third_party/packages/flutter_svg/test/widget_svg_test.dart @@ -7,6 +7,7 @@ import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:http/http.dart' as http; +import 'package:vector_graphics/vector_graphics_compat.dart'; class _TolerantComparator extends LocalFileComparator { _TolerantComparator(super.testFile); @@ -139,6 +140,28 @@ void main() { await _checkWidgetAndGolden(key, 'flutter_logo.string.png'); }); + testWidgets('SvgPicture.string with renderingStrategy', + (WidgetTester tester) async { + final GlobalKey key = GlobalKey(); + await tester.pumpWidget( + MediaQuery( + data: mediaQueryData, + child: RepaintBoundary( + key: key, + child: SvgPicture.string( + svgStr, + width: 100.0, + height: 100.0, + renderingStrategy: RenderingStrategy.raster, + ), + ), + ), + ); + + await tester.pumpAndSettle(); + await _checkWidgetAndGolden(key, 'flutter_logo.string.png'); + }); + testWidgets('SvgPicture.string with colorMapper', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); @@ -295,6 +318,25 @@ void main() { await _checkWidgetAndGolden(key, 'flutter_logo.memory.png'); }); + testWidgets('SvgPicture.memory with strategy', (WidgetTester tester) async { + final GlobalKey key = GlobalKey(); + await tester.pumpWidget( + MediaQuery( + data: mediaQueryData, + child: RepaintBoundary( + key: key, + child: SvgPicture.memory( + svgBytes, + renderingStrategy: RenderingStrategy.raster, + ), + ), + ), + ); + await tester.pumpAndSettle(); + + await _checkWidgetAndGolden(key, 'flutter_logo.memory.png'); + }); + testWidgets('SvgPicture.memory with colorMapper', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); @@ -334,6 +376,26 @@ void main() { await _checkWidgetAndGolden(key, 'flutter_logo.asset.png'); }); + testWidgets('SvgPicture.asset with strategy', (WidgetTester tester) async { + final FakeAssetBundle fakeAsset = FakeAssetBundle(); + final GlobalKey key = GlobalKey(); + await tester.pumpWidget( + MediaQuery( + data: mediaQueryData, + child: RepaintBoundary( + key: key, + child: SvgPicture.asset( + 'test.svg', + bundle: fakeAsset, + renderingStrategy: RenderingStrategy.raster, + ), + ), + ), + ); + await tester.pumpAndSettle(); + await _checkWidgetAndGolden(key, 'flutter_logo.asset.png'); + }); + testWidgets('SvgPicture.asset with colorMapper', (WidgetTester tester) async { final FakeAssetBundle fakeAsset = FakeAssetBundle(); final GlobalKey key = GlobalKey(); @@ -380,6 +442,33 @@ void main() { await _checkWidgetAndGolden(key, 'flutter_logo.asset.png'); }); + testWidgets('SvgPicture.asset DefaultAssetBundle with strategy', + (WidgetTester tester) async { + final FakeAssetBundle fakeAsset = FakeAssetBundle(); + final GlobalKey key = GlobalKey(); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: MediaQuery( + data: mediaQueryData, + child: DefaultAssetBundle( + bundle: fakeAsset, + child: RepaintBoundary( + key: key, + child: SvgPicture.asset( + 'test.svg', + semanticsLabel: 'Test SVG', + renderingStrategy: RenderingStrategy.raster, + ), + ), + ), + ), + ), + ); + await tester.pumpAndSettle(); + await _checkWidgetAndGolden(key, 'flutter_logo.asset.png'); + }); + testWidgets('SvgPicture.asset DefaultAssetBundle with colorMapper', (WidgetTester tester) async { final FakeAssetBundle fakeAsset = FakeAssetBundle(); @@ -425,6 +514,25 @@ void main() { await _checkWidgetAndGolden(key, 'flutter_logo.network.png'); }); + testWidgets('SvgPicture.network with strategy', (WidgetTester tester) async { + final GlobalKey key = GlobalKey(); + await tester.pumpWidget( + MediaQuery( + data: mediaQueryData, + child: RepaintBoundary( + key: key, + child: SvgPicture.network( + 'test.svg', + httpClient: FakeHttpClient(), + renderingStrategy: RenderingStrategy.raster, + ), + ), + ), + ); + await tester.pumpAndSettle(); + await _checkWidgetAndGolden(key, 'flutter_logo.network.png'); + }); + testWidgets('SvgPicture.network with colorMapper', (WidgetTester tester) async { final GlobalKey key = GlobalKey();