Visitar URL original
<Pattern> Support (#110) · flutter/packages@16a1e61 · GitHub
Skip to content

Commit 16a1e61

Browse files
<Pattern> Support (#110)
1 parent 55d6f39 commit 16a1e61

29 files changed

Lines changed: 880 additions & 84 deletions

‎packages/vector_graphics/lib/src/listener.dart‎

Lines changed: 102 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
import 'dart:ui' as ui;
66
import 'dart:typed_data';
7-
87
import 'package:flutter/cupertino.dart';
98
import '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].
68102
class 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(

‎packages/vector_graphics/test/vector_graphics_test.dart‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ void main() {
5959
]),
6060
0,
6161
);
62-
codec.writeDrawPath(buffer, pathId, paintId);
62+
codec.writeDrawPath(buffer, pathId, paintId, null);
6363

6464
codec.decode(buffer.done(), listener);
6565

‎packages/vector_graphics_codec/lib/vector_graphics_codec.dart‎

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ class VectorGraphicsCodec {
7777
static const int _imageConfigTag = 46;
7878
static const int _drawImageTag = 47;
7979
static const int _beginCommandsTag = 48;
80+
static const int _patternTag = 49;
8081

8182
static const int _version = 1;
8283
static const int _magicNumber = 0x00882d62;
@@ -169,6 +170,9 @@ class VectorGraphicsCodec {
169170
case _drawImageTag:
170171
_readDrawImage(buffer, listener);
171172
continue;
173+
case _patternTag:
174+
_readPattern(buffer, listener);
175+
continue;
172176
default:
173177
throw StateError('Unknown type tag $type');
174178
}
@@ -200,13 +204,15 @@ class VectorGraphicsCodec {
200204
VectorGraphicsBuffer buffer,
201205
int pathId,
202206
int paintId,
207+
int? patternId,
203208
) {
204209
buffer._checkPhase(_CurrentSection.commands);
205210
buffer._addCommandsTag();
206211

207212
buffer._putUint8(_drawPathTag);
208213
buffer._putUint16(pathId);
209214
buffer._putUint16(paintId);
215+
buffer._putUint16(patternId ?? kMaxId);
210216
}
211217

212218
/// Encode a draw vertices command in the current buffer.
@@ -561,12 +567,14 @@ class VectorGraphicsCodec {
561567
VectorGraphicsBuffer buffer,
562568
int textId,
563569
int paintId,
570+
int? patternId,
564571
) {
565572
buffer._checkPhase(_CurrentSection.commands);
566573
buffer._addCommandsTag();
567574
buffer._putUint8(_drawTextTag);
568575
buffer._putUint16(textId);
569576
buffer._putUint16(paintId);
577+
buffer._putUint16(patternId ?? kMaxId);
570578
}
571579

572580
void writeClipPath(VectorGraphicsBuffer buffer, int path) {
@@ -582,6 +590,28 @@ class VectorGraphicsCodec {
582590
buffer._putUint8(_maskTag);
583591
}
584592

593+
int writePattern(
594+
VectorGraphicsBuffer buffer,
595+
double x,
596+
double y,
597+
double width,
598+
double height,
599+
Float64List transform,
600+
) {
601+
buffer._checkPhase(_CurrentSection.commands);
602+
assert(buffer._nextPatternId < kMaxId);
603+
final int id = buffer._nextPatternId;
604+
buffer._nextPatternId += 1;
605+
buffer._putUint8(_patternTag);
606+
buffer._putUint16(id);
607+
buffer._putFloat32(x);
608+
buffer._putFloat32(y);
609+
buffer._putFloat32(width);
610+
buffer._putFloat32(height);
611+
buffer._writeTransform(transform);
612+
return id;
613+
}
614+
585615
/// Write a new path to the [buffer], returing the identifier
586616
/// assigned to it.
587617
///
@@ -706,7 +736,11 @@ class VectorGraphicsCodec {
706736
) {
707737
final int pathId = buffer.getUint16();
708738
final int paintId = buffer.getUint16();
709-
listener?.onDrawPath(pathId, paintId);
739+
int? patternId = buffer.getUint16();
740+
if (patternId == kMaxId) {
741+
patternId = null;
742+
}
743+
listener?.onDrawPath(pathId, paintId, patternId);
710744
}
711745

712746
void _readDrawVertices(
@@ -773,7 +807,11 @@ class VectorGraphicsCodec {
773807
_ReadBuffer buffer, VectorGraphicsCodecListener? listener) {
774808
final int textId = buffer.getUint16();
775809
final int paintId = buffer.getUint16();
776-
listener?.onDrawText(textId, paintId);
810+
int? patternId = buffer.getUint16();
811+
if (patternId == kMaxId) {
812+
patternId = null;
813+
}
814+
listener?.onDrawText(textId, paintId, patternId);
777815
}
778816

779817
void _readImageConfig(
@@ -796,6 +834,16 @@ class VectorGraphicsCodec {
796834

797835
listener?.onDrawImage(id, x, y, width, height, transformLength);
798836
}
837+
838+
void _readPattern(_ReadBuffer buffer, VectorGraphicsCodecListener? listener) {
839+
final int patternId = buffer.getUint16();
840+
final double x = buffer.getFloat32();
841+
final double y = buffer.getFloat32();
842+
final double width = buffer.getFloat32();
843+
final double height = buffer.getFloat32();
844+
final Float64List? transform = buffer.getTransform();
845+
listener?.onPatternStart(patternId, x, y, width, height, transform!);
846+
}
799847
}
800848

801849
/// Implement this listener class to support decoding of vector_graphics binary
@@ -852,6 +900,7 @@ abstract class VectorGraphicsCodecListener {
852900
void onDrawPath(
853901
int pathId,
854902
int? paintId,
903+
int? patternId,
855904
);
856905

857906
/// Draw the vertices with the given [vertices] and optionally index buffer
@@ -916,6 +965,7 @@ abstract class VectorGraphicsCodecListener {
916965
void onDrawText(
917966
int textId,
918967
int paintId,
968+
int? patternId,
919969
);
920970

921971
/// An image has been decoded.
@@ -934,6 +984,13 @@ abstract class VectorGraphicsCodecListener {
934984
double height,
935985
Float64List? transform,
936986
);
987+
988+
/// A pattern has been decoded.
989+
///
990+
/// All subsequent pattern commands will refer to this pattern, until
991+
/// [onPatternFinished] is invoked.
992+
void onPatternStart(int patternId, double x, double y, double width,
993+
double height, Float64List transform);
937994
}
938995

939996
enum _CurrentSection {
@@ -985,6 +1042,9 @@ class VectorGraphicsBuffer {
9851042
/// The next image id to be used.
9861043
int _nextImageId = 0;
9871044

1045+
/// The next pattern id to be used.
1046+
int _nextPatternId = 0;
1047+
9881048
bool _addedCommandTag = false;
9891049

9901050
/// The current decoding phase.

0 commit comments

Comments
 (0)