Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[vector_graphics] Error handling enhancement #8061

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions packages/vector_graphics/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## 1.1.15
* Enhance error handling.

## 1.1.14

* Relaxes dependency constraint on vector_graphics_codec.
Expand Down
91 changes: 52 additions & 39 deletions packages/vector_graphics/lib/src/vector_graphics.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import 'dart:math' as math;
import 'dart:ui' as ui;

import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'package:vector_graphics_codec/vector_graphics_codec.dart';
Expand Down Expand Up @@ -279,8 +280,7 @@ class _PictureData {

@immutable
class _PictureKey {
const _PictureKey(
this.cacheKey, this.locale, this.textDirection, this.clipViewbox);
const _PictureKey(this.cacheKey, this.locale, this.textDirection, this.clipViewbox);

final Object cacheKey;
final Locale? locale;
Expand All @@ -300,16 +300,14 @@ class _PictureKey {
}

class _VectorGraphicWidgetState extends State<VectorGraphic> {
_PictureData? _pictureInfo;
_PictureData? _pictureData;
Object? _error;
StackTrace? _stackTrace;
Locale? locale;
TextDirection? textDirection;

static final Map<_PictureKey, _PictureData> _livePictureCache =
<_PictureKey, _PictureData>{};
static final Map<_PictureKey, Future<_PictureData>> _pendingPictures =
<_PictureKey, Future<_PictureData>>{};
static final Map<_PictureKey, _PictureData?> _livePictureCache = <_PictureKey, _PictureData?>{};
static final Map<_PictureKey, Future<_PictureData?>> _pendingPictures = <_PictureKey, Future<_PictureData?>>{};

@override
void didChangeDependencies() {
Expand All @@ -329,8 +327,8 @@ class _VectorGraphicWidgetState extends State<VectorGraphic> {

@override
void dispose() {
_maybeReleasePicture(_pictureInfo);
_pictureInfo = null;
_maybeReleasePicture(_pictureData);
_pictureData = null;
super.dispose();
}

Expand All @@ -345,29 +343,39 @@ class _VectorGraphicWidgetState extends State<VectorGraphic> {
}
}

Future<_PictureData> _loadPicture(
BuildContext context, _PictureKey key, BytesLoader loader) {
Future<_PictureData?> _loadPicture(BuildContext context, _PictureKey key, BytesLoader loader) {
if (_pendingPictures.containsKey(key)) {
return _pendingPictures[key]!;
}
final Future<_PictureData> result =
loader.loadBytes(context).then((ByteData data) {
return decodeVectorGraphics(
data,
locale: key.locale,
textDirection: key.textDirection,
clipViewbox: key.clipViewbox,
loader: loader,
onError: (Object error, StackTrace? stackTrace) {
return _handleError(
error,
stackTrace,
);
},
);
}).then((PictureInfo pictureInfo) {
return _PictureData(pictureInfo, 0, key);

final Future<_PictureData?> result = loader.loadBytes(context).then((ByteData data) async {
if (data.lengthInBytes == 0) {
debugPrint('_VectorGraphicWidgetState.decodeVectorGraphics: empty');
_handleError(const FormatException('Empty SVG xml content'), null);
return null;
} else {
return decodeVectorGraphics(data,
locale: key.locale,
textDirection: key.textDirection,
clipViewbox: key.clipViewbox,
loader: loader, onError: (Object error, StackTrace? stackTrace) {
debugPrintStack(
stackTrace: stackTrace, label: '_VectorGraphicWidgetState.decodeVectorGraphics.onError: $error');
_handleError(error, stackTrace);
});
}
}).onError((Object? error, StackTrace stackTrace) {
debugPrintStack(stackTrace: stackTrace, label: '_VectorGraphicWidgetState._loadPictureInfo.onError: $error');
_handleError(error ?? '', stackTrace);
return null;
}).then((PictureInfo? pictureInfo) {
if (pictureInfo == null) {
return null;
} else {
return _PictureData(pictureInfo, 0, key);
}
});

_pendingPictures[key] = result;
result.whenComplete(() {
_pendingPictures.remove(key);
Expand All @@ -376,6 +384,9 @@ class _VectorGraphicWidgetState extends State<VectorGraphic> {
}

void _handleError(Object error, StackTrace? stackTrace) {
if (!mounted) {
return;
}
setState(() {
_error = error;
_stackTrace = stackTrace;
Expand All @@ -385,20 +396,22 @@ class _VectorGraphicWidgetState extends State<VectorGraphic> {
void _loadAssetBytes() {
// First check if we have an avilable picture and use this immediately.
final Object loaderKey = widget.loader.cacheKey(context);
final _PictureKey key =
_PictureKey(loaderKey, locale, textDirection, widget.clipViewbox);
final _PictureKey key = _PictureKey(loaderKey, locale, textDirection, widget.clipViewbox);
final _PictureData? data = _livePictureCache[key];
if (data != null) {
data.count += 1;
setState(() {
_maybeReleasePicture(_pictureInfo);
_pictureInfo = data;
_maybeReleasePicture(_pictureData);
_pictureData = data;
});
return;
}
// If not, then check if there is a pending load.
final BytesLoader loader = widget.loader;
_loadPicture(context, key, loader).then((_PictureData data) {
_loadPicture(context, key, loader).then((_PictureData? data) {
if (data == null) {
return;
}
data.count += 1;

// The widget may have changed, requesting a new vector graphic before
Expand All @@ -411,8 +424,8 @@ class _VectorGraphicWidgetState extends State<VectorGraphic> {
_livePictureCache[key] = data;
}
setState(() {
_maybeReleasePicture(_pictureInfo);
_pictureInfo = data;
_maybeReleasePicture(_pictureData);
_pictureData = data;
});
});
}
Expand All @@ -421,7 +434,7 @@ class _VectorGraphicWidgetState extends State<VectorGraphic> {

@override
Widget build(BuildContext context) {
final PictureInfo? pictureInfo = _pictureInfo?.pictureInfo;
final PictureInfo? pictureInfo = _pictureData?.pictureInfo;

Widget child;
if (pictureInfo != null) {
Expand Down Expand Up @@ -452,22 +465,22 @@ class _VectorGraphicWidgetState extends State<VectorGraphic> {
if (_webRenderObject) {
child = _RawWebVectorGraphicWidget(
pictureInfo: pictureInfo,
assetKey: _pictureInfo!.key,
assetKey: _pictureData!.key,
colorFilter: widget.colorFilter,
opacity: widget.opacity,
);
} else if (widget.strategy == RenderingStrategy.raster) {
child = _RawVectorGraphicWidget(
pictureInfo: pictureInfo,
assetKey: _pictureInfo!.key,
assetKey: _pictureData!.key,
colorFilter: widget.colorFilter,
opacity: widget.opacity,
scale: scale,
);
} else {
child = _RawPictureVectorGraphicWidget(
pictureInfo: pictureInfo,
assetKey: _pictureInfo!.key,
assetKey: _pictureData!.key,
colorFilter: widget.colorFilter,
opacity: widget.opacity,
);
Expand Down
2 changes: 1 addition & 1 deletion packages/vector_graphics/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: vector_graphics
description: A vector graphics rendering package for Flutter using a binary encoding.
repository: https://github.com/flutter/packages/tree/main/packages/vector_graphics
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+vector_graphics%22
version: 1.1.14
version: 1.1.15

environment:
sdk: ^3.4.0
Expand Down
Loading