avd.dart 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. // ignore_for_file: public_member_api_docs
  2. import 'dart:async';
  3. import 'dart:convert';
  4. import 'dart:typed_data';
  5. import 'dart:ui' show Picture;
  6. import 'package:flutter/services.dart' show AssetBundle;
  7. import 'package:flutter/widgets.dart';
  8. import 'package:xml/xml.dart';
  9. import './svg.dart';
  10. import 'src/avd/xml_parsers.dart';
  11. import 'src/avd_parser.dart';
  12. import 'src/picture_provider.dart';
  13. import 'src/picture_stream.dart';
  14. import 'src/vector_drawable.dart';
  15. final Avd avd = Avd._();
  16. class Avd {
  17. Avd._();
  18. Future<PictureInfo> avdPictureDecoder(
  19. Uint8List raw,
  20. bool allowDrawingOutsideOfViewBox,
  21. ColorFilter colorFilter,
  22. String key) async {
  23. final DrawableRoot avdRoot = await fromAvdBytes(raw, key);
  24. final Picture pic = avdRoot.toPicture(
  25. clipToViewBox: allowDrawingOutsideOfViewBox == true ? false : true,
  26. colorFilter: colorFilter);
  27. return PictureInfo(picture: pic, viewport: avdRoot.viewport.viewBoxRect);
  28. }
  29. Future<PictureInfo> avdPictureStringDecoder(
  30. String raw,
  31. bool allowDrawingOutsideOfViewBox,
  32. ColorFilter colorFilter,
  33. String key,
  34. ) async {
  35. final DrawableRoot avd = fromAvdString(raw, key);
  36. return PictureInfo(
  37. picture: avd.toPicture(
  38. clipToViewBox: allowDrawingOutsideOfViewBox == true ? false : true,
  39. colorFilter: colorFilter),
  40. viewport: avd.viewport.viewBoxRect,
  41. size: avd.viewport.size,
  42. );
  43. }
  44. Future<DrawableRoot> fromAvdBytes(Uint8List raw, String key) async {
  45. // TODO(dnfield): do utf decoding in another thread?
  46. // Might just have to live with potentially slow(ish) decoding, this is causing errors.
  47. // See: https://github.com/dart-lang/sdk/issues/31954
  48. // See: https://github.com/flutter/flutter/blob/bf3bd7667f07709d0b817ebfcb6972782cfef637/packages/flutter/lib/src/services/asset_bundle.dart#L66
  49. // if (raw.lengthInBytes < 20 * 1024) {
  50. return fromAvdString(utf8.decode(raw), key);
  51. // } else {
  52. // final String str =
  53. // await compute(_utf8Decode, raw, debugLabel: 'UTF8 decode for SVG');
  54. // return fromSvgString(str);
  55. // }
  56. }
  57. // String _utf8Decode(Uint8List data) {
  58. // return utf8.decode(data);
  59. // }
  60. /// Creates a [DrawableRoot] from a string of Android Vector Drawable data.
  61. DrawableRoot fromAvdString(String rawSvg, String key) {
  62. final XmlElement svg = XmlDocument.parse(rawSvg).rootElement;
  63. final DrawableViewport viewBox = parseViewBox(svg.attributes);
  64. final List<Drawable> children = svg.children
  65. .whereType<XmlElement>()
  66. .map((XmlElement child) => parseAvdElement(child, viewBox.viewBoxRect))
  67. .toList();
  68. // todo : style on root
  69. return DrawableRoot(
  70. getAttribute(svg.attributes, 'id', def: ''),
  71. viewBox,
  72. children,
  73. DrawableDefinitionServer(),
  74. null
  75. );
  76. }
  77. }
  78. /// Extends [VectorDrawableImage] to parse SVG data to [Drawable].
  79. class AvdPicture extends SvgPicture {
  80. const AvdPicture(PictureProvider pictureProvider,
  81. {Key key,
  82. bool matchTextDirection = false,
  83. bool allowDrawingOutsideViewBox = false,
  84. WidgetBuilder placeholderBuilder})
  85. : super(pictureProvider,
  86. key: key,
  87. matchTextDirection: matchTextDirection,
  88. allowDrawingOutsideViewBox: allowDrawingOutsideViewBox,
  89. placeholderBuilder: placeholderBuilder);
  90. AvdPicture.string(String bytes,
  91. {bool matchTextDirection = false,
  92. bool allowDrawingOutsideViewBox = false,
  93. WidgetBuilder placeholderBuilder,
  94. Color color,
  95. BlendMode colorBlendMode = BlendMode.srcIn,
  96. Key key})
  97. : this(
  98. StringPicture(
  99. allowDrawingOutsideViewBox == true
  100. ? avdStringDecoderOutsideViewBox
  101. : avdStringDecoder,
  102. bytes,
  103. colorFilter: _getColorFilter(color, colorBlendMode)),
  104. matchTextDirection: matchTextDirection,
  105. allowDrawingOutsideViewBox: allowDrawingOutsideViewBox,
  106. placeholderBuilder: placeholderBuilder,
  107. key: key);
  108. AvdPicture.asset(String assetName,
  109. {Key key,
  110. bool matchTextDirection = false,
  111. AssetBundle bundle,
  112. String package,
  113. bool allowDrawingOutsideViewBox = false,
  114. WidgetBuilder placeholderBuilder,
  115. Color color,
  116. BlendMode colorBlendMode = BlendMode.srcIn})
  117. : this(
  118. ExactAssetPicture(
  119. allowDrawingOutsideViewBox == true
  120. ? avdStringDecoderOutsideViewBox
  121. : avdStringDecoder,
  122. assetName,
  123. bundle: bundle,
  124. package: package,
  125. colorFilter: _getColorFilter(color, colorBlendMode)),
  126. matchTextDirection: matchTextDirection,
  127. allowDrawingOutsideViewBox: allowDrawingOutsideViewBox,
  128. placeholderBuilder: placeholderBuilder,
  129. key: key);
  130. static ColorFilter _getColorFilter(Color color, BlendMode colorBlendMode) =>
  131. color == null
  132. ? null
  133. : ColorFilter.mode(color, colorBlendMode ?? BlendMode.srcIn);
  134. static final PictureInfoDecoder<Uint8List> avdByteDecoder =
  135. (Uint8List bytes, ColorFilter colorFilter, String key) =>
  136. avd.avdPictureDecoder(bytes, false, colorFilter, key);
  137. static final PictureInfoDecoder<String> avdStringDecoder =
  138. (String data, ColorFilter colorFilter, String key) =>
  139. avd.avdPictureStringDecoder(data, false, colorFilter, key);
  140. static final PictureInfoDecoder<Uint8List> avdByteDecoderOutsideViewBox =
  141. (Uint8List bytes, ColorFilter colorFilter, String key) =>
  142. avd.avdPictureDecoder(bytes, true, colorFilter, key);
  143. static final PictureInfoDecoder<String> avdStringDecoderOutsideViewBox =
  144. (String data, ColorFilter colorFilter, String key) =>
  145. avd.avdPictureStringDecoder(data, true, colorFilter, key);
  146. }
  147. /// Creates a [DrawableRoot] from a string of SVG data.
  148. DrawableRoot fromAvdString(String rawSvg, Rect size) {
  149. final XmlElement svg = XmlDocument.parse(rawSvg).rootElement;
  150. final DrawableViewport viewBox = parseViewBox(svg.attributes);
  151. final List<Drawable> children = svg.children
  152. .whereType<XmlElement>()
  153. .map((XmlElement child) => parseAvdElement(child, size))
  154. .toList();
  155. // todo : style on root
  156. return DrawableRoot(
  157. getAttribute(svg.attributes, 'id', def: ''),
  158. viewBox,
  159. children,
  160. DrawableDefinitionServer(),
  161. null
  162. );
  163. }