Repository navigation
[various] Support SVG filters (blur, offset, feMerge) - #11909
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces support for SVG filters, specifically blur and offset, and alpha masks across the vector_graphics, vector_graphics_codec, and vector_graphics_compiler packages. It updates the parser to handle , feGaussianBlur, feOffset, and feMerge elements, adds encoding/decoding for paint blur commands, and implements rendering support via ImageFilter.blur. The review feedback highlights several areas for improvement: handling comma-separated values in stdDeviation, defaulting omitted in attributes on feMergeNode, preserving the original element's opacity when applying isSourceAlpha filters, and implementing cycle detection during recursive filter tracing to prevent stack overflows.
0453cc0 to
5955e54
Compare
5955e54 to
5b44d76
Compare
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request adds support for SVG filters (specifically Gaussian blur) and alpha masks (mask-type=alpha) across the vector graphics packages, including updates to the codec, compiler, and renderer, along with an interactive gallery example. Feedback on the changes highlights a redundant check in the filter parser, a limitation in parsing filters where feMerge is not the final operation, and incomplete support for multi-layer filters on group nodes (ParentNode).
5b44d76 to
a6f0287
Compare
|
/gemini review |
a6f0287 to
ce01413
Compare
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces support for SVG filters (specifically Gaussian blur) and alpha masks across the vector graphics packages. Key changes include adding a paint blur command to the codec, parsing filter primitives (feGaussianBlur, feOffset, feMerge) in the compiler, resolving filter layers in the resolver visitor, and applying image filters to paints in the renderer. Additionally, the example app is updated with a filter and mask gallery. The review feedback highlights three areas for improvement: using the ui. prefix for ImageFilter to prevent compilation errors, resolving a transformation mismatch in visitTextPositionNode that could cause layout misalignment, and using ByteData.sublistView instead of asByteData() for safer byte buffer handling.
There was a problem hiding this comment.
Code Review
This pull request adds support for SVG filters (specifically Gaussian blur, offset, and merge) and alpha masks across the vector graphics packages, including the compiler, codec, and runtime renderer. It also updates the example application with a gallery demonstrating these features. The reviewer feedback suggests handling trailing delimiters in stdDeviation parsing to prevent invalidating the filter, and combining chained Gaussian blurs using the square root of the sum of squares rather than linear addition.
|
/gemini review |
ce01413 to
53a75e8
Compare
There was a problem hiding this comment.
Code Review
This pull request introduces support for SVG filters, specifically blur and multi-layer filters, and alpha masks (mask-type=alpha) across the vector_graphics package, compiler, and codec. It also adds a filter and mask gallery to the example application along with corresponding tests. Review feedback points out three areas for improvement: handling single-layer filters with offsets at the TextPositionNode level to avoid text positioning bugs, ensuring single-layer filters with isSourceAlpha enabled are not ignored during parsing, and using the ui. prefix for ImageFilter.blur in the listener for import consistency.
f4e0eff to
98a6f03
Compare
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request adds support for SVG filters (such as Gaussian blur and offset) and alpha masks across the vector graphics packages. It updates the compiler to parse and resolve these filters, adds encoding and decoding support in the codec, and implements paint blur rendering in the listener. An issue was identified in the resolver where multi-layer filters on text nodes only process the first layer, ignoring subsequent layers, and a fix was suggested to resolve all layers into a parent node.
98a6f03 to
d02df90
Compare
|
/gemini review |
d02df90 to
f51ca1b
Compare
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces support for SVG filters (specifically Gaussian blur, offsets, and multi-layer merging) and alpha masks across the vector graphics packages. Key changes include codec updates to handle paint blur commands, XML parsing for filter and mask attributes, and resolving these filters into paint properties or layers during compilation. Feedback on these changes points out a missing dart:math import in the parser, opportunities to optimize performance by caching a regular expression and avoiding redundant node recreation when the current filter layer has no visual effect, and a suggestion to refactor duplicated paint-creation logic into a helper method.
There was a problem hiding this comment.
Code Review
This pull request introduces support for SVG filters (such as blur and offset) and alpha masks across the vector_graphics, vector_graphics_codec, and vector_graphics_compiler packages. It adds the capability to parse, encode, decode, and render these filters and masks, along with corresponding tests and gallery examples. Feedback on the changes suggests defaulting parsedX and parsedY to 0.0 when stdDeviation is omitted on a <feGaussianBlur> element to comply with SVG specifications and avoid breaking the filter reference chain.
f51ca1b to
c525511
Compare
|
/gemini review |
#13025) [vector_graphics_compiler] Support SVG alpha masks (`mask-type="alpha"`) Fixes flutter/flutter#158734 This PR adds support for SVG alpha masks (`mask-type="alpha"` and `style="mask-type: alpha"`) in `vector_graphics_compiler`, split out from #11909 per review feedback. ### Summary of Changes * **SVG Parser & AST (`vector_graphics_compiler`)**: * Parses the `mask-type` attribute (and inline `style="mask-type: ..."` property) on `<mask>` elements in `SvgParser`. * Propagates `isAlphaMask` through `ResolvedMaskNode` and `MaskNode`. * Emits `BlendMode.dstIn` for alpha masks instead of `BlendMode.srcIn` with a luminance-to-alpha color filter matrix (`BlendMode.modulate`). * **MaskingOptimizer Compatibility**: * Updates `MaskingOptimizer` so single-path masks using gradients with translucent stops (`stop-opacity < 1.0`) are preserved rather than replaced with solid geometry intersection (which previously discarded the gradient's alpha channel). ## Pre-Review Checklist **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. [^1]: Regular contributors who have demonstrated familiarity with the repository guidelines only need to comment if the PR is not auto-exempted by repo tooling. TAG=agy CONV=1bad96cc-81aa-438f-98f6-cb909289144a
…lur commands (#13148) Adds a new `_paintBlurTag` command (`writePaintBlur` / `onPaintBlur`) to `vector_graphics_codec` (`1.2.0`) to support encoding and decoding Gaussian blur image filters (`sigmaX`, `sigmaY`) alongside paint records. This is split out from #11909 so the codec changes can land and be published first. Part of flutter/flutter#158592 ## Pre-Review Checklist
6ec752f to
bf5d899
Compare
|
Rebased onto |
|
I put this in review officially and removed myself as a reviewer, @walley892 is working on this one as the first reviewer. |
There was a problem hiding this comment.
Code Review
This pull request adds support for SVG filters (feGaussianBlur, feOffset, feMerge, and feMergeNode) to the vector_graphics and vector_graphics_compiler packages. The changes introduce SVG filter parsing, update paint attributes to store blur parameters, scale blur standard deviations based on transform scale factors, and adjust clipping, masking, and overdraw optimizers to handle blurred paths correctly. The binary encoder and decoder are also updated to support paint blur instructions, package versions are bumped, and comprehensive tests are added. There are no review comments, and I have no feedback to provide.
7b02dc3 to
aee6249
Compare
walley892
left a comment
There was a problem hiding this comment.
Still waiting on the codec change to hit pub.dev to run CI, but I've got a few comments to start us off
| return; | ||
| } | ||
|
|
||
| static void filter(SvgParser parserState, bool warningsAsErrors) { |
There was a problem hiding this comment.
Right now, this supports feMerge, feGaussianBlur, feOffset and feMergeNode, and ignores other filter primitives.
This creates a regression compared to today's behavior when mixing supported and unsupported primitives. For example:
<svg width="140" height="140" viewBox="0 0 140 140" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_d_1_2)">
<rect x="20" y="16" width="100" height="100" rx="12" fill="#4F46E5"/>
</g>
<defs>
<filter id="filter0_d_1_2" x="0" y="0" width="140" height="140" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="5"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1_2"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_1_2" result="shape"/>
</filter>
</defs>
</svg>
Should render as a drop shadow, but instead just creates a blurred rect
Maybe if a filter contains unsupported primitives - we just fail it and emit an error?
There was a problem hiding this comment.
Thanks, that makes sense. I updated filter to fail and emit an unhandled element error if it contains unsupported primitives, and added a test for it.
| repository: https://github.com/flutter/packages/tree/main/packages/vector_graphics | ||
| issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+vector_graphics%22 | ||
| version: 1.2.5 | ||
| version: 1.2.6 |
There was a problem hiding this comment.
Let's make this a full minor version bump - 1.3.0
There was a problem hiding this comment.
Done, bumped vector_graphics to 1.3.0.
| if (parserState._currentStartElement?.isSelfClosing ?? false) { | ||
| return; | ||
| } |
There was a problem hiding this comment.
Thanks, it's not needed anymore, it was an unrelated guard for self closing clipPath elements. I removed it.
| final children = <Node>[]; | ||
| for (final SvgFilterLayer layer in filter.layers) { | ||
| children.add(_resolveParentNodeForLayer(parentNode, nextTransform, layer)); | ||
| } | ||
| return ParentNode(SvgAttributes.empty, children: children); |
There was a problem hiding this comment.
This creates a new savelayer for each layer, which causes the opacity to be applied to each layer separately instead of to the result of the entire filter. For example:
<svg width="140" height="140" viewBox="0 0 140 140" xmlns="http://www.w3.org/2000/svg">
<filter id="drop" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="3" result="blur"/>
<feOffset in="blur" dx="10" dy="10" result="shadow"/>
<feMerge>
<feMergeNode in="shadow"/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
<g opacity="0.5" filter="url(#drop)">
<rect x="20" y="20" width="90" height="90" fill="#DC2626"/>
</g>
</svg>
There was a problem hiding this comment.
Thanks, I realized I didn't have a test for this either. I updated visitParentNode to handle that case, and a test to cover it.
867b452 to
23a9dab
Compare
|
@walley892 it looks like vector_graphics_codec 1.2.0 is held up because the release workflow run (https://github.com/flutter/packages/actions/runs/38633635933) hit a timeout (flutter/flutter#194870). |
flar
left a comment
There was a problem hiding this comment.
I apparently never submitted these review comments.
| @override | ||
| void onPaintBlur(int paintId, double sigmaX, double sigmaY) { | ||
| final clampedX = sigmaX < 0.0 ? 0.0 : sigmaX; | ||
| final clampedY = sigmaY < 0.0 ? 0.0 : sigmaY; |
There was a problem hiding this comment.
These 2 lines can protect against NaN values by reversing the comparison.
sigma > 0.0 ? sigma : 0.0 produces 0.0 for NaN
sigma < 0.0 ? 0.0 : sigma produces NaN for NaN.
NaN values become a NOP here instead of being passed along to future code.
There was a problem hiding this comment.
Good catch, switched both checks to > 0.0 so NaN clamps to 0.0.
| expect(drawPath.memberName, #drawPath); | ||
| final paint = drawPath.positionalArguments[1] as ui.Paint; | ||
| expect(paint.imageFilter, isNull); | ||
| }); |
There was a problem hiding this comment.
Add tests for one or both being NaN.
There was a problem hiding this comment.
Added tests covering NaN for sigmaX, sigmaY, and both.
walley892
left a comment
There was a problem hiding this comment.
LGTM assuming CI passes
|
Rebased onto @walley892 @flar could one of you re-trigger CI (and add |
I don't have a changes requested review on here. |
|
autosubmit label was removed for flutter/packages/11909, because This PR has not met approval requirements for merging. Changes were requested by {gaaclarke}, please make the needed changes and resubmit this PR.
|
[various] Support SVG filters (blur, offset, feMerge)
Fixes flutter/flutter#158592
This PR introduces support for basic SVG filters (
feGaussianBlur,feOffset, andfeMerge) to thevector_graphicsecosystem. (Alpha mask support has been split out into a separate PR per review feedback.)Key Features:
feGaussianBlur,feOffset, andfeMergeinvector_graphics_compiler.vector_graphics_codecto support encoding and decoding paint blurs.vector_graphicsto render paint blurs using Flutter'sui.ImageFilter.blur.SourceAlphafilters to preserve opacity variations in gradient stops by mapping gradient colors to black while maintaining their alpha values.Implementation Details:
SourceGraphic/SourceAlphato determine the necessary rendering layers.feMerge) by duplicating the target rendering nodes for each layer in the AST.TextPositionNodelevel (rather than leafTextNodes) to maintain correct text chunk alignment and cursor positioning.SourceAlphastate down the tree.blurSigmaX/blurSigmaYwhenTessellationVisitorandPathOpsconvertPathNodes toVerticesNodes.MaskingOptimizer,ClippingOptimizer, andOverdrawOptimizerfrom collapsing or intersecting paths that carry a blur filter (since blurred paint extends beyond geometric path bounds).stdDeviationvalues.stdDeviationattributes to0.0(as per SVG spec).inattributes forfeMergeNodes (falling back to the previous sibling primitive's result orSourceGraphic).SourceAlphafilters.<feMerge />elements.SourceGraphicbranches in a merge).try-finallyblocks inside parent node and text position node visitors to guarantee robust recovery in case of exceptions.ResolvingVisitorto prevent redundant object allocations for shared SVG gradients.imageFilterwhen blur standard deviations are0.0to avoid unnecessary rendering overhead in Flutter.Pre-Review Checklist
[shared_preferences]///).If you need help, consider asking for advice on the #hackers-new channel on Discord.
Note: The Flutter team is currently trialing the use of Gemini Code Assist for GitHub. Comments from the
gemini-code-assistbot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.TAG=agy
CONV=27cb188a-9ad9-4434-8918-8ef71bdba17c
Footnotes
Regular contributors who have demonstrated familiarity with the repository guidelines only need to comment if the PR is not auto-exempted by repo tooling. ↩ ↩2