From 4e5cc67c21a80f6dfd6e5decf233637dba9a6849 Mon Sep 17 00:00:00 2001 From: Edwin Hollen Date: Tue, 6 Oct 2026 17:34:02 +0000 Subject: [PATCH 1/4] [vector_graphics_codec] Add writePaintBlur and onPaintBlur support --- packages/vector_graphics_codec/CHANGELOG.md | 3 +- .../lib/vector_graphics_codec.dart | 23 ++++++++++ packages/vector_graphics_codec/pubspec.yaml | 2 +- .../test/vector_graphics_codec_test.dart | 46 +++++++++++++++++++ 4 files changed, 72 insertions(+), 2 deletions(-) diff --git a/packages/vector_graphics_codec/CHANGELOG.md b/packages/vector_graphics_codec/CHANGELOG.md index ca5ef61007c4..4357e1640162 100644 --- a/packages/vector_graphics_codec/CHANGELOG.md +++ b/packages/vector_graphics_codec/CHANGELOG.md @@ -1,5 +1,6 @@ -## NEXT +## 1.1.14 +* Adds support for encoding and decoding paint blur commands (`writePaintBlur` and `onPaintBlur`) for SVG filters. * Updates minimum supported SDK version to Flutter 3.41/Dart 3.11. ## 1.1.13 diff --git a/packages/vector_graphics_codec/lib/vector_graphics_codec.dart b/packages/vector_graphics_codec/lib/vector_graphics_codec.dart index 4b06b710984e..d8c5bdbdbc64 100644 --- a/packages/vector_graphics_codec/lib/vector_graphics_codec.dart +++ b/packages/vector_graphics_codec/lib/vector_graphics_codec.dart @@ -126,6 +126,7 @@ class VectorGraphicsCodec { static const int _textPositionTag = 50; static const int _updateTextPositionTag = 51; static const int _pathTagHalfPrecision = 52; + static const int _paintBlurTag = 53; static const int _version = 1; static const int _magicNumber = 0x00882d62; @@ -230,6 +231,9 @@ class VectorGraphicsCodec { case _updateTextPositionTag: _readUpdateTextPosition(buffer, listener); continue; + case _paintBlurTag: + _readPaintBlur(buffer, listener); + continue; default: throw StateError('Unknown type tag $type'); } @@ -959,6 +963,22 @@ class VectorGraphicsCodec { final Float64List? transform = buffer.getTransform(); listener?.onPatternStart(patternId, x, y, width, height, transform!); } + + /// Write a paint blur command to the buffer. + void writePaintBlur(VectorGraphicsBuffer buffer, int paintId, double sigmaX, double sigmaY) { + buffer._checkPhase(_CurrentSection.paints); + buffer._putUint8(_paintBlurTag); + buffer._putUint16(paintId); + buffer._putFloat32(sigmaX); + buffer._putFloat32(sigmaY); + } + + void _readPaintBlur(_ReadBuffer buffer, VectorGraphicsCodecListener? listener) { + final int paintId = buffer.getUint16(); + final double sigmaX = buffer.getFloat32(); + final double sigmaY = buffer.getFloat32(); + listener?.onPaintBlur(paintId, sigmaX, sigmaY); + } } /// Implement this listener class to support decoding of vector_graphics binary @@ -1028,6 +1048,9 @@ abstract class VectorGraphicsCodecListener { /// Prepare to draw a new mask, until the next [onRestoreLayer] command. void onMask(); + /// A paint blur has been decoded. + void onPaintBlur(int paintId, double sigmaX, double sigmaY) {} + /// A radial gradient shader has been parsed. /// /// [focalX] and [focalY] are either both `null` or `non-null`. diff --git a/packages/vector_graphics_codec/pubspec.yaml b/packages/vector_graphics_codec/pubspec.yaml index 333cda09d6c0..0c7ea03b65e6 100644 --- a/packages/vector_graphics_codec/pubspec.yaml +++ b/packages/vector_graphics_codec/pubspec.yaml @@ -2,7 +2,7 @@ name: vector_graphics_codec description: An encoding library for the binary format used in `package:vector_graphics` repository: https://github.com/flutter/packages/tree/main/packages/vector_graphics_codec issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+vector_graphics%22 -version: 1.1.13 +version: 1.1.14 environment: sdk: ^3.11.0 diff --git a/packages/vector_graphics_codec/test/vector_graphics_codec_test.dart b/packages/vector_graphics_codec/test/vector_graphics_codec_test.dart index be4ef2de29e7..f9dcbd0d1a40 100644 --- a/packages/vector_graphics_codec/test/vector_graphics_codec_test.dart +++ b/packages/vector_graphics_codec/test/vector_graphics_codec_test.dart @@ -125,6 +125,24 @@ void main() { ]); }); + test('Can encode and decode paint blur', () { + final buffer = VectorGraphicsBuffer(); + final listener = TestListener(); + final int paintId = codec.writeFill(buffer, 23, 0); + codec.writePaintBlur(buffer, paintId, 2.5, 3.5); + final int pathId = codec.writePath( + buffer, + Uint8List.fromList([ControlPointTypes.moveTo, ControlPointTypes.close]), + Float32List.fromList([1, 2]), + 0, + ); + codec.writeDrawPath(buffer, pathId, paintId, null); + + codec.decode(buffer.done(), listener); + + expect(listener.commands, contains(OnPaintBlur(paintId, 2.5, 3.5))); + }); + test('Basic message encode and decode with shaded path', () { final buffer = VectorGraphicsBuffer(); final listener = TestListener(); @@ -875,6 +893,12 @@ class TestListener extends VectorGraphicsCodecListener { ); } + @override + void onPaintBlur(int paintId, double sigmaX, double sigmaY) { + super.onPaintBlur(paintId, sigmaX, sigmaY); + commands.add(OnPaintBlur(paintId, sigmaX, sigmaY)); + } + @override void onPathClose() { commands.add(const OnPathClose()); @@ -1339,6 +1363,28 @@ class OnPaintObject { 'paintStyle: $paintStyle, id: $id, shaderId: $shaderId)'; } +@immutable +class OnPaintBlur { + const OnPaintBlur(this.paintId, this.sigmaX, this.sigmaY); + + final int paintId; + final double sigmaX; + final double sigmaY; + + @override + int get hashCode => Object.hash(paintId, sigmaX, sigmaY); + + @override + bool operator ==(Object other) => + other is OnPaintBlur && + other.paintId == paintId && + other.sigmaX == sigmaX && + other.sigmaY == sigmaY; + + @override + String toString() => 'OnPaintBlur(paintId: $paintId, sigmaX: $sigmaX, sigmaY: $sigmaY)'; +} + @immutable class OnPathClose { const OnPathClose(); From 25c84e3bae9ed45972a46f80386d6bd376982ca5 Mon Sep 17 00:00:00 2001 From: Edwin Hollen Date: Tue, 6 Oct 2026 19:43:40 +0000 Subject: [PATCH 2/4] [vector_graphics_codec] Add paint blur assertions and tighten test Add assertions for paintId, sigmaX, and sigmaY in writePaintBlur and assert the full decoded command sequence in vector_graphics_codec_test. --- .../lib/vector_graphics_codec.dart | 3 +++ .../test/vector_graphics_codec_test.dart | 20 ++++++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/packages/vector_graphics_codec/lib/vector_graphics_codec.dart b/packages/vector_graphics_codec/lib/vector_graphics_codec.dart index d8c5bdbdbc64..4f2a76cb0e8e 100644 --- a/packages/vector_graphics_codec/lib/vector_graphics_codec.dart +++ b/packages/vector_graphics_codec/lib/vector_graphics_codec.dart @@ -966,6 +966,9 @@ class VectorGraphicsCodec { /// Write a paint blur command to the buffer. void writePaintBlur(VectorGraphicsBuffer buffer, int paintId, double sigmaX, double sigmaY) { + assert(paintId >= 0 && paintId < kMaxId); + assert(sigmaX >= 0.0); + assert(sigmaY >= 0.0); buffer._checkPhase(_CurrentSection.paints); buffer._putUint8(_paintBlurTag); buffer._putUint16(paintId); diff --git a/packages/vector_graphics_codec/test/vector_graphics_codec_test.dart b/packages/vector_graphics_codec/test/vector_graphics_codec_test.dart index f9dcbd0d1a40..8d91eb891e43 100644 --- a/packages/vector_graphics_codec/test/vector_graphics_codec_test.dart +++ b/packages/vector_graphics_codec/test/vector_graphics_codec_test.dart @@ -140,7 +140,25 @@ void main() { codec.decode(buffer.done(), listener); - expect(listener.commands, contains(OnPaintBlur(paintId, 2.5, 3.5))); + expect(listener.commands, [ + OnPaintObject( + color: 23, + strokeCap: null, + strokeJoin: null, + blendMode: 0, + strokeMiterLimit: null, + strokeWidth: null, + paintStyle: 0, + id: paintId, + shaderId: null, + ), + OnPaintBlur(paintId, 2.5, 3.5), + OnPathStart(pathId, 0), + const OnPathMoveTo(1, 2), + const OnPathClose(), + const OnPathFinished(), + OnDrawPath(pathId, paintId, null), + ]); }); test('Basic message encode and decode with shaded path', () { From 1faa18dfb3f5f3d2ed9f58dc0127370d235034de Mon Sep 17 00:00:00 2001 From: Edwin Hollen Date: Tue, 13 Oct 2026 21:29:26 +0000 Subject: [PATCH 3/4] [vector_graphics_codec] Expand writePaintBlur docs and bump to 1.2.0 --- packages/vector_graphics_codec/CHANGELOG.md | 2 +- .../lib/vector_graphics_codec.dart | 12 ++++++++++-- packages/vector_graphics_codec/pubspec.yaml | 2 +- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/vector_graphics_codec/CHANGELOG.md b/packages/vector_graphics_codec/CHANGELOG.md index 4357e1640162..3874b733dafa 100644 --- a/packages/vector_graphics_codec/CHANGELOG.md +++ b/packages/vector_graphics_codec/CHANGELOG.md @@ -1,4 +1,4 @@ -## 1.1.14 +## 1.2.0 * Adds support for encoding and decoding paint blur commands (`writePaintBlur` and `onPaintBlur`) for SVG filters. * Updates minimum supported SDK version to Flutter 3.41/Dart 3.11. diff --git a/packages/vector_graphics_codec/lib/vector_graphics_codec.dart b/packages/vector_graphics_codec/lib/vector_graphics_codec.dart index 4f2a76cb0e8e..bfd1b69f6e9a 100644 --- a/packages/vector_graphics_codec/lib/vector_graphics_codec.dart +++ b/packages/vector_graphics_codec/lib/vector_graphics_codec.dart @@ -964,7 +964,13 @@ class VectorGraphicsCodec { listener?.onPatternStart(patternId, x, y, width, height, transform!); } - /// Write a paint blur command to the buffer. + /// Encode a Gaussian blur filter command for a paint object into [buffer]. + /// + /// The [paintId] must refer to a previously encoded paint object (from + /// [writeFill] or [writeStroke]). + /// + /// [sigmaX] and [sigmaY] specify the non-negative standard deviations of the + /// Gaussian blur kernel along the horizontal and vertical axes, respectively. void writePaintBlur(VectorGraphicsBuffer buffer, int paintId, double sigmaX, double sigmaY) { assert(paintId >= 0 && paintId < kMaxId); assert(sigmaX >= 0.0); @@ -1051,7 +1057,9 @@ abstract class VectorGraphicsCodecListener { /// Prepare to draw a new mask, until the next [onRestoreLayer] command. void onMask(); - /// A paint blur has been decoded. + /// A Gaussian blur filter for the paint object identified by [paintId] has + /// been decoded, with horizontal and vertical standard deviations [sigmaX] + /// and [sigmaY]. void onPaintBlur(int paintId, double sigmaX, double sigmaY) {} /// A radial gradient shader has been parsed. diff --git a/packages/vector_graphics_codec/pubspec.yaml b/packages/vector_graphics_codec/pubspec.yaml index 0c7ea03b65e6..180a5e0b2ad6 100644 --- a/packages/vector_graphics_codec/pubspec.yaml +++ b/packages/vector_graphics_codec/pubspec.yaml @@ -2,7 +2,7 @@ name: vector_graphics_codec description: An encoding library for the binary format used in `package:vector_graphics` repository: https://github.com/flutter/packages/tree/main/packages/vector_graphics_codec issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+vector_graphics%22 -version: 1.1.14 +version: 1.2.0 environment: sdk: ^3.11.0 From 9a4b6a5bb3d0bcfe39b765a9cc6d81ef0ab54bb0 Mon Sep 17 00:00:00 2001 From: Edwin Hollen Date: Wed, 14 Oct 2026 16:25:14 +0000 Subject: [PATCH 4/4] [vector_graphics_codec] Verify paintId against buffer._nextPaintId in writePaintBlur --- .../lib/vector_graphics_codec.dart | 5 ++++- .../test/vector_graphics_codec_test.dart | 12 ++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/packages/vector_graphics_codec/lib/vector_graphics_codec.dart b/packages/vector_graphics_codec/lib/vector_graphics_codec.dart index bfd1b69f6e9a..04d2f31ecd7f 100644 --- a/packages/vector_graphics_codec/lib/vector_graphics_codec.dart +++ b/packages/vector_graphics_codec/lib/vector_graphics_codec.dart @@ -972,7 +972,10 @@ class VectorGraphicsCodec { /// [sigmaX] and [sigmaY] specify the non-negative standard deviations of the /// Gaussian blur kernel along the horizontal and vertical axes, respectively. void writePaintBlur(VectorGraphicsBuffer buffer, int paintId, double sigmaX, double sigmaY) { - assert(paintId >= 0 && paintId < kMaxId); + assert( + paintId >= 0 && paintId < buffer._nextPaintId, + 'paintId ($paintId) must refer to a previously encoded paint object.', + ); assert(sigmaX >= 0.0); assert(sigmaY >= 0.0); buffer._checkPhase(_CurrentSection.paints); diff --git a/packages/vector_graphics_codec/test/vector_graphics_codec_test.dart b/packages/vector_graphics_codec/test/vector_graphics_codec_test.dart index 8d91eb891e43..011764fb667c 100644 --- a/packages/vector_graphics_codec/test/vector_graphics_codec_test.dart +++ b/packages/vector_graphics_codec/test/vector_graphics_codec_test.dart @@ -161,6 +161,18 @@ void main() { ]); }); + test('writePaintBlur asserts that paintId was previously encoded', () { + final buffer = VectorGraphicsBuffer(); + expect(() => codec.writePaintBlur(buffer, 0, 2.5, 3.5), throwsA(isA())); + + final int paintId = codec.writeFill(buffer, 23, 0); + expect( + () => codec.writePaintBlur(buffer, paintId + 1, 2.5, 3.5), + throwsA(isA()), + ); + expect(() => codec.writePaintBlur(buffer, -1, 2.5, 3.5), throwsA(isA())); + }); + test('Basic message encode and decode with shaded path', () { final buffer = VectorGraphicsBuffer(); final listener = TestListener();