Skip to content

Commit 2b3368e

Browse files
authored
Small bugs (#15)
* Small bugs * fix assert
1 parent 1138ecc commit 2b3368e

File tree

3 files changed

+55
-37
lines changed

3 files changed

+55
-37
lines changed

packages/vector_graphics_compiler/lib/src/svg/node.dart

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -178,13 +178,9 @@ class PathNode extends Node {
178178
'Do not use empty paints on leaf nodes',
179179
),
180180
assert(
181-
paint.fill != Fill.empty,
181+
paint.fill != Fill.empty || paint.stroke != Stroke.empty,
182182
'Do not use empty fills on leaf nodes',
183183
),
184-
assert(
185-
paint.stroke != Stroke.empty,
186-
'Do not use empty strokes on leaf nodes',
187-
),
188184
super(id: id, paint: paint);
189185

190186
/// The description of the geometry this leaf node draws.

packages/vector_graphics_compiler/lib/src/svg/parser.dart

Lines changed: 20 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -450,7 +450,10 @@ class _Elements {
450450
parserState.currentGroup?.transform,
451451
),
452452
);
453-
nextPath.fillType = parserState.parseFillRule('clip-rule')!;
453+
nextPath.fillType = parserState.parseFillRule(
454+
'clip-rule',
455+
'nonzero',
456+
)!;
454457
if (currentPath != null &&
455458
nextPath.fillType != currentPath.fillType) {
456459
currentPath = nextPath;
@@ -481,18 +484,6 @@ class _Elements {
481484
if (warningsAsErrors) {
482485
throw UnsupportedError(errorMessage);
483486
}
484-
// FlutterError.reportError(FlutterErrorDetails(
485-
// exception: UnsupportedError(errorMessage),
486-
// informationCollector: () => <DiagnosticsNode>[
487-
// ErrorDescription(
488-
// 'The <clipPath> element contained an unsupported child ${event.name}'),
489-
// if (parserState._key != null) ErrorDescription(''),
490-
// if (parserState._key != null)
491-
// DiagnosticsProperty<String>('Picture key', parserState._key),
492-
// ],
493-
// library: 'SVG',
494-
// context: ErrorDescription('in _Element.clipPath'),
495-
// ));
496487
}
497488
}
498489
}
@@ -938,6 +929,10 @@ class SvgParser {
938929
currentColor: parent.color,
939930
leaf: true,
940931
);
932+
if (paint.isEmpty) {
933+
// This shape does not draw anything. Treat the element as handled.
934+
return true;
935+
}
941936
final PathNode drawable = PathNode(
942937
path,
943938
id: getAttribute(attributes, 'id'),
@@ -1201,9 +1196,9 @@ class SvgParser {
12011196
Rect bounds, {
12021197
double? opacity,
12031198
}) {
1204-
final Shader? shader = definitions.getShader(iri);
1199+
final Shader? shader = definitions.getGradient<Shader>(iri);
12051200
if (shader == null) {
1206-
// reportMissingDef(key, iri, '_getDefinitionPaint');
1201+
_reportMissingDef(key, iri, '_getDefinitionPaint');
12071202
}
12081203

12091204
switch (paintingStyle) {
@@ -1265,7 +1260,6 @@ class SvgParser {
12651260
Rect bounds,
12661261
Stroke? parentStroke,
12671262
Color? currentColor,
1268-
bool leaf,
12691263
) {
12701264
final String? rawStroke = getAttribute(attributes, 'stroke', def: null);
12711265
final String? rawStrokeOpacity = getAttribute(
@@ -1297,7 +1291,7 @@ class SvgParser {
12971291
(parentStroke == null || parentStroke.isEmpty)) {
12981292
return null;
12991293
} else if (rawStroke == 'none') {
1300-
return leaf ? null : Stroke.empty;
1294+
return Stroke.empty;
13011295
}
13021296

13031297
Paint? definitionPaint;
@@ -1339,7 +1333,6 @@ class SvgParser {
13391333
Fill? parentFill,
13401334
Color? defaultFillColor,
13411335
Color? currentColor,
1342-
bool leaf,
13431336
) {
13441337
final String rawFill = attribute('fill', def: '')!;
13451338
final String? rawFillOpacity = attribute('fill-opacity', def: '1.0');
@@ -1358,9 +1351,6 @@ class SvgParser {
13581351
bounds,
13591352
opacity: opacity,
13601353
).fill;
1361-
if (definitionFill == Fill.empty && leaf) {
1362-
return null;
1363-
}
13641354
return definitionFill;
13651355
}
13661356

@@ -1377,7 +1367,7 @@ class SvgParser {
13771367
return null;
13781368
}
13791369
if (rawFill == 'none') {
1380-
return leaf ? null : Fill.empty;
1370+
return Fill.empty;
13811371
}
13821372

13831373
return Fill(
@@ -1408,8 +1398,9 @@ class SvgParser {
14081398
/// Parses a `fill-rule` attribute into a [PathFillType].
14091399
PathFillType? parseFillRule([
14101400
String attr = 'fill-rule',
1401+
String? def,
14111402
]) {
1412-
final String? rawFillRule = getAttribute(attributes, attr, def: null);
1403+
final String? rawFillRule = getAttribute(attributes, attr, def: def);
14131404
return parseRawFillRule(rawFillRule);
14141405
}
14151406

@@ -1478,17 +1469,13 @@ class SvgParser {
14781469
bounds,
14791470
parentStyle?.stroke,
14801471
currentColor,
1481-
leaf,
14821472
);
14831473
final Fill? fill = parseFill(
14841474
bounds,
14851475
parentStyle?.fill,
14861476
defaultFillColor,
14871477
currentColor,
1488-
leaf,
14891478
);
1490-
assert(!leaf || fill != Fill.empty);
1491-
assert(!leaf || stroke != Stroke.empty);
14921479
return Paint(
14931480
blendMode: _blendModes[getAttribute(attributes, 'mix-blend-mode')!],
14941481
stroke: stroke,
@@ -1650,21 +1637,22 @@ void _reportMissingDef(String? key, String? href, String methodName) {
16501637
].join('\n,'));
16511638
}
16521639

1653-
// TODO(dnfield): remove/fix this
16541640
class _DrawableDefinitionServer {
16551641
static const String emptyUrlIri = 'url(#)';
16561642
final Map<String, Node> _drawables = <String, Node>{};
16571643
final Map<String, Shader> _shaders = <String, Shader>{};
1644+
final Map<String, List<Path>> _clips = <String, List<Path>>{};
16581645

16591646
Node? getDrawable(String ref) => _drawables[ref];
1660-
Shader? getShader(String ref) => _shaders[ref];
1661-
List<Path>? getClipPath(String ref) => null;
1662-
T? getGradient<T extends Shader>(String ref) => null;
1647+
List<Path>? getClipPath(String ref) => _clips[ref];
1648+
T? getGradient<T extends Shader>(String ref) => _shaders[ref] as T;
16631649
void addGradient<T extends Shader>(String ref, T gradient) {
16641650
_shaders[ref] = gradient;
16651651
}
16661652

1667-
void addClipPath(String ref, List<Path> paths) {}
1653+
void addClipPath(String ref, List<Path> paths) {
1654+
_clips[ref] = paths;
1655+
}
16681656

16691657
void addDrawable(String ref, Node drawable) {
16701658
_drawables[ref] = drawable;

packages/vector_graphics_compiler/test/parser_test.dart

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,40 @@ import 'package:vector_graphics_compiler/vector_graphics_compiler.dart';
55
import 'test_svg_strings.dart';
66

77
void main() {
8+
test('Can parse an SVG with clips without crashing', () async {
9+
const String svg = '''
10+
<!-- Learn about this code on MDN: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/clipPath -->
11+
<svg viewBox="0 0 120 120" xmlns="http://www.w3.org/2000/svg">
12+
<defs>
13+
<clipPath id="myClip">
14+
<circle cx="30" cy="30" r="20"/>
15+
<circle cx="70" cy="70" r="20"/>
16+
</clipPath>
17+
</defs>
18+
19+
<rect x="10" y="10" width="100" height="100"
20+
clip-path="url(#myClip)"/>
21+
</svg>
22+
''';
23+
final VectorInstructions instructions = await parse(svg);
24+
// Depending on how we implement clipping, this number will change. For now,
25+
// just make it possible to actually parse the SVG without throwing an
26+
// exception.
27+
expect(instructions.commands.length, 1);
28+
});
29+
30+
test('Path with empty paint does not draw anything', () async {
31+
final VectorInstructions instructions = await parse(
32+
'''
33+
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 192 192" width="24">
34+
<path fill="none" d="M0 0h192v192H0z" />
35+
</svg>''',
36+
key: 'emptyPath',
37+
warningsAsErrors: true,
38+
);
39+
expect(instructions.commands.isEmpty, true);
40+
});
41+
842
test('Use circles test', () async {
943
final VectorInstructions instructions = await parse(
1044
simpleUseCircles,

0 commit comments

Comments
 (0)