Skip to content

Commit 78761ee

Browse files
authored
Refactor parsing, start blend mode support, improve attribute inheritence/processing (#29)
* Start supporting blends, major refactor * fix default stroke width, blend mode with masks, tests * better support for unordered elements. * docs * Test, save layer for opacity, make stops non-null
1 parent be4662f commit 78761ee

File tree

11 files changed

+972
-828
lines changed

11 files changed

+972
-828
lines changed

packages/vector_graphics/lib/src/listener.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,8 @@ class FlutterVectorGraphicsListener extends VectorGraphicsCodecListener {
113113
if (strokeMiterLimit != null && strokeMiterLimit != 4.0) {
114114
paint.strokeMiterLimit = strokeMiterLimit;
115115
}
116-
if (strokeWidth != null && strokeWidth != 1.0) {
116+
// SVG's default stroke width is 1.0. Flutter's default is 0.0.
117+
if (strokeWidth != null && strokeWidth != 0.0) {
117118
paint.strokeWidth = strokeWidth;
118119
}
119120
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import 'geometry/path.dart';
2+
import 'paint.dart';
3+
import 'vector_instructions.dart';
4+
5+
/// An interface for building up a stack of vector commands.
6+
class DrawCommandBuilder {
7+
final Map<Paint, int> _paints = <Paint, int>{};
8+
final Map<Path, int> _paths = <Path, int>{};
9+
final List<DrawCommand> _commands = <DrawCommand>[];
10+
11+
int _getOrGenerateId<T>(T object, Map<T, int> map) =>
12+
map.putIfAbsent(object, () => map.length);
13+
14+
/// Add a save layer to the command stack.
15+
void addSaveLayer(Paint paint) {
16+
assert(paint.fill!.color != null);
17+
18+
final int paintId = _getOrGenerateId(paint, _paints);
19+
_commands.add(DrawCommand(
20+
DrawCommandType.saveLayer,
21+
paintId: paintId,
22+
));
23+
}
24+
25+
/// Add a restore to the command stack.
26+
void restore() {
27+
_commands.add(const DrawCommand(DrawCommandType.restore));
28+
}
29+
30+
/// Adds a clip to the command stack.
31+
void addClip(Path path) {
32+
final int pathId = _getOrGenerateId(path, _paths);
33+
_commands.add(DrawCommand(DrawCommandType.clip, objectId: pathId));
34+
}
35+
36+
/// Adds a mask to the command stack.
37+
void addMask() {
38+
_commands.add(const DrawCommand(DrawCommandType.mask));
39+
}
40+
41+
/// Add a path to the current draw command stack
42+
void addPath(Path path, Paint paint, String? debugString) {
43+
final int pathId = _getOrGenerateId(path, _paths);
44+
final int paintId = _getOrGenerateId(paint, _paints);
45+
_commands.add(DrawCommand(
46+
DrawCommandType.path,
47+
objectId: pathId,
48+
paintId: paintId,
49+
debugString: debugString,
50+
));
51+
}
52+
53+
/// Create a new [VectorInstructions] with the given width and height.
54+
VectorInstructions toInstructions(double width, double height) {
55+
return VectorInstructions(
56+
width: width,
57+
height: height,
58+
paints: _paints.keys.toList(),
59+
paths: _paths.keys.toList(),
60+
commands: _commands,
61+
);
62+
}
63+
}

packages/vector_graphics_compiler/lib/src/paint.dart

Lines changed: 7 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ class LinearGradient extends Shader {
109109
required this.from,
110110
required this.to,
111111
required this.colors,
112-
this.offsets,
112+
required this.offsets,
113113
required this.tileMode,
114114
this.unitMode = GradientUnitMode.objectBoundingBox,
115115
this.transform,
@@ -126,7 +126,7 @@ class LinearGradient extends Shader {
126126

127127
/// The positions to apply [colors] to. If specified, must be the same length
128128
/// as [colors]. If not specified, [colors] must be two colors.
129-
final List<double>? offsets;
129+
final List<double> offsets;
130130

131131
/// Specifies the meaning of [from] and [to].
132132
final TileMode tileMode;
@@ -178,7 +178,7 @@ class LinearGradient extends Shader {
178178

179179
@override
180180
int get hashCode => Object.hash(from, to, Object.hashAll(colors),
181-
Object.hashAll(offsets ?? <double>[]), tileMode, unitMode);
181+
Object.hashAll(offsets), tileMode, unitMode);
182182

183183
@override
184184
bool operator ==(Object other) {
@@ -249,7 +249,7 @@ class RadialGradient extends Shader {
249249
required this.center,
250250
required this.radius,
251251
required this.colors,
252-
this.offsets,
252+
required this.offsets,
253253
required this.tileMode,
254254
this.transform,
255255
this.focalPoint,
@@ -267,7 +267,7 @@ class RadialGradient extends Shader {
267267

268268
/// The positions to apply [colors] to. If specified, must be the same length
269269
/// as [colors]. If not specified, [colors] must be two colors.
270-
final List<double>? offsets;
270+
final List<double> offsets;
271271

272272
/// Specifies the meaning of [from] and [to].
273273
final TileMode tileMode;
@@ -333,15 +333,8 @@ class RadialGradient extends Shader {
333333
}
334334

335335
@override
336-
int get hashCode => Object.hash(
337-
center,
338-
radius,
339-
Object.hashAll(colors),
340-
Object.hashAll(offsets ?? <double>[]),
341-
tileMode,
342-
transform,
343-
focalPoint,
344-
unitMode);
336+
int get hashCode => Object.hash(center, radius, Object.hashAll(colors),
337+
Object.hashAll(offsets), tileMode, transform, focalPoint, unitMode);
345338

346339
@override
347340
bool operator ==(Object other) {
@@ -392,9 +385,6 @@ class Paint {
392385
this.fill,
393386
});
394387

395-
/// An empty paint object, in which all attributes are `null`.
396-
static const Paint empty = Paint();
397-
398388
/// The Porter-Duff algorithm to use when compositing this painting object
399389
/// with any objects painted under it.
400390
///
@@ -413,28 +403,6 @@ class Paint {
413403
/// followed by stroke.
414404
final Fill? fill;
415405

416-
/// Returns a paint object that merges the properties of the parent paint
417-
/// into this one.
418-
///
419-
/// If parent is null, returns this.
420-
Paint applyParent(Paint? parent, {bool leaf = false}) {
421-
if (parent == null) {
422-
return this;
423-
}
424-
final Fill? defaultFill =
425-
leaf && parent.fill == Fill.empty ? null : parent.fill;
426-
final Stroke? defaultStroke =
427-
leaf && parent.stroke == Stroke.empty ? null : parent.stroke;
428-
return Paint(
429-
blendMode: blendMode ?? parent.blendMode,
430-
stroke: stroke?.applyParent(parent.stroke) ?? defaultStroke,
431-
fill: fill?.applyParent(parent.fill) ?? defaultFill,
432-
);
433-
}
434-
435-
/// Whether this paint has a stroke or fill.
436-
bool get isEmpty => (fill?.isEmpty ?? true) && (stroke?.isEmpty ?? true);
437-
438406
@override
439407
int get hashCode => Object.hash(blendMode, stroke, fill);
440408

@@ -502,9 +470,6 @@ class Stroke {
502470
this.width,
503471
});
504472

505-
/// A stroke object that has no attributes set.
506-
static const Stroke empty = Stroke();
507-
508473
/// The color to use for this stroke.
509474
///
510475
/// Defaults to [Color.opaqueBlack].
@@ -533,24 +498,6 @@ class Stroke {
533498
/// The width of the stroke, if [style] is [PaintingStyle.stroke].
534499
final double? width;
535500

536-
/// Whether this object is equal to [Stroke.empty].
537-
bool get isEmpty => this == Stroke.empty;
538-
539-
/// Applies heritable values from the parent to this stroke.
540-
Stroke applyParent(Stroke? parent) {
541-
if (parent == null || isEmpty) {
542-
return this;
543-
}
544-
return Stroke(
545-
color: color ?? parent.color,
546-
shader: shader ?? parent.shader,
547-
cap: cap ?? parent.cap,
548-
join: join ?? parent.join,
549-
miterLimit: miterLimit ?? parent.miterLimit,
550-
width: width ?? parent.width,
551-
);
552-
}
553-
554501
/// Creates a string with the dart:ui code to represent this stroke and any
555502
/// shaders it contains as a ui.Paint.
556503
String toFlutterPaintString(String shaderName, String paintName,
@@ -644,9 +591,6 @@ class Fill {
644591
this.shader,
645592
});
646593

647-
/// A fill object that has no attributes set.
648-
static const Fill empty = Fill();
649-
650594
/// The color to use for this stroke.
651595
///
652596
/// Defaults to [Color.opaqueBlack].
@@ -658,20 +602,6 @@ class Fill {
658602
/// gradient.
659603
final Shader? shader;
660604

661-
/// Applies heritable values from the parent to this fill.
662-
Fill applyParent(Fill? parent) {
663-
if (parent == null || isEmpty) {
664-
return this;
665-
}
666-
return Fill(
667-
color: color ?? parent.color,
668-
shader: shader ?? parent.shader,
669-
);
670-
}
671-
672-
/// Whether this fill has any attributes set.
673-
bool get isEmpty => this == Fill.empty;
674-
675605
/// Creates a string with the dart:ui code to represent this fill and any
676606
/// shaders it contains as a ui.Paint.
677607
String toFlutterPaintString(String shaderName, String paintName,

0 commit comments

Comments
 (0)