44
55import 'dart:ui' as ui;
66import 'dart:typed_data' ;
7-
87import 'package:flutter/cupertino.dart' ;
98import 'package:vector_graphics_codec/vector_graphics_codec.dart' ;
109
@@ -63,6 +62,41 @@ Future<PictureInfo> decodeVectorGraphics(
6362 return listener.toPicture ();
6463}
6564
65+ /// Pattern configuration to be used when creating ImageShader.
66+ class _PatternConfig {
67+ /// Constructs a [_PatternConfig] .
68+ _PatternConfig (this ._patternId, this ._width, this ._height, this ._transform);
69+
70+ /// This id will match any path or text element that has a non-null patternId.
71+ /// This number will also be used to map path and text elements to the
72+ /// correct [ImageShader] .
73+ final int _patternId;
74+
75+ /// This is the width of the pattern's viewbox in px.
76+ /// Values must be > = 1.
77+ final double _width;
78+
79+ /// The is the height of the pattern's viewbox in px.
80+ /// Values must be > = 1.
81+ final double _height;
82+
83+ /// This is the transform of the pattern that has been created from the children,
84+ /// of the original [ResolvedPatternNode] .
85+ final Float64List _transform;
86+ }
87+
88+ /// Pattern state that holds information about how to construct the pattern.
89+ class _PatternState {
90+ /// The canvas that the element should draw to for a given [PatternConfig] .
91+ ui.Canvas ? canvas;
92+
93+ /// The image shader created by the pattern.
94+ ui.ImageShader ? shader;
95+
96+ /// The recorder that will capture the newly created canvas.
97+ ui.PictureRecorder ? recorder;
98+ }
99+
66100/// A listener implementation for the vector graphics codec that converts the
67101/// format into a [ui.Picture] .
68102class FlutterVectorGraphicsListener extends VectorGraphicsCodecListener {
@@ -103,11 +137,13 @@ class FlutterVectorGraphicsListener extends VectorGraphicsCodecListener {
103137 final List <_TextConfig > _textConfig = < _TextConfig > [];
104138 final List <Future <ui.Image >> _pendingImages = < Future <ui.Image >> [];
105139 final Map <int , ui.Image > _images = < int , ui.Image > {};
106-
140+ final Map < int , _PatternState > _patterns = < int , _PatternState > {};
107141 ui.Path ? _currentPath;
108142 ui.Size _size = ui.Size .zero;
109143 bool _done = false ;
110144
145+ _PatternConfig ? _currentPattern;
146+
111147 static final ui.Paint _emptyPaint = ui.Paint ();
112148 static final ui.Paint _grayscaleDstInPaint = ui.Paint ()
113149 ..blendMode = ui.BlendMode .dstIn
@@ -141,13 +177,28 @@ class FlutterVectorGraphicsListener extends VectorGraphicsCodecListener {
141177 }
142178
143179 @override
144- void onDrawPath (int pathId, int ? paintId) {
180+ void onDrawPath (int pathId, int ? paintId, int ? patternId) async {
145181 final ui.Path path = _paths[pathId];
146182 ui.Paint ? paint;
147183 if (paintId != null ) {
148184 paint = _paints[paintId];
149185 }
150- _canvas.drawPath (path, paint ?? _emptyPaint);
186+ if (patternId != null ) {
187+ if (paintId != null ) {
188+ paint! .shader = _patterns[patternId]! .shader;
189+ } else {
190+ final ui.Paint newPaint = ui.Paint ();
191+ newPaint.shader = _patterns[patternId]! .shader;
192+ paint = newPaint;
193+ }
194+ }
195+ if (_currentPattern != null ) {
196+ _patterns[_currentPattern! ._patternId]!
197+ .canvas!
198+ .drawPath (path, paint ?? _emptyPaint);
199+ } else {
200+ _canvas.drawPath (path, paint ?? _emptyPaint);
201+ }
151202 }
152203
153204 @override
@@ -242,7 +293,13 @@ class FlutterVectorGraphicsListener extends VectorGraphicsCodecListener {
242293
243294 @override
244295 void onRestoreLayer () {
245- _canvas.restore ();
296+ if (_currentPattern != null ) {
297+ final int patternId = _currentPattern! ._patternId;
298+ onPatternFinished (_currentPattern, _patterns[patternId]! .recorder,
299+ _patterns[patternId]! .canvas! );
300+ } else {
301+ _canvas.restore ();
302+ }
246303 }
247304
248305 @override
@@ -261,6 +318,42 @@ class FlutterVectorGraphicsListener extends VectorGraphicsCodecListener {
261318 _canvas.clipPath (_paths[pathId]);
262319 }
263320
321+ @override
322+ void onPatternStart (int patternId, double x, double y, double width,
323+ double height, Float64List transform) {
324+ assert (_currentPattern == null );
325+ _currentPattern = _PatternConfig (patternId, width, height, transform);
326+ _patterns[patternId]! .recorder = ui.PictureRecorder ();
327+ final ui.Canvas newCanvas = ui.Canvas (_patterns[patternId]! .recorder! );
328+ newCanvas.clipRect (ui.Offset (x, y) & ui.Size (width, height));
329+ _patterns[patternId]! .canvas = newCanvas;
330+ }
331+
332+ /// Creates ImageShader for active pattern.
333+ void onPatternFinished (_PatternConfig ? currentPattern,
334+ ui.PictureRecorder ? patternRecorder, ui.Canvas canvas) {
335+ final FlutterVectorGraphicsListener patternListener =
336+ FlutterVectorGraphicsListener ._(
337+ canvas, patternRecorder! , _locale, _textDirection);
338+
339+ patternListener._size =
340+ ui.Size (currentPattern! ._width, currentPattern._height);
341+
342+ final PictureInfo pictureInfo = patternListener.toPicture ();
343+ _currentPattern = null ;
344+ final ui.Image image = pictureInfo.picture.toImageSync (
345+ currentPattern._width.round (), currentPattern._height.round ());
346+
347+ final ui.ImageShader pattern = ui.ImageShader (
348+ image,
349+ ui.TileMode .repeated,
350+ ui.TileMode .repeated,
351+ currentPattern._transform,
352+ );
353+
354+ _patterns[currentPattern._patternId]! .shader = pattern;
355+ }
356+
264357 @override
265358 void onLinearGradient (
266359 double fromX,
@@ -351,8 +444,11 @@ class FlutterVectorGraphicsListener extends VectorGraphicsCodecListener {
351444 }
352445
353446 @override
354- void onDrawText (int textId, int paintId) {
447+ void onDrawText (int textId, int paintId, int ? patternId) async {
355448 final ui.Paint paint = _paints[paintId];
449+ if (patternId != null ) {
450+ paint.shader = _patterns[patternId]! .shader;
451+ }
356452 final _TextConfig textConfig = _textConfig[textId];
357453 final ui.ParagraphBuilder builder = ui.ParagraphBuilder (
358454 ui.ParagraphStyle (
0 commit comments