-
Notifications
You must be signed in to change notification settings - Fork 751
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #18181 from ramezgerges/skcanvaselement
feat(skia): SKCanvasElement
- Loading branch information
Showing
19 changed files
with
393 additions
and
33 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
using System.Numerics; | ||
using Windows.Foundation; | ||
using Microsoft.UI.Composition; | ||
using Microsoft.UI.Xaml; | ||
using SkiaSharp; | ||
|
||
namespace Uno.WinUI.Graphics2DSK; | ||
|
||
/// <summary> | ||
/// A <see cref="FrameworkElement"/> that exposes the ability to draw directly on the window using SkiaSharp. | ||
/// </summary> | ||
/// <remarks>This is only available on skia-based targets.</remarks> | ||
public abstract class SKCanvasElement : FrameworkElement | ||
{ | ||
private protected override ShapeVisual CreateElementVisual() => new SKCanvasVisual(this, Compositor.GetSharedCompositor()); | ||
|
||
/// <summary> | ||
/// Queue a rendering cycle that will call <see cref="RenderOverride"/>. | ||
/// </summary> | ||
public void Invalidate() => _visual.Compositor.InvalidateRender(_visual); | ||
|
||
/// <summary> | ||
/// The SkiaSharp drawing logic goes here. | ||
/// </summary> | ||
/// <param name="canvas">The SKCanvas that should be drawn on.</param> | ||
/// <param name="area">The dimensions of the clipping area.</param> | ||
/// <remarks> | ||
/// When called, the <paramref name="canvas"/> is already set up such that the origin (0,0) is at the top-left of the clipping area. | ||
/// Drawing outside this area (i.e. outside the (0, 0, area.Width, area.Height) rectangle will be clipped out. | ||
/// </remarks> | ||
protected abstract void RenderOverride(SKCanvas canvas, Size area); | ||
|
||
private class SKCanvasVisual(SKCanvasElement owner, Compositor compositor) : ShapeVisual(compositor) | ||
{ | ||
internal override void Paint(in PaintingSession session) | ||
{ | ||
// We save and restore the canvas state ourselves so that the inheritor doesn't accidentally forget to. | ||
session.Canvas.Save(); | ||
// clipping here guarantees that drawing doesn't get outside the intended area | ||
session.Canvas.ClipRect(new SKRect(0, 0, Size.X, Size.Y)); | ||
owner.RenderOverride(session.Canvas, Size.ToSize()); | ||
session.Canvas.Restore(); | ||
} | ||
} | ||
} |
24 changes: 24 additions & 0 deletions
24
src/AddIns/Uno.WinUI.Graphics2DSK/Uno.WinUI.Graphics2DSK.csproj
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
<PropertyGroup> | ||
<TargetFrameworks>$(NetSkiaPreviousAndCurrent)</TargetFrameworks> | ||
|
||
<RootNamespace>Uno.WinUI.Graphics2DSK</RootNamespace> | ||
<GeneratePackageOnBuild Condition="'$(UNO_UWP_BUILD)'!='true' And '$(Configuration)'=='Release'">true</GeneratePackageOnBuild> | ||
|
||
<Nullable>enable</Nullable> | ||
</PropertyGroup> | ||
|
||
<Import Project="../../targetframework-override.props" /> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="SkiaSharp" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\..\Uno.UI\Uno.UI.Skia.csproj" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<None Include="..\..\Common\uno.png" Pack="true" PackagePath="\" /> | ||
</ItemGroup> | ||
</Project> |
This file contains 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
This file contains 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
This file contains 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
131 changes: 131 additions & 0 deletions
131
src/SamplesApp/UITests.Shared/Windows_UI_Composition/SKCanvasElementImpl.skia.cs
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
#if __SKIA__ | ||
using System; | ||
using Windows.Foundation; | ||
using Microsoft.UI.Xaml; | ||
using Uno.WinUI.Graphics2DSK; | ||
using SkiaSharp; | ||
|
||
namespace UITests.Shared.Windows_UI_Composition; | ||
|
||
public class SKCanvasElementImpl : SKCanvasElement | ||
{ | ||
public static int SampleCount => 3; | ||
|
||
public static DependencyProperty SampleProperty { get; } = DependencyProperty.Register( | ||
nameof(Sample), | ||
typeof(int), | ||
typeof(SKCanvasElementImpl), | ||
new PropertyMetadata(0, (o, args) => ((SKCanvasElementImpl)o).SampleChanged((int)args.NewValue))); | ||
|
||
public int Sample | ||
{ | ||
get => (int)GetValue(SampleProperty); | ||
set => SetValue(SampleProperty, value); | ||
} | ||
|
||
private void SampleChanged(int newIndex) | ||
{ | ||
Sample = Math.Min(Math.Max(0, newIndex), SampleCount - 1); | ||
} | ||
|
||
protected override void RenderOverride(SKCanvas canvas, Size area) | ||
{ | ||
var minDim = Math.Min(area.Width, area.Height); | ||
// rescale to fit the given area, assuming each drawing is 260x260 | ||
canvas.Scale((float)(minDim / 260), (float)(minDim / 260)); | ||
|
||
switch (Sample) | ||
{ | ||
case 0: | ||
SkiaDrawing0(canvas); | ||
break; | ||
case 1: | ||
SkiaDrawing1(canvas); | ||
break; | ||
case 2: | ||
SkiaDrawing2(canvas); | ||
break; | ||
} | ||
} | ||
|
||
// https://fiddle.skia.org/c/@shapes | ||
private void SkiaDrawing0(SKCanvas canvas) | ||
{ | ||
var paint = new SKPaint(); | ||
paint.Style = SKPaintStyle.Fill; | ||
paint.IsAntialias = true; | ||
paint.StrokeWidth = 4; | ||
paint.Color = new SKColor(0xff4285F4); | ||
|
||
var rect = SKRect.Create(10, 10, 100, 160); | ||
canvas.DrawRect(rect, paint); | ||
|
||
var oval = new SKPath(); | ||
oval.AddRoundRect(rect, 20, 20); | ||
oval.Offset(new SKPoint(40, 80)); | ||
paint.Color = new SKColor(0xffDB4437); | ||
canvas.DrawPath(oval, paint); | ||
|
||
paint.Color = new SKColor(0xff0F9D58); | ||
canvas.DrawCircle(180, 50, 25, paint); | ||
|
||
rect.Offset(80, 50); | ||
paint.Color = new SKColor(0xffF4B400); | ||
paint.Style = SKPaintStyle.Stroke; | ||
canvas.DrawRoundRect(rect, 10, 10, paint); | ||
} | ||
|
||
// https://fiddle.skia.org/c/@bezier_curves | ||
private void SkiaDrawing1(SKCanvas canvas) | ||
{ | ||
var paint = new SKPaint(); | ||
paint.Style = SKPaintStyle.Stroke; | ||
paint.StrokeWidth = 8; | ||
paint.Color = new SKColor(0xff4285F4); | ||
paint.IsAntialias = true; | ||
paint.StrokeCap = SKStrokeCap.Round; | ||
|
||
var path = new SKPath(); | ||
path.MoveTo(10, 10); | ||
path.QuadTo(256, 64, 128, 128); | ||
path.QuadTo(10, 192, 250, 250); | ||
canvas.DrawPath(path, paint); | ||
} | ||
|
||
// https://fiddle.skia.org/c/@shader | ||
private void SkiaDrawing2(SKCanvas canvas) | ||
{ | ||
var paint = new SKPaint(); | ||
using var pathEffect = SKPathEffect.CreateDiscrete(10.0f, 4.0f); | ||
paint.PathEffect = pathEffect; | ||
SKPoint[] points = | ||
{ | ||
new SKPoint(0.0f, 0.0f), | ||
new SKPoint(256.0f, 256.0f) | ||
}; | ||
SKColor[] colors = | ||
{ | ||
new SKColor(66, 133, 244), | ||
new SKColor(15, 157, 88) | ||
}; | ||
paint.Shader = SKShader.CreateLinearGradient(points[0], points[1], colors, SKShaderTileMode.Clamp); | ||
paint.IsAntialias = true; | ||
var path = Star(); | ||
canvas.DrawPath(path, paint); | ||
|
||
SKPath Star() | ||
{ | ||
const float R = 60.0f, C = 128.0f; | ||
var path = new SKPath(); | ||
path.MoveTo(C + R, C); | ||
for (var i = 1; i < 15; ++i) | ||
{ | ||
var a = 0.44879895f * i; | ||
var r = R + R * (i % 2); | ||
path.LineTo((float)(C + r * Math.Cos(a)), (float)(C + r * Math.Sin(a))); | ||
} | ||
return path; | ||
} | ||
} | ||
} | ||
#endif |
Oops, something went wrong.