20 using Avalonia.Media.Imaging;
21 using Avalonia.Platform;
22 using Avalonia.Rendering.SceneGraph;
26 using System.Collections.Generic;
28 using System.Linq.Expressions;
29 using System.Reflection;
30 using System.Threading;
34 internal interface ISKRenderCanvas
36 void InvalidateDirty();
37 void InvalidateZIndex();
54 private SKColor BackgroundColour;
70 public Func<long, Bitmap>
Spinner {
get;
set; } =
null;
72 private readonly System.Diagnostics.Stopwatch LastFrameStopwatch =
new System.Diagnostics.Stopwatch();
73 static readonly Func<IDrawingContextImpl, IVisualNode> GetNode;
77 Type DeferredDrawingContextImpl = Assembly.GetAssembly(typeof(Avalonia.Rendering.SceneGraph.Scene)).GetType(
"Avalonia.Rendering.SceneGraph.DeferredDrawingContextImpl");
79 FieldInfo NodeFieldInfo = DeferredDrawingContextImpl.GetField(
"_node", BindingFlags.NonPublic | BindingFlags.Instance);
81 ParameterExpression ownerParameter = Expression.Parameter(typeof(IDrawingContextImpl));
83 MemberExpression exp = Expression.Field(Expression.Convert(ownerParameter, DeferredDrawingContextImpl), NodeFieldInfo);
84 GetNode = Expression.Lambda<Func<IDrawingContextImpl, IVisualNode>>(exp, ownerParameter).Compile();
87 private Dictionary<string, (SKBitmap, bool)> Images;
88 private List<List<SKRenderAction>> TaggedRenderActions;
98 public SKMultiLayerRenderCanvas(
Document document,
Colour backgroundColour,
double width,
double height, List<SKRenderAction> layerTransforms =
null) : this(document.Pages, backgroundColour, width, height, layerTransforms) { }
110 List<SKRenderContext> contents = (from el in layers select el.CopyToSKRenderContext()).ToList();
111 List<SKRenderAction> contentTransforms;
113 if (layerTransforms==
null)
119 contentTransforms = layerTransforms;
122 UpdateWith(contents, contentTransforms, backgroundColour, width, height);
125 this.Height = height;
127 this.PointerPressed += this.PointerPressedAction;
128 this.PointerReleased += this.PointerReleasedAction;
129 this.PointerMoved += this.PointerMoveAction;
130 this.PointerLeave += this.PointerLeaveAction;
132 LastFrameStopwatch.Start();
145 UpdateWith(contents, contentTransforms, backgroundColour, width, height);
148 this.Height = height;
150 this.PointerPressed += this.PointerPressedAction;
151 this.PointerReleased += this.PointerReleasedAction;
152 this.PointerMoved += this.PointerMoveAction;
153 this.PointerLeave += this.PointerLeaveAction;
155 LastFrameStopwatch.Start();
166 public void UpdateWith(List<SKRenderContext> contents, List<SKRenderAction> contentTransforms,
Colour backgroundColour,
double width,
double height)
170 if (this.RenderActions ==
null)
172 this.RenderActions =
new List<List<SKRenderAction>>();
176 this.RenderActions.Clear();
179 if (this.LayerTransforms ==
null)
181 this.LayerTransforms =
new List<SKRenderAction>();
185 this.LayerTransforms.Clear();
190 this.BackgroundColour = backgroundColour.ToSKColor();
192 if (this.Images ==
null)
194 Images =
new Dictionary<string, (SKBitmap, bool)>();
201 for (
int i = 0; i < contents.Count; i++)
203 this.LayerTransforms.Add(contentTransforms[i]);
204 this.RenderActions.Add(contents[i].SKRenderActions);
206 foreach (KeyValuePair<
string, (SKBitmap,
bool)> kvp in contents[i].Images)
208 this.Images[kvp.Key] = kvp.Value;
212 if (this.TaggedRenderActions ==
null)
214 this.TaggedRenderActions =
new List<List<SKRenderAction>>();
218 this.TaggedRenderActions.Clear();
222 for (
int i = this.RenderActions.Count - 1; i >= 0; i--)
224 TaggedRenderActions.Add(
new List<SKRenderAction>());
226 for (
int j = this.RenderActions[i].Count - 1; j >= 0; j--)
229 if (!
string.IsNullOrEmpty(this.RenderActions[i][j].Tag))
231 TaggedRenderActions[this.RenderActions.Count - 1 - i].Add(this.RenderActions[i][j]);
248 this.LayerTransforms[layer] = newTransform;
249 this.RenderActions[layer] = newContent.SKRenderActions;
251 foreach (KeyValuePair<
string, (SKBitmap,
bool)> kvp in newContent.Images)
253 this.Images[kvp.Key] = kvp.Value;
256 TaggedRenderActions[this.RenderActions.Count - 1 - layer].Clear();
258 for (
int j = this.RenderActions[layer].Count - 1; j >= 0; j--)
261 if (!
string.IsNullOrEmpty(this.RenderActions[layer][j].Tag))
263 TaggedRenderActions[this.RenderActions.Count - 1 - layer].Add(this.RenderActions[layer][j]);
280 this.LayerTransforms.Add(newTransform);
281 this.RenderActions.Add(newContent.SKRenderActions);
283 foreach (KeyValuePair<
string, (SKBitmap,
bool)> kvp in newContent.Images)
285 this.Images[kvp.Key] = kvp.Value;
288 TaggedRenderActions.Insert(0,
new List<SKRenderAction>());
290 for (
int j = this.RenderActions[this.RenderActions.Count - 1].Count - 1; j >= 0; j--)
292 RenderActions[this.RenderActions.Count - 1][j].InternalParent =
this;
293 if (!
string.IsNullOrEmpty(this.RenderActions[this.RenderActions.Count - 1][j].Tag))
295 TaggedRenderActions[0].Add(this.RenderActions[this.RenderActions.Count - 1][j]);
313 this.LayerTransforms.Insert(index, newTransform);
314 this.RenderActions.Insert(index, newContent.SKRenderActions);
316 foreach (KeyValuePair<
string, (SKBitmap,
bool)> kvp in newContent.Images)
318 this.Images[kvp.Key] = kvp.Value;
321 TaggedRenderActions.Insert(this.RenderActions.Count - 1 - index,
new List<SKRenderAction>());
323 for (
int j = this.RenderActions[index].Count - 1; j >= 0; j--)
326 if (!
string.IsNullOrEmpty(this.RenderActions[index][j].Tag))
328 TaggedRenderActions[this.RenderActions.Count - 1 - index].Add(this.RenderActions[index][j]);
344 this.LayerTransforms[layer].Dispose();
345 this.LayerTransforms.RemoveAt(layer);
347 for (
int i = 0; i < this.RenderActions[layer].Count; i++)
349 this.RenderActions[layer][i].Dispose();
351 this.RenderActions.RemoveAt(layer);
353 TaggedRenderActions.RemoveAt(this.TaggedRenderActions.Count - 1 - layer);
368 var temp = this.LayerTransforms[layer1];
369 this.LayerTransforms[layer1] = this.LayerTransforms[layer2];
370 this.LayerTransforms[layer2] = temp;
372 var temp2 = this.RenderActions[layer1];
373 this.RenderActions[layer1] = this.RenderActions[layer2];
374 this.RenderActions[layer2] = temp2;
376 var temp3 = this.TaggedRenderActions[this.RenderActions.Count - 1 - layer1];
377 this.TaggedRenderActions[this.RenderActions.Count - 1 - layer1] = this.TaggedRenderActions[this.RenderActions.Count - 1 - layer2];
378 this.TaggedRenderActions[this.RenderActions.Count - 1 - layer2] = temp3;
393 var temp = this.LayerTransforms[oldIndex];
394 this.LayerTransforms.RemoveAt(oldIndex);
395 this.LayerTransforms.Insert(newIndex, temp);
397 var temp2 = this.RenderActions[oldIndex];
398 this.RenderActions.RemoveAt(oldIndex);
399 this.RenderActions.Insert(newIndex, temp2);
401 var temp3 = this.TaggedRenderActions[this.RenderActions.Count - 1 - oldIndex];
402 this.TaggedRenderActions.RemoveAt(this.RenderActions.Count - 1 - oldIndex);
403 this.TaggedRenderActions.Insert(this.RenderActions.Count - 1 - newIndex, temp3);
411 private void PointerPressedAction(
object sender, Avalonia.Input.PointerPressedEventArgs e)
413 SKPoint position = e.GetPosition(
this).ToSKPoint();
415 for (
int i = 0; i < TaggedRenderActions.Count; i++)
419 for (
int j = 0; j < TaggedRenderActions[i].Count; j++)
421 if (TaggedRenderActions[i][j].LastRenderedGlobalHitTestPath?.Contains(position.X, position.Y) ==
true)
426 CurrentPressedAction = TaggedRenderActions[i][j];
427 TaggedRenderActions[i][j].FirePointerPressed(e);
431 else if (TaggedRenderActions[i][j].ActionType == SKRenderAction.ActionTypes.Text)
433 CurrentPressedAction = TaggedRenderActions[i][j];
434 TaggedRenderActions[i][j].FirePointerPressed(e);
438 else if (TaggedRenderActions[i][j].ActionType == SKRenderAction.ActionTypes.RasterImage)
440 CurrentPressedAction = TaggedRenderActions[i][j];
441 TaggedRenderActions[i][j].FirePointerPressed(e);
455 private void PointerReleasedAction(
object sender, Avalonia.Input.PointerReleasedEventArgs e)
457 if (CurrentPressedAction !=
null)
461 CurrentPressedAction.FirePointerReleased(e);
463 CurrentPressedAction =
null;
467 SKPoint position = e.GetPosition(
this).ToSKPoint();
469 for (
int i = 0; i < TaggedRenderActions.Count; i++)
473 for (
int j = 0; j < TaggedRenderActions[i].Count; j++)
475 if (TaggedRenderActions[i][j].LastRenderedGlobalHitTestPath?.Contains(position.X, position.Y) ==
true)
477 if (TaggedRenderActions[i][j].ActionType == SKRenderAction.ActionTypes.Path)
479 TaggedRenderActions[i][j].FirePointerReleased(e);
483 else if (TaggedRenderActions[i][j].ActionType == SKRenderAction.ActionTypes.Text)
485 TaggedRenderActions[i][j].FirePointerReleased(e);
489 else if (TaggedRenderActions[i][j].ActionType == SKRenderAction.ActionTypes.RasterImage)
491 TaggedRenderActions[i][j].FirePointerReleased(e);
506 private SKRenderAction CurrentOverAction =
null;
507 private void PointerMoveAction(
object sender, Avalonia.Input.PointerEventArgs e)
509 SKPoint position = e.GetPosition(
this).ToSKPoint();
513 for (
int i = 0; i < TaggedRenderActions.Count; i++)
515 for (
int j = 0; j < TaggedRenderActions[i].Count; j++)
517 if (TaggedRenderActions[i][j].LastRenderedGlobalHitTestPath?.Contains(position.X, position.Y) ==
true)
519 if (TaggedRenderActions[i][j].ActionType == SKRenderAction.ActionTypes.Path)
523 if (CurrentOverAction != TaggedRenderActions[i][j])
525 if (CurrentOverAction !=
null && !CurrentOverAction.Disposed)
527 CurrentOverAction.FirePointerLeave(e);
529 CurrentOverAction = TaggedRenderActions[i][j];
530 CurrentOverAction.FirePointerEnter(e);
535 else if (TaggedRenderActions[i][j].ActionType == SKRenderAction.ActionTypes.Text)
539 if (CurrentOverAction != TaggedRenderActions[i][j])
541 if (CurrentOverAction !=
null && !CurrentOverAction.Disposed)
543 CurrentOverAction.FirePointerLeave(e);
545 CurrentOverAction = TaggedRenderActions[i][j];
546 CurrentOverAction.FirePointerEnter(e);
551 else if (TaggedRenderActions[i][j].ActionType == SKRenderAction.ActionTypes.RasterImage)
555 if (CurrentOverAction != TaggedRenderActions[i][j])
557 if (CurrentOverAction !=
null && !CurrentOverAction.Disposed)
559 CurrentOverAction.FirePointerLeave(e);
561 CurrentOverAction = TaggedRenderActions[i][j];
562 CurrentOverAction.FirePointerEnter(e);
578 if (CurrentOverAction !=
null && !CurrentOverAction.Disposed)
580 CurrentOverAction.FirePointerLeave(e);
582 CurrentOverAction =
null;
586 private void PointerLeaveAction(
object sender, Avalonia.Input.PointerEventArgs e)
588 if (CurrentOverAction !=
null && !CurrentOverAction.Disposed)
590 CurrentOverAction.FirePointerLeave(e);
592 CurrentOverAction =
null;
596 protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
598 base.OnAttachedToVisualTree(e);
600 StartRenderingThread();
604 protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
606 StopRenderingThread();
609 private void StopRenderingThread()
611 DisposedHandle.Set();
614 private EventWaitHandle DisposedHandle;
615 private EventWaitHandle RenderRequestedHandle;
617 private RenderingParameters RenderingRequest =
null;
618 private readonly
object RenderingRequestLock =
new object();
620 private void StartRenderingThread()
622 DisposedHandle =
new EventWaitHandle(
false, EventResetMode.ManualReset);
623 RenderRequestedHandle =
new EventWaitHandle(
false, EventResetMode.ManualReset);
625 Thread renderingThread =
new Thread(async () =>
627 bool finished =
false;
628 WaitHandle[] handles =
new WaitHandle[] { DisposedHandle, RenderRequestedHandle };
632 int handle = EventWaitHandle.WaitAny(handles);
638 else if (handle == 1)
640 RenderingParameters requestParams;
642 lock (RenderingRequestLock)
644 requestParams = RenderingRequest.Clone();
645 RenderRequestedHandle.Reset();
650 if (BackBuffer ==
null || BackBufferRenderingParams ==
null || requestParams.RenderWidth > BackBufferRenderingParams.RenderWidth || requestParams.RenderHeight > BackBufferRenderingParams.RenderHeight)
652 await Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(() =>
654 SKCanvas tempCanvasReference = BackBufferSkiaCanvas;
655 ISkiaDrawingContextImpl tempContextReference = BackBufferSkiaContext;
656 RenderTargetBitmap tempBufferReference = BackBuffer;
658 _ = Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(() =>
660 tempCanvasReference?.Dispose();
661 tempContextReference?.Dispose();
662 tempBufferReference?.Dispose();
663 }, Avalonia.Threading.DispatcherPriority.MinValue);
666 BackBuffer =
new RenderTargetBitmap(
new PixelSize(requestParams.RenderWidth, requestParams.RenderHeight),
new Vector(96, 96));
667 BackBufferSkiaContext = BackBuffer.CreateDrawingContext(
null) as ISkiaDrawingContextImpl;
668 BackBufferSkiaCanvas = BackBufferSkiaContext.SkCanvas;
669 }, Avalonia.Threading.DispatcherPriority.MaxValue);
672 canvas = BackBufferSkiaCanvas;
676 canvas.Scale(requestParams.Scale);
677 canvas.Translate(-requestParams.Left, -requestParams.Top);
679 canvas.Clear(BackgroundColour);
681 canvas.ClipRect(
new SKRect(requestParams.Left, requestParams.Top, requestParams.Left + requestParams.Width, requestParams.Top + requestParams.Height));
685 canvas.RestoreToCount(-1);
687 BackBufferRenderingParams = requestParams;
689 lock (FrontBufferLock)
691 RenderTargetBitmap tempFrontReference = FrontBuffer;
692 RenderingParameters tempFrontRenderingParameters = FrontBufferRenderingParams;
693 SKCanvas tempFrontCanvas = FrontBufferSkiaCanvas;
694 ISkiaDrawingContextImpl tempFrontContext = FrontBufferSkiaContext;
696 FrontBuffer = BackBuffer;
697 FrontBufferRenderingParams = BackBufferRenderingParams;
698 FrontBufferSkiaCanvas = BackBufferSkiaCanvas;
699 FrontBufferSkiaContext = BackBufferSkiaContext;
701 BackBuffer = BackBuffer2;
702 BackBufferRenderingParams = BackBufferRenderingParams2;
703 BackBufferSkiaCanvas = BackBufferSkiaCanvas2;
704 BackBufferSkiaContext = BackBufferSkiaContext2;
706 BackBuffer2 = tempFrontReference;
707 BackBufferRenderingParams2 = tempFrontRenderingParameters;
708 BackBufferSkiaCanvas2 = tempFrontCanvas;
709 BackBufferSkiaContext2 = tempFrontContext;
712 await Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(() =>
714 base.InvalidateVisual();
715 }, Avalonia.Threading.DispatcherPriority.MaxValue);
720 renderingThread.Start();
737 SKColor realBackground = background ?? this.BackgroundColour;
741 width = (int)Math.Round(
this.PageWidth * scale);
742 height = (int)Math.Round(
this.PageHeight * scale);
744 RenderTargetBitmap tbr =
new RenderTargetBitmap(
new PixelSize(width, height),
new Vector(96, 96));
745 ISkiaDrawingContextImpl context = tbr.CreateDrawingContext(
null) as ISkiaDrawingContextImpl;
746 SKCanvas canvas = context.SkCanvas;
748 canvas.Clear(realBackground);
752 canvas.Scale((
float)scale);
756 canvas.RestoreToCount(-1);
764 private void RenderImage(SKCanvas canvas)
768 for (
int i = 0; i < this.RenderActions.Count; i++)
774 SKMatrix mat = this.LayerTransforms[i].Transform.Value;
775 canvas.Concat(ref mat);
778 RenderLayer(canvas, i);
797 private void RenderLayer(SKCanvas canvas,
int layer)
799 bool updateHitTests = this.TaggedRenderActions[this.TaggedRenderActions.Count - 1 - layer].Count > 0;
801 HashSet<uint> ZIndices =
new HashSet<uint>();
805 SKMatrix invertedInitialTransform;
807 if (this.LayerTransforms[layer].ActionType == SKRenderAction.ActionTypes.Transform)
809 invertedInitialTransform = (canvas.TotalMatrix.PreConcat(this.LayerTransforms[layer].Transform.Value.Invert())).Invert();
813 invertedInitialTransform = canvas.TotalMatrix.Invert();
816 SKPath clipPath =
null;
817 Stack<SKPath> clipPaths =
new Stack<SKPath>();
818 clipPaths.Push(
null);
820 for (
int i = 0; i < this.RenderActions[layer].Count; i++)
822 ZIndices.Add(this.RenderActions[layer][i].ZIndex);
824 if (this.RenderActions[layer][i].ActionType == SKRenderAction.ActionTypes.Clip)
826 canvas.ClipPath(this.RenderActions[layer][i].Path, antialias:
true);
830 if (clipPath ==
null)
832 clipPath = this.RenderActions[layer][i].Path.Clone();
833 clipPath.Transform(canvas.TotalMatrix.PostConcat(invertedInitialTransform));
837 using (SKPath tempPath = this.RenderActions[layer][i].Path.Clone())
839 tempPath.Transform(canvas.TotalMatrix.PostConcat(invertedInitialTransform));
840 clipPath.Op(tempPath, SKPathOp.Intersect);
845 else if (this.RenderActions[layer][i].ActionType == SKRenderAction.ActionTypes.Restore)
851 clipPath = clipPaths.Pop();
854 else if (this.RenderActions[layer][i].ActionType == SKRenderAction.ActionTypes.Save)
860 clipPaths.Push(clipPath?.Clone());
863 else if (this.RenderActions[layer][i].ActionType == SKRenderAction.ActionTypes.Transform)
865 SKMatrix mat = this.RenderActions[layer][i].Transform.Value;
866 canvas.Concat(ref mat);
870 if (this.RenderActions[layer][i].ZIndex == 0)
873 if (this.RenderActions[layer][i].ActionType == SKRenderAction.ActionTypes.Path &&
this.RenderActions[layer][i].Path !=
null)
875 canvas.DrawPath(this.RenderActions[layer][i].Path, this.RenderActions[layer][i].Paint);
877 else if (this.RenderActions[layer][i].ActionType == SKRenderAction.ActionTypes.Text)
879 canvas.DrawText(this.RenderActions[layer][i].Text, this.RenderActions[layer][i].TextX, this.RenderActions[layer][i].TextY, this.RenderActions[layer][i].Font, this.RenderActions[layer][i].Paint);
881 else if (this.RenderActions[layer][i].ActionType == SKRenderAction.ActionTypes.RasterImage)
883 (SKBitmap image,
bool interpolate) = this.Images[this.RenderActions[layer][i].ImageId];
893 paint =
new SKPaint() { FilterQuality = SKFilterQuality.Medium };
896 canvas.DrawBitmap(image, this.RenderActions[layer][i].ImageSource.Value,
this.RenderActions[layer][i].ImageDestination.Value, paint);
902 if (updateHitTests && this.RenderActions[layer][i].Tag !=
null && this.RenderActions[layer][i].HitTestPath !=
null)
904 SKPath hitTestPath = this.RenderActions[layer][i].HitTestPath.Clone();
905 hitTestPath.Transform(canvas.TotalMatrix.PostConcat(invertedInitialTransform));
907 if (clipPath !=
null)
909 hitTestPath.Op(clipPath, SKPathOp.Intersect);
912 this.RenderActions[layer][i].LastRenderedGlobalHitTestPath = hitTestPath;
919 uint[] sortedIndices = ZIndices.OrderBy(x => x).ToArray();
921 if (sortedIndices.Length > 1 || sortedIndices[0] != 0)
923 for (
int j = 0; j < sortedIndices.Length; j++)
927 for (
int i = 0; i < this.RenderActions[layer].Count; i++)
929 if (this.RenderActions[layer][i].ActionType == SKRenderAction.ActionTypes.Clip)
931 canvas.ClipPath(this.RenderActions[layer][i].Path, antialias:
true);
933 else if (this.RenderActions[layer][i].ActionType == SKRenderAction.ActionTypes.Restore)
937 else if (this.RenderActions[layer][i].ActionType == SKRenderAction.ActionTypes.Save)
941 else if (this.RenderActions[layer][i].ActionType == SKRenderAction.ActionTypes.Transform)
943 SKMatrix mat = this.RenderActions[layer][i].Transform.Value;
944 canvas.Concat(ref mat);
946 else if (sortedIndices[j] != 0 && this.RenderActions[layer][i].ZIndex == sortedIndices[j])
948 if (this.RenderActions[layer][i].ActionType == SKRenderAction.ActionTypes.Path &&
this.RenderActions[layer][i].Path !=
null)
950 canvas.DrawPath(this.RenderActions[layer][i].Path, this.RenderActions[layer][i].Paint);
952 else if (this.RenderActions[layer][i].ActionType == SKRenderAction.ActionTypes.Text)
954 canvas.DrawText(this.RenderActions[layer][i].Text, this.RenderActions[layer][i].TextX, this.RenderActions[layer][i].TextY, this.RenderActions[layer][i].Font, this.RenderActions[layer][i].Paint);
956 else if (this.RenderActions[layer][i].ActionType == SKRenderAction.ActionTypes.RasterImage)
958 (SKBitmap image,
bool interpolate) = this.Images[this.RenderActions[layer][i].ImageId];
968 paint =
new SKPaint() { FilterQuality = SKFilterQuality.Medium };
971 canvas.DrawBitmap(image, this.RenderActions[layer][i].ImageSource.Value,
this.RenderActions[layer][i].ImageDestination.Value, paint);
983 private bool IsDirty =
false;
991 base.InvalidateVisual();
999 for (
int i = 0; i < this.TaggedRenderActions.Count; i++)
1001 this.TaggedRenderActions[i] = this.TaggedRenderActions[i].OrderByDescending(a => a.ZIndex).ToList();
1007 private RenderTargetBitmap FrontBuffer =
null;
1008 private RenderingParameters FrontBufferRenderingParams =
null;
1009 private readonly
object FrontBufferLock =
new object();
1010 ISkiaDrawingContextImpl FrontBufferSkiaContext =
null;
1011 SKCanvas FrontBufferSkiaCanvas =
null;
1013 private RenderTargetBitmap BackBuffer =
null;
1014 private RenderingParameters BackBufferRenderingParams =
null;
1015 ISkiaDrawingContextImpl BackBufferSkiaContext =
null;
1016 SKCanvas BackBufferSkiaCanvas =
null;
1018 private RenderTargetBitmap BackBuffer2 =
null;
1019 private RenderingParameters BackBufferRenderingParams2 =
null;
1020 ISkiaDrawingContextImpl BackBufferSkiaContext2 =
null;
1021 SKCanvas BackBufferSkiaCanvas2 =
null;
1024 public override void Render(DrawingContext context)
1026 lock (FrontBufferLock)
1028 IVisualNode node = GetNode(context.PlatformImpl);
1030 Rect layoutBounds = node.LayoutBounds;
1031 Rect clipBounds = node.ClipBounds;
1034 double DPIscaling = (VisualRoot as Avalonia.Layout.ILayoutRoot)?.LayoutScaling ?? 1;
1036 double scale = 0.5 * (this.
PageWidth / layoutBounds.Width + this.
PageHeight / layoutBounds.Height);
1039 double left = Math.Max(0, (clipBounds.Left - layoutBounds.Left) * scale);
1040 double top = Math.Max(0, (clipBounds.Top - layoutBounds.Top) * scale);
1042 double width = Math.Min((clipBounds.Right - layoutBounds.Left) * scale, this.
PageWidth) - left;
1043 double height = Math.Min((clipBounds.Bottom - layoutBounds.Top) * scale, this.
PageHeight) - top;
1045 int pixelWidth = (int)Math.Round(width / scale * DPIscaling);
1046 int pixelHeight = (int)Math.Round(height / scale * DPIscaling);
1048 if (pixelWidth > 0 && pixelHeight > 0)
1050 RenderingParameters currentParameters =
new RenderingParameters((
float)left, (
float)top, (
float)width, (
float)height, (
float)(1 / scale * DPIscaling), pixelWidth, pixelHeight);
1052 if (FrontBuffer !=
null && FrontBufferRenderingParams == currentParameters && !IsDirty)
1054 if (!RenderRequestedHandle.WaitOne(0))
1056 LastFrameStopwatch.Reset();
1060 Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(() =>
1062 this.InvalidateVisual();
1065 context.DrawImage(FrontBuffer,
new Rect(0, 0, pixelWidth, pixelHeight),
new Rect(left, top, width, height));
1067 else if (FrontBuffer !=
null && FrontBufferRenderingParams.GoodEnough(currentParameters) && !IsDirty)
1069 if (!RenderRequestedHandle.WaitOne(0))
1071 LastFrameStopwatch.Reset();
1075 Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(() =>
1077 this.InvalidateVisual();
1080 context.DrawImage(FrontBuffer,
new Rect(0, 0, FrontBufferRenderingParams.RenderWidth, FrontBufferRenderingParams.RenderHeight),
new Rect(FrontBufferRenderingParams.Left, FrontBufferRenderingParams.Top, FrontBufferRenderingParams.Width, FrontBufferRenderingParams.Height));
1084 lock (RenderingRequestLock)
1087 RenderingRequest = currentParameters;
1088 RenderRequestedHandle.Set();
1089 LastFrameStopwatch.Start();
1092 if (FrontBuffer !=
null)
1094 context.DrawImage(FrontBuffer,
new Rect(0, 0, FrontBufferRenderingParams.RenderWidth, FrontBufferRenderingParams.RenderHeight),
new Rect(FrontBufferRenderingParams.Left, FrontBufferRenderingParams.Top, FrontBufferRenderingParams.Width, FrontBufferRenderingParams.Height));
1097 long milliseconds = LastFrameStopwatch.ElapsedMilliseconds;
1099 Bitmap spinner =
Spinner?.Invoke(milliseconds);
1101 if (spinner !=
null)
1103 double spinnerWidth = spinner.Size.Width * scale;
1104 double spinnerHeight = spinner.Size.Height * scale;
1106 double actualLeft = (clipBounds.Left - layoutBounds.Left) * scale;
1107 double actualTop = (clipBounds.Top - layoutBounds.Top) * scale;
1109 double actualRight = (clipBounds.Right - layoutBounds.Left) * scale;
1110 double actualBottom = (clipBounds.Bottom - layoutBounds.Top) * scale;
1112 context.DrawImage(spinner,
new Rect(0, 0, spinner.Size.Width, spinner.Size.Height),
new Rect((actualLeft + actualRight - spinnerWidth) * 0.5, (actualTop + actualBottom - spinnerHeight) * 0.5, spinnerWidth, spinnerHeight));
1115 Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(() =>
1117 this.InvalidateVisual();
1124 private bool disposedValue;
1127 protected virtual void Dispose(
bool disposing)
1133 this.BackBufferSkiaCanvas?.Dispose();
1134 this.BackBufferSkiaCanvas2?.Dispose();
1135 this.BackBufferSkiaContext?.Dispose();
1136 this.BackBufferSkiaContext2?.Dispose();
1137 this.BackBuffer?.Dispose();
1138 this.BackBuffer2?.Dispose();
1139 this.DisposedHandle?.Set();
1140 this.FrontBufferSkiaCanvas?.Dispose();
1141 this.FrontBufferSkiaContext?.Dispose();
1142 this.FrontBuffer?.Dispose();
1144 foreach (KeyValuePair<
string, (SKBitmap,
bool)> image in this.Images)
1146 image.Value.Item1?.Dispose();
1149 for (
int i = 0; i < this.RenderActions?.Count; i++)
1151 foreach (SKRenderAction act
in this.RenderActions[i])
1156 this.LayerTransforms?[i]?.Dispose();
1160 disposedValue =
true;
1168 GC.SuppressFinalize(
this);