Skip to content

Commit 49c97ec

Browse files
author
Jonah Williams
authored
add a hidden debugging format --dump-debug (#136)
1 parent d1561e2 commit 49c97ec

File tree

4 files changed

+244
-0
lines changed

4 files changed

+244
-0
lines changed

packages/vector_graphics_compiler/bin/vector_graphics_compiler.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ final ArgParser argParser = ArgParser()
5555
abbr: 'k',
5656
help: 'The maximum number of SVG processing isolates to spawn at once. '
5757
'If not provided, defaults to the number of cores.')
58+
..addFlag('dump-debug',
59+
help:
60+
'Dump a human readable debugging format alongside the compiled asset',
61+
hide: true)
5862
..addOption(
5963
'output',
6064
abbr: 'o',
@@ -113,6 +117,7 @@ Future<void> main(List<String> args) async {
113117
final bool clippingOptimizerEnabled = results['optimize-clips'] == true;
114118
final bool overdrawOptimizerEnabled = results['optimize-overdraw'] == true;
115119
final bool tessellate = results['tessellate'] == true;
120+
final bool dumpDebug = results['dump-debug'] == true;
116121
final int concurrency;
117122
if (results.wasParsed('concurrency')) {
118123
concurrency = int.parse(results['concurrency'] as String);
@@ -131,6 +136,7 @@ Future<void> main(List<String> args) async {
131136
clippingOptimizerEnabled: clippingOptimizerEnabled,
132137
overdrawOptimizerEnabled: overdrawOptimizerEnabled,
133138
tessellate: tessellate,
139+
dumpDebug: dumpDebug,
134140
)) {
135141
exit(1);
136142
}
Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'dart:convert';
6+
import 'dart:typed_data';
7+
8+
import 'package:vector_graphics_codec/vector_graphics_codec.dart';
9+
10+
import 'paint.dart';
11+
12+
/// Write an unstable but human readable form of the vector graphics binary
13+
/// package intended to be used for debugging and development.
14+
Uint8List dumpToDebugFormat(Uint8List bytes) {
15+
const VectorGraphicsCodec codec = VectorGraphicsCodec();
16+
final _DebugVectorGraphicsListener listener = _DebugVectorGraphicsListener();
17+
final DecodeResponse response =
18+
codec.decode(bytes.buffer.asByteData(), listener);
19+
if (!response.complete) {
20+
codec.decode(bytes.buffer.asByteData(), listener, response: response);
21+
}
22+
return utf8.encode(listener.buffer.toString()) as Uint8List;
23+
}
24+
25+
String _intToColor(int value) {
26+
return 'Color(0x${(value & 0xFFFFFFFF).toRadixString(16).padLeft(8, '0')})';
27+
}
28+
29+
class _DebugVectorGraphicsListener extends VectorGraphicsCodecListener {
30+
final StringBuffer buffer = StringBuffer();
31+
32+
@override
33+
void onClipPath(int pathId) {
34+
buffer.writeln('DrawClip: id:$pathId');
35+
}
36+
37+
@override
38+
void onDrawImage(int imageId, double x, double y, double width, double height,
39+
Float64List? transform) {
40+
buffer.writeln(
41+
'DrawImage: id:$imageId (Rect.fromLTWH($x, $y, $width, $height), transform: $transform)');
42+
}
43+
44+
@override
45+
void onDrawPath(int pathId, int? paintId, int? patternId) {
46+
final String patternContext =
47+
patternId != null ? ', patternId:$patternId' : '';
48+
buffer.writeln('DrawPath: id:$pathId (paintId:$paintId$patternContext)');
49+
}
50+
51+
@override
52+
void onDrawText(int textId, int paintId, int? patternId) {
53+
buffer.writeln('DrawText: id:$textId ($paintId, $patternId)');
54+
}
55+
56+
@override
57+
void onDrawVertices(Float32List vertices, Uint16List? indices, int? paintId) {
58+
buffer.writeln('DrawVertices: $vertices ($indices, paintId: $paintId)');
59+
}
60+
61+
@override
62+
void onImage(int imageId, int format, Uint8List data) {
63+
buffer.writeln(
64+
'StoreImage: id:$imageId (format:$format, byteLength:${data.lengthInBytes}');
65+
}
66+
67+
@override
68+
void onLinearGradient(double fromX, double fromY, double toX, double toY,
69+
Int32List colors, Float32List? offsets, int tileMode, int id) {
70+
buffer.writeln(
71+
'StoreGradient: id:$id Linear(\n'
72+
' from: ($fromX, $fromY)\n'
73+
' to: ($toX, $toY)\n'
74+
' colors: [${colors.map(_intToColor).join(',')}]\n'
75+
' offsets: $offsets\n'
76+
' tileMode: ${TileMode.values[tileMode].name}',
77+
);
78+
}
79+
80+
@override
81+
void onMask() {
82+
buffer.writeln('BeginMask:');
83+
}
84+
85+
@override
86+
void onPaintObject({
87+
required int color,
88+
required int? strokeCap,
89+
required int? strokeJoin,
90+
required int blendMode,
91+
required double? strokeMiterLimit,
92+
required double? strokeWidth,
93+
required int paintStyle,
94+
required int id,
95+
required int? shaderId,
96+
}) {
97+
// Fill
98+
if (paintStyle == 0) {
99+
buffer.writeln(
100+
'StorePaint: id:$id Fill(${_intToColor(color)}, blendMode: ${BlendMode.values[blendMode].name}, shader: $shaderId)');
101+
} else {
102+
buffer.writeln(
103+
'StorePaint: id:$id Stroke(${_intToColor(color)}, strokeCap: $strokeCap, $strokeJoin: $strokeJoin, '
104+
'blendMode: ${BlendMode.values[blendMode].name}, strokeMiterLimit: $strokeMiterLimit, strokeWidth: $strokeWidth, shader: $shaderId)');
105+
}
106+
}
107+
108+
@override
109+
void onPathClose() {
110+
buffer.writeln(' close()');
111+
}
112+
113+
@override
114+
void onPathCubicTo(
115+
double x1, double y1, double x2, double y2, double x3, double y3) {
116+
buffer.writeln(' cubicTo(($x1, $y1), ($x2, $y2), ($x3, $y3)');
117+
}
118+
119+
@override
120+
void onPathFinished() {
121+
buffer.writeln('EndPath:');
122+
}
123+
124+
@override
125+
void onPathLineTo(double x, double y) {
126+
buffer.writeln(' lineTo($x, $y)');
127+
}
128+
129+
@override
130+
void onPathMoveTo(double x, double y) {
131+
buffer.writeln(' moveTo($x, $y)');
132+
}
133+
134+
@override
135+
void onPathStart(int id, int fillType) {
136+
buffer
137+
.writeln('PathStart: id:$id ${fillType == 0 ? 'nonZero' : 'evenOdd'}');
138+
}
139+
140+
@override
141+
void onPatternStart(int patternId, double x, double y, double width,
142+
double height, Float64List transform) {
143+
buffer.writeln(
144+
'StorePattern: $patternId (Rect.fromLTWH($x, $y, $width, $height), transform: $transform)');
145+
}
146+
147+
@override
148+
void onRadialGradient(
149+
double centerX,
150+
double centerY,
151+
double radius,
152+
double? focalX,
153+
double? focalY,
154+
Int32List colors,
155+
Float32List? offsets,
156+
Float64List? transform,
157+
int tileMode,
158+
int id) {
159+
final bool hasFocal = focalX != null;
160+
buffer.writeln(
161+
'StoreGradient: id:$id Radial(\n'
162+
'center: ($centerX, $centerY)\n'
163+
'radius: $radius\n'
164+
'${hasFocal ? 'focal: ($focalX, $focalY)\n' : ''}'
165+
'colors: [${colors.map(_intToColor).join(',')}]\n'
166+
'offsets: $offsets\n'
167+
'transform: $transform\n'
168+
'tileMode: ${TileMode.values[tileMode].name}',
169+
);
170+
}
171+
172+
@override
173+
void onRestoreLayer() {
174+
buffer.writeln('Restore:');
175+
}
176+
177+
@override
178+
void onSaveLayer(int paintId) {
179+
buffer.writeln('SaveLayer: $paintId');
180+
}
181+
182+
@override
183+
void onSize(double width, double height) {
184+
buffer.writeln('RecordSize: Size($width, $height)');
185+
}
186+
187+
@override
188+
void onTextConfig(
189+
String text,
190+
String? fontFamily,
191+
double x,
192+
double y,
193+
int fontWeight,
194+
double fontSize,
195+
Float64List? transform,
196+
int id,
197+
) {
198+
buffer.writeln(
199+
'RecordText: id:$id ($text, ($x, $y), weight: $fontWeight, size: $fontSize, family: $fontFamily, transform: $transform)');
200+
}
201+
}

packages/vector_graphics_compiler/lib/src/isolate_processor.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import 'dart:typed_data';
99
import 'package:pool/pool.dart';
1010

1111
import '../vector_graphics_compiler.dart';
12+
import 'debug_format.dart';
1213

1314
/// The isolate processor distributes SVG compilation across multiple isolates.
1415
class IsolateProcessor {
@@ -32,6 +33,7 @@ class IsolateProcessor {
3233
required bool clippingOptimizerEnabled,
3334
required bool overdrawOptimizerEnabled,
3435
required bool tessellate,
36+
required bool dumpDebug,
3537
}) async {
3638
_total = pairs.length;
3739
_current = 0;
@@ -44,6 +46,7 @@ class IsolateProcessor {
4446
clippingOptimizerEnabled: clippingOptimizerEnabled,
4547
overdrawOptimizerEnabled: overdrawOptimizerEnabled,
4648
tessellate: tessellate,
49+
dumpDebug: dumpDebug,
4750
libpathops: _libpathops,
4851
libtessellator: _libtessellator,
4952
).catchError((dynamic error, [StackTrace? stackTrace]) {
@@ -81,6 +84,7 @@ class IsolateProcessor {
8184
required bool clippingOptimizerEnabled,
8285
required bool overdrawOptimizerEnabled,
8386
required bool tessellate,
87+
required bool dumpDebug,
8488
required String? libpathops,
8589
required String? libtessellator,
8690
}) async {
@@ -105,6 +109,10 @@ class IsolateProcessor {
105109
enableOverdrawOptimizer: overdrawOptimizerEnabled,
106110
);
107111
File(pair.outputPath).writeAsBytesSync(bytes);
112+
if (dumpDebug) {
113+
final Uint8List debugBytes = dumpToDebugFormat(bytes);
114+
File(pair.outputPath + '.debug').writeAsBytesSync(debugBytes);
115+
}
108116
});
109117
_current++;
110118
print('Progress: $_current/$_total');

packages/vector_graphics_compiler/test/cli_test.dart

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ void main() {
2020
clippingOptimizerEnabled: false,
2121
overdrawOptimizerEnabled: false,
2222
tessellate: false,
23+
dumpDebug: false,
2324
);
2425
expect(result, isTrue);
2526
expect(output.existsSync(), isTrue);
@@ -29,4 +30,32 @@ void main() {
2930
}
3031
}
3132
});
33+
34+
test('Can dump debug format with isolate processor', () async {
35+
final File output = File('test_data/example.vec');
36+
final File outputDebug = File('test_data/example.vec.debug');
37+
try {
38+
final IsolateProcessor processor = IsolateProcessor(null, null, 4);
39+
final bool result = await processor.process(
40+
<Pair>[
41+
Pair('test_data/example.svg', output.path),
42+
],
43+
maskingOptimizerEnabled: false,
44+
clippingOptimizerEnabled: false,
45+
overdrawOptimizerEnabled: false,
46+
tessellate: false,
47+
dumpDebug: true,
48+
);
49+
expect(result, isTrue);
50+
expect(output.existsSync(), isTrue);
51+
expect(outputDebug.existsSync(), isTrue);
52+
} finally {
53+
if (output.existsSync()) {
54+
output.deleteSync();
55+
}
56+
if (outputDebug.existsSync()) {
57+
outputDebug.deleteSync();
58+
}
59+
}
60+
});
3261
}

0 commit comments

Comments
 (0)