Add Editing Helpers#456
Merged
wieslawsoltes merged 1 commit intomasterfrom Jan 3, 2026
Merged
Conversation
Owner
Author
Editing HelpersOverviewThis feature adds small, focused editing helpers to Namespaces and TypesShimSkiaSharp.EditingEditModepublic enum EditMode
{
InPlace,
CloneOnWrite
}
SKPictureEditingExtensionspublic static class SKPictureEditingExtensions
{
public static IEnumerable<TCommand> FindCommands<TCommand>(this SKPicture picture)
where TCommand : CanvasCommand;
public static int ReplaceCommands(
this SKPicture picture,
Func<CanvasCommand, CanvasCommand?> replace);
public static int UpdatePaints(
this SKPicture picture,
Func<SKPaint, bool> predicate,
Action<SKPaint> update,
EditMode mode = EditMode.InPlace);
public static int UpdatePaths(
this SKPicture picture,
Func<SKPath, bool> predicate,
Action<SKPath> update,
EditMode mode = EditMode.InPlace);
}Behavior notes:
SKPathEditingExtensionspublic static class SKPathEditingExtensions
{
public static int UpdateCommands(
this SKPath path,
Func<PathCommand, bool> predicate,
Func<PathCommand, PathCommand> replace);
public static void Transform(this SKPath path, SKMatrix matrix);
}Behavior notes:
SKPaintEditingExtensionspublic static class SKPaintEditingExtensions
{
public static void ApplyColorTransform(this SKPaint paint, Func<SKColor, SKColor> transform);
public static void ApplyShaderTransform(this SKPaint paint, Func<SKShader, SKShader> transform);
}Behavior notes:
Canvas command visitorpublic interface ICanvasCommandVisitor
{
void Visit(ClipPathCanvasCommand cmd);
void Visit(ClipRectCanvasCommand cmd);
void Visit(DrawImageCanvasCommand cmd);
void Visit(DrawPathCanvasCommand cmd);
void Visit(DrawTextBlobCanvasCommand cmd);
void Visit(DrawTextCanvasCommand cmd);
void Visit(DrawTextOnPathCanvasCommand cmd);
void Visit(RestoreCanvasCommand cmd);
void Visit(SaveCanvasCommand cmd);
void Visit(SaveLayerCanvasCommand cmd);
void Visit(SetMatrixCanvasCommand cmd);
}
public static class CanvasCommandVisitorExtensions
{
public static void Accept(this CanvasCommand command, ICanvasCommandVisitor visitor);
}Behavior notes:
Svg.Model.EditingDrawableWalkerpublic static class DrawableWalker
{
public static IEnumerable<DrawableBase> Traverse(DrawableBase root);
public static IEnumerable<DrawableBase> Traverse(IEnumerable<DrawableBase> roots);
}Behavior notes:
DrawableEditingExtensionspublic static class DrawableEditingExtensions
{
public static int UpdateFills(
this DrawableBase root,
Func<SKPaint, bool> predicate,
Action<SKPaint> update,
EditMode mode = EditMode.InPlace);
public static int UpdateStrokes(
this DrawableBase root,
Func<SKPaint, bool> predicate,
Action<SKPaint> update,
EditMode mode = EditMode.InPlace);
public static int UpdateOpacity(
this DrawableBase root,
Func<SKPaint, bool> predicate,
Action<SKPaint> update,
EditMode mode = EditMode.InPlace);
}Behavior notes:
SvgDocumentEditingExtensionspublic static class SvgDocumentEditingExtensions
{
public static IEnumerable<SvgElement> TraverseElements(this SvgDocument document);
public static int UpdateStyleAttributes(
this SvgDocument document,
Func<SvgVisualElement, bool> predicate,
Action<SvgVisualElement> update);
}Behavior notes:
ExamplesUpdate paints in a picture (clone-on-write)using ShimSkiaSharp.Editing;
picture.UpdatePaints(
paint => paint.Color is { },
paint =>
{
var c = paint.Color!.Value;
paint.Color = new SKColor(c.Red, c.Red, c.Red, c.Alpha);
},
EditMode.CloneOnWrite);Update paths inside commands and clip pathsusing ShimSkiaSharp.Editing;
picture.UpdatePaths(
path => path.Commands is { Count: > 0 },
path => path.LineTo(10, 10),
EditMode.CloneOnWrite);Update strokes on drawablesusing Svg.Model.Editing;
root.UpdateStrokes(
paint => true,
paint => paint.StrokeWidth *= 2f,
EditMode.CloneOnWrite);Update SVG DOM attributesusing Svg.Model.Editing;
document.UpdateStyleAttributes(
element => element.ID == "target",
element => element.Visibility = "hidden");TestsCoverage is provided in:
The tests cover command replacement, clone-on-write behavior, clip-path traversal, path transforms (including sweep flips for reflections), drawable traversal (including markers), and SVG DOM updates. Compatibility and Limitations
|
This was referenced Jan 5, 2026
This was referenced Apr 7, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Add editing helpers for ShimSkiaSharp and Svg.Model to make common edits (paints, paths, command filtering, drawable traversal) straightforward, with explicit in-place vs clone-on-write behavior. The work is additive and preserves existing render semantics.
API Additions
ShimSkiaSharp.Editing
EditModeenum withInPlaceandCloneOnWrite.SKPictureEditingExtensions:FindCommands<TCommand>()ReplaceCommands(Func<CanvasCommand, CanvasCommand?> replace)UpdatePaints(predicate, update, EditMode mode = InPlace)UpdatePaths(predicate, update, EditMode mode = InPlace)SKPathEditingExtensions:UpdateCommands(predicate, replace)Transform(SKMatrix matrix)(axis-aligned only)SKPaintEditingExtensions:ApplyColorTransform(Func<SKColor, SKColor>)ApplyShaderTransform(Func<SKShader, SKShader>)ICanvasCommandVisitorCanvasCommandVisitorExtensions.Accept(this CanvasCommand, ICanvasCommandVisitor)Svg.Model.Editing
DrawableWalker.Traverseoverloads for drawable tree enumeration.DrawableEditingExtensions:UpdateFills,UpdateStrokes,UpdateOpacitywithEditMode.SvgDocumentEditingExtensions:TraverseElementsUpdateStyleAttributes(predicate, update)Implementation Details
UpdatePaintsandUpdatePathsupdate each unique resource once using reference equality. In clone-on-write mode, the helpers useCloneContextto clone and preserve shared references.UpdatePathshandlesDrawPathCanvasCommand,DrawTextOnPathCanvasCommand, and clip paths insideClipPathCanvasCommand, including nestedClipPathstructures. In clone-on-write, predicates are evaluated on original paths and updates apply to the corresponding clones.TransformrewritesPathCommandcoordinates for translation/scale only. Non-uniform scale converts circles to ovals; arcs scale radii and flip sweep on reflection.DrawableWalkernow includesDrawablePath.MarkerDrawablesandDrawableBase.MaskDrawablealong with existing child containers,UseDrawable,SwitchDrawable, andMarkerDrawableedges.DrawableEditingExtensionsclone paints once per shared reference and reuse clones across drawables.SvgDocumentEditingExtensionstraverses the SVG DOM (including the document root) and updates matchingSvgVisualElementinstances.Tests
New unit tests cover:
Tests are in:
tests/ShimSkiaSharp.UnitTests/EditingHelpersTests.cstests/Svg.Model.UnitTests/EditingHelpersTests.csCompatibility
No breaking changes. All additions are new helpers and do not change existing rendering behavior.