Browse Source

WIP: More work on VisualBrush

Laying the foundations for getting `VisualBrush` working with
`DeferredRenderer`.
scenegraph-after-breakage
Steven Kirk 10 years ago
parent
commit
5261ab303f
  1. 36
      src/Avalonia.Controls/Control.cs
  2. 1
      src/Avalonia.Visuals/Avalonia.Visuals.csproj
  3. 20
      src/Avalonia.Visuals/Rendering/IVisualBrushInitialize.cs
  4. 13
      src/Avalonia.Visuals/Rendering/IVisualBrushRenderer.cs
  5. 6
      src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs
  6. 37
      src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs

36
src/Avalonia.Controls/Control.cs

@ -17,7 +17,9 @@ using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Logging;
using Avalonia.LogicalTree;
using Avalonia.Rendering;
using Avalonia.Styling;
using Avalonia.VisualTree;
namespace Avalonia.Controls
{
@ -33,7 +35,7 @@ namespace Avalonia.Controls
/// - Implements <see cref="IStyleable"/> to allow styling to work on the control.
/// - Implements <see cref="ILogical"/> to form part of a logical tree.
/// </remarks>
public class Control : InputElement, IControl, INamed, ISetInheritanceParent, ISetLogicalParent, ISupportInitialize
public class Control : InputElement, IControl, INamed, ISetInheritanceParent, ISetLogicalParent, ISupportInitialize, IVisualBrushInitialize
{
/// <summary>
/// Defines the <see cref="DataContext"/> property.
@ -460,6 +462,38 @@ namespace Avalonia.Controls
InheritanceParent = parent;
}
/// <inheritdoc/>
void IVisualBrushInitialize.EnsureInitialized()
{
if (VisualRoot == null)
{
if (!IsInitialized)
{
foreach (var i in this.GetSelfAndVisualDescendents())
{
var c = i as IControl;
if (c?.IsInitialized == false)
{
var init = c as ISupportInitialize;
if (init != null)
{
init.BeginInit();
init.EndInit();
}
}
}
}
if (!IsArrangeValid)
{
Measure(Size.Infinity);
Arrange(new Rect(DesiredSize));
}
}
}
/// <summary>
/// Adds a pseudo-class to be set when a property is true.
/// </summary>

1
src/Avalonia.Visuals/Avalonia.Visuals.csproj

@ -119,6 +119,7 @@
<Compile Include="Rendering\DefaultRenderLoop.cs" />
<Compile Include="Rendering\IRenderLayerFactory.cs" />
<Compile Include="Rendering\IVisualBrushRenderer.cs" />
<Compile Include="Rendering\IVisualBrushInitialize.cs" />
<Compile Include="Rendering\RendererBase.cs" />
<Compile Include="Rendering\RenderLayer.cs" />
<Compile Include="Rendering\RenderLayers.cs" />

20
src/Avalonia.Visuals/Rendering/IVisualBrushInitialize.cs

@ -0,0 +1,20 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using Avalonia.Media;
namespace Avalonia.Rendering
{
/// <summary>
/// Internal interface for initializing controls that are to be used as the viusal in a
/// <see cref="VisualBrush"/>.
/// </summary>
public interface IVisualBrushInitialize
{
/// <summary>
/// Ensures that the control is ready to use as the visual in a visual brush.
/// </summary>
void EnsureInitialized();
}
}

13
src/Avalonia.Visuals/Rendering/IVisualBrushRenderer.cs

@ -1,4 +1,7 @@
using System;
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using Avalonia.Media;
namespace Avalonia.Rendering
@ -8,6 +11,14 @@ namespace Avalonia.Rendering
/// </summary>
public interface IVisualBrushRenderer
{
/// <summary>
/// Gets the size of the intermediate render target to which the visual brush should be
/// drawn.
/// </summary>
/// <param name="brush">The visual brush.</param>
/// <returns>The size of the intermediate render target to create.</returns>
Size GetRenderTargetSize(VisualBrush brush);
/// <summary>
/// Renders a visual brush to a bitmap.
/// </summary>

6
src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs

@ -79,6 +79,12 @@ namespace Avalonia.Rendering
{
}
Size IVisualBrushRenderer.GetRenderTargetSize(VisualBrush brush)
{
(brush.Visual as IVisualBrushInitialize)?.EnsureInitialized();
return brush.Visual?.Bounds.Size ?? Size.Empty;
}
void IVisualBrushRenderer.RenderVisualBrush(IDrawingContextImpl context, VisualBrush brush)
{
var visual = brush.Visual;

37
src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs

@ -348,24 +348,27 @@ namespace Avalonia.Direct2D1.Media
{
if (_visualBrushRenderer != null)
{
TileBrushImplHelper.EnsureInitialized(visualBrush.Visual);
var intermediateSize = _visualBrushRenderer.GetRenderTargetSize(visualBrush);
using (var intermediate = new BitmapRenderTarget(
_renderTarget,
CompatibleRenderTargetOptions.None,
visualBrush.Visual.Bounds.Size.ToSharpDX()))
if (intermediateSize.Width >= 1 && intermediateSize.Height >= 1)
{
using (var ctx = new RenderTarget(intermediate).CreateDrawingContext(_visualBrushRenderer))
using (var intermediate = new BitmapRenderTarget(
_renderTarget,
CompatibleRenderTargetOptions.None,
intermediateSize.ToSharpDX()))
{
intermediate.Clear(null);
_visualBrushRenderer.RenderVisualBrush(ctx, visualBrush);
using (var ctx = new RenderTarget(intermediate).CreateDrawingContext(_visualBrushRenderer))
{
intermediate.Clear(null);
_visualBrushRenderer.RenderVisualBrush(ctx, visualBrush);
}
return new ImageBrushImpl(
visualBrush,
_renderTarget,
new D2DBitmapImpl(intermediate.Bitmap),
destinationSize);
}
return new ImageBrushImpl(
visualBrush,
_renderTarget,
new D2DBitmapImpl(intermediate.Bitmap),
destinationSize);
}
}
else
@ -373,10 +376,8 @@ namespace Avalonia.Direct2D1.Media
throw new NotSupportedException("No IVisualBrushRenderer was supplied to DrawingContextImpl.");
}
}
else
{
return new SolidColorBrushImpl((Avalonia.Media.SolidColorBrush)null, _renderTarget);
}
return new SolidColorBrushImpl(null, _renderTarget);
}
public void PushGeometryClip(Avalonia.Media.Geometry clip)

Loading…
Cancel
Save