Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions src/Svg.Model/MaskType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
namespace Svg.Model;

/// <summary>
/// Specifies how the pixel content of a mask element is used when applied.
/// Corresponds to the CSS <c>mask-type</c> property on the mask element.
/// </summary>
/// <remarks>
/// SVG spec: https://www.w3.org/TR/css-masking-1/#the-mask-type
/// </remarks>
public enum MaskType
{
/// <summary>
/// Default. The luminance values of the mask content determine the mask.
/// White (high luminance) = fully visible, Black (zero luminance) = fully masked.
/// </summary>
Luminance,

/// <summary>
/// The alpha channel of the mask content determines the mask.
/// Opaque pixels = fully visible, transparent pixels = fully masked.
/// This is what <c>style="mask-type:alpha"</c> sets.
/// </summary>
Alpha
}
26 changes: 22 additions & 4 deletions src/Svg.SceneGraph/SvgSceneResource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,9 @@ internal void AddDependentCompilationRoot(string compilationRootKey)
}

sceneDocument.ResolveRuntimePayloadTree(maskNode);
var maskType = GetMaskType(svgMask);

var payload = new SvgSceneMaskPayload(maskNode, CreateMaskPaint(), CreateMaskDstInPaint());
var payload = new SvgSceneMaskPayload(maskNode, CreateMaskPaint(), CreateMaskDstInPaint(maskType));
_maskPayloads.Add(cacheKey, payload);
return payload;
}
Expand Down Expand Up @@ -231,15 +232,15 @@ private static SKPaint CreateMaskPaint()
};
}

private static SKPaint CreateMaskDstInPaint()
private static SKPaint CreateMaskDstInPaint(MaskType maskType)
{
return new SKPaint
{
IsAntialias = true,
Style = SKPaintStyle.StrokeAndFill,
BlendMode = SKBlendMode.DstIn,
Color = FilterEffectsService.s_transparentBlack,
ColorFilter = SKColorFilter.CreateLumaColor()
ColorFilter = maskType == MaskType.Alpha ? null : SKColorFilter.CreateLumaColor()
};
}

Expand All @@ -261,10 +262,27 @@ private static SvgSceneMaskPayload CreateEmptyMaskPayload(SvgMask svgMask)
TotalTransform = SKMatrix.Identity,
TransformedBounds = SKRect.Empty
};

var maskType = GetMaskType(svgMask);

SvgSceneCompiler.AssignRetainedVisualState(maskNode, svgMask);
SvgSceneCompiler.AssignRetainedResourceKeys(maskNode, svgMask);
return new SvgSceneMaskPayload(maskNode, CreateMaskPaint(), CreateMaskDstInPaint());
return new SvgSceneMaskPayload(maskNode, CreateMaskPaint(), CreateMaskDstInPaint(maskType));
}

private static MaskType GetMaskType(SvgMask mask)
{
var maskType = MaskType.Luminance;

if (mask.TryGetAttribute("mask-type", out var maskTypeStr)
&& !string.IsNullOrWhiteSpace(maskTypeStr))
{
return string.Equals(maskTypeStr.Trim(), "alpha", StringComparison.OrdinalIgnoreCase)
? MaskType.Alpha
: MaskType.Luminance;
}

return maskType;
}

private sealed class ReadOnlySetView<T> : IReadOnlyCollection<T> where T : notnull
Expand Down