diff --git a/src/Avalonia.Visuals/Avalonia.Visuals.csproj b/src/Avalonia.Visuals/Avalonia.Visuals.csproj
index 21978720e9..9282290177 100644
--- a/src/Avalonia.Visuals/Avalonia.Visuals.csproj
+++ b/src/Avalonia.Visuals/Avalonia.Visuals.csproj
@@ -69,6 +69,9 @@
+
+
+
@@ -124,12 +127,15 @@
+
+
+
@@ -185,6 +191,7 @@
+
diff --git a/src/Avalonia.Visuals/Media/IImageBrush.cs b/src/Avalonia.Visuals/Media/IImageBrush.cs
new file mode 100644
index 0000000000..aaa481bd28
--- /dev/null
+++ b/src/Avalonia.Visuals/Media/IImageBrush.cs
@@ -0,0 +1,15 @@
+using Avalonia.Media.Imaging;
+
+namespace Avalonia.Media
+{
+ ///
+ /// Paints an area with an .
+ ///
+ public interface IImageBrush : ITileBrush
+ {
+ ///
+ /// Gets the image to draw.
+ ///
+ IBitmap Source { get; }
+ }
+}
\ No newline at end of file
diff --git a/src/Avalonia.Visuals/Media/ITileBrush.cs b/src/Avalonia.Visuals/Media/ITileBrush.cs
new file mode 100644
index 0000000000..8e2349f506
--- /dev/null
+++ b/src/Avalonia.Visuals/Media/ITileBrush.cs
@@ -0,0 +1,39 @@
+namespace Avalonia.Media
+{
+ ///
+ /// A brush which displays a repeating image.
+ ///
+ public interface ITileBrush : IBrush
+ {
+ ///
+ /// Gets the horizontal alignment of a tile in the destination.
+ ///
+ AlignmentX AlignmentX { get; }
+
+ ///
+ /// Gets the horizontal alignment of a tile in the destination.
+ ///
+ AlignmentY AlignmentY { get; }
+
+ ///
+ /// Gets the rectangle on the destination in which to paint a tile.
+ ///
+ RelativeRect DestinationRect { get; }
+
+ ///
+ /// Gets the rectangle of the source image that will be displayed.
+ ///
+ RelativeRect SourceRect { get; }
+
+ ///
+ /// Gets a value indicating how the source rectangle will be stretched to fill the
+ /// destination rect.
+ ///
+ Stretch Stretch { get; }
+
+ ///
+ /// Gets the brush's tile mode.
+ ///
+ TileMode TileMode { get; }
+ }
+}
\ No newline at end of file
diff --git a/src/Avalonia.Visuals/Media/IVisualBrush.cs b/src/Avalonia.Visuals/Media/IVisualBrush.cs
new file mode 100644
index 0000000000..e74892b218
--- /dev/null
+++ b/src/Avalonia.Visuals/Media/IVisualBrush.cs
@@ -0,0 +1,15 @@
+using Avalonia.VisualTree;
+
+namespace Avalonia.Media
+{
+ ///
+ /// Paints an area with an .
+ ///
+ public interface IVisualBrush : ITileBrush
+ {
+ ///
+ /// Gets the visual to draw.
+ ///
+ IVisual Visual { get; }
+ }
+}
\ No newline at end of file
diff --git a/src/Avalonia.Visuals/Media/ImageBush.cs b/src/Avalonia.Visuals/Media/ImageBush.cs
index caf43d19a2..85c1f6c71a 100644
--- a/src/Avalonia.Visuals/Media/ImageBush.cs
+++ b/src/Avalonia.Visuals/Media/ImageBush.cs
@@ -8,7 +8,7 @@ namespace Avalonia.Media
///
/// Paints an area with an .
///
- public class ImageBrush : TileBrush
+ public class ImageBrush : TileBrush, IImageBrush
{
///
/// Defines the property.
diff --git a/src/Avalonia.Visuals/Media/TileBrush.cs b/src/Avalonia.Visuals/Media/TileBrush.cs
index 1708c7e9f6..3a7f9d9920 100644
--- a/src/Avalonia.Visuals/Media/TileBrush.cs
+++ b/src/Avalonia.Visuals/Media/TileBrush.cs
@@ -37,7 +37,7 @@ namespace Avalonia.Media
///
/// Base class for brushes which display repeating images.
///
- public abstract class TileBrush : Brush
+ public abstract class TileBrush : Brush, ITileBrush
{
///
/// Defines the property.
diff --git a/src/Avalonia.Visuals/Media/VisualBrush.cs b/src/Avalonia.Visuals/Media/VisualBrush.cs
index 41a61f6022..85ccf7afc9 100644
--- a/src/Avalonia.Visuals/Media/VisualBrush.cs
+++ b/src/Avalonia.Visuals/Media/VisualBrush.cs
@@ -8,7 +8,7 @@ namespace Avalonia.Media
///
/// Paints an area with an .
///
- public class VisualBrush : TileBrush
+ public class VisualBrush : TileBrush, IVisualBrush
{
///
/// Defines the property.
diff --git a/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs b/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs
index a17a5119a5..9f49d48da0 100644
--- a/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs
+++ b/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs
@@ -105,7 +105,7 @@ namespace Avalonia.Rendering
Render(_scene);
}
- Size IVisualBrushRenderer.GetRenderTargetSize(VisualBrush brush)
+ Size IVisualBrushRenderer.GetRenderTargetSize(IVisualBrush brush)
{
if (brush.Visual != null)
{
@@ -115,7 +115,7 @@ namespace Avalonia.Rendering
return Size.Empty;
}
- void IVisualBrushRenderer.RenderVisualBrush(IDrawingContextImpl context, VisualBrush brush)
+ void IVisualBrushRenderer.RenderVisualBrush(IDrawingContextImpl context, IVisualBrush brush)
{
if (brush.Visual != null)
{
diff --git a/src/Avalonia.Visuals/Rendering/IVisualBrushRenderer.cs b/src/Avalonia.Visuals/Rendering/IVisualBrushRenderer.cs
index 6c410587fe..0eeb608955 100644
--- a/src/Avalonia.Visuals/Rendering/IVisualBrushRenderer.cs
+++ b/src/Avalonia.Visuals/Rendering/IVisualBrushRenderer.cs
@@ -17,7 +17,7 @@ namespace Avalonia.Rendering
///
/// The visual brush.
/// The size of the intermediate render target to create.
- Size GetRenderTargetSize(VisualBrush brush);
+ Size GetRenderTargetSize(IVisualBrush brush);
///
/// Renders a visual brush to a bitmap.
@@ -25,6 +25,6 @@ namespace Avalonia.Rendering
/// The drawing context to render to.
/// The visual brush.
/// A bitmap containing the rendered brush.
- void RenderVisualBrush(IDrawingContextImpl context, VisualBrush brush);
+ void RenderVisualBrush(IDrawingContextImpl context, IVisualBrush brush);
}
}
diff --git a/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs b/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs
index bcd84682be..da95645571 100644
--- a/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs
+++ b/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs
@@ -79,13 +79,13 @@ namespace Avalonia.Rendering
{
}
- Size IVisualBrushRenderer.GetRenderTargetSize(VisualBrush brush)
+ Size IVisualBrushRenderer.GetRenderTargetSize(IVisualBrush brush)
{
(brush.Visual as IVisualBrushInitialize)?.EnsureInitialized();
return brush.Visual?.Bounds.Size ?? Size.Empty;
}
- void IVisualBrushRenderer.RenderVisualBrush(IDrawingContextImpl context, VisualBrush brush)
+ void IVisualBrushRenderer.RenderVisualBrush(IDrawingContextImpl context, IVisualBrush brush)
{
var visual = brush.Visual;
Render(new DrawingContext(context), visual, visual.Bounds);
diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/BrushDrawOperation.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/BrushDrawOperation.cs
new file mode 100644
index 0000000000..bc003563e1
--- /dev/null
+++ b/src/Avalonia.Visuals/Rendering/SceneGraph/BrushDrawOperation.cs
@@ -0,0 +1,48 @@
+using System;
+using Avalonia.Media;
+using Avalonia.Rendering.SceneGraph.Media;
+
+namespace Avalonia.Rendering.SceneGraph
+{
+ public abstract class BrushDrawOperation : IDrawOperation
+ {
+ public abstract Rect Bounds { get; }
+ public abstract bool HitTest(Point p);
+ public abstract void Render(IDrawingContextImpl context);
+
+ protected IBrush Convert(IBrush brush)
+ {
+ var imageBrush = brush as ImageBrush;
+ var visualBrush = brush as VisualBrush;
+
+ if (imageBrush != null)
+ {
+ return new SceneImageBrush(imageBrush);
+ }
+ else if (visualBrush != null)
+ {
+ return new SceneVisualBrush(visualBrush);
+ }
+ else
+ {
+ return brush;
+ }
+ }
+
+ protected Pen Convert(Pen pen)
+ {
+ var brush = pen?.Brush != null ? Convert(pen.Brush) : null;
+ return ReferenceEquals(pen?.Brush, brush) ?
+ pen :
+ new Pen(
+ pen.Brush,
+ thickness: pen.Thickness,
+ dashStyle: pen.DashStyle,
+ dashCap: pen.DashCap,
+ startLineCap: pen.StartLineCap,
+ endLineCap: pen.EndLineCap,
+ lineJoin: pen.LineJoin,
+ miterLimit: pen.MiterLimit);
+ }
+ }
+}
diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/GeometryNode.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/GeometryNode.cs
index fbc7be6e67..f4dbdbecf6 100644
--- a/src/Avalonia.Visuals/Rendering/SceneGraph/GeometryNode.cs
+++ b/src/Avalonia.Visuals/Rendering/SceneGraph/GeometryNode.cs
@@ -7,18 +7,18 @@ using Avalonia.Platform;
namespace Avalonia.Rendering.SceneGraph
{
- public class GeometryNode : IDrawOperation
+ public class GeometryNode : BrushDrawOperation
{
public GeometryNode(Matrix transform, IBrush brush, Pen pen, IGeometryImpl geometry)
{
Bounds = geometry.GetRenderBounds(pen.Thickness).TransformToAABB(transform);
Transform = transform;
- Brush = brush;
- Pen = pen;
+ Brush = Convert(brush);
+ Pen = Convert(pen);
Geometry = geometry;
}
- public Rect Bounds { get; }
+ public override Rect Bounds { get; }
public Matrix Transform { get; }
public IBrush Brush { get; }
public Pen Pen { get; }
@@ -32,13 +32,13 @@ namespace Avalonia.Rendering.SceneGraph
Equals(geometry, Geometry);
}
- public void Render(IDrawingContextImpl context)
+ public override void Render(IDrawingContextImpl context)
{
context.Transform = Transform;
context.DrawGeometry(Brush, Pen, Geometry);
}
- public bool HitTest(Point p)
+ public override bool HitTest(Point p)
{
p *= Transform.Invert();
return (Brush != null && Geometry.FillContains(p)) ||
diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/LineNode.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/LineNode.cs
index 61ffada7d2..16e7c65cad 100644
--- a/src/Avalonia.Visuals/Rendering/SceneGraph/LineNode.cs
+++ b/src/Avalonia.Visuals/Rendering/SceneGraph/LineNode.cs
@@ -6,18 +6,18 @@ using Avalonia.Media;
namespace Avalonia.Rendering.SceneGraph
{
- public class LineNode : IDrawOperation
+ public class LineNode : BrushDrawOperation
{
public LineNode(Matrix transform, Pen pen, Point p1, Point p2)
{
Bounds = new Rect(P1, P2);
Transform = transform;
- Pen = pen;
+ Pen = Convert(pen);
P1 = p1;
P2 = p2;
}
- public Rect Bounds { get; }
+ public override Rect Bounds { get; }
public Matrix Transform { get; }
public Pen Pen { get; }
public Point P1 { get; }
@@ -28,13 +28,13 @@ namespace Avalonia.Rendering.SceneGraph
return transform == Transform && pen == Pen && p1 == P1 && p2 == P2;
}
- public void Render(IDrawingContextImpl context)
+ public override void Render(IDrawingContextImpl context)
{
context.Transform = Transform;
context.DrawLine(Pen, P1, P2);
}
- public bool HitTest(Point p)
+ public override bool HitTest(Point p)
{
// TODO: Implement line hit testing.
return false;
diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/Media/SceneImageBrush.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/Media/SceneImageBrush.cs
new file mode 100644
index 0000000000..d17ebdbfe4
--- /dev/null
+++ b/src/Avalonia.Visuals/Rendering/SceneGraph/Media/SceneImageBrush.cs
@@ -0,0 +1,37 @@
+using System;
+using Avalonia.Media;
+using Avalonia.Media.Imaging;
+
+namespace Avalonia.Rendering.SceneGraph.Media
+{
+ internal class SceneImageBrush : IImageBrush
+ {
+ public SceneImageBrush(IImageBrush source)
+ {
+ AlignmentX = source.AlignmentX;
+ AlignmentY = source.AlignmentY;
+ DestinationRect = source.DestinationRect;
+ Opacity = source.Opacity;
+ Source = source.Source;
+ SourceRect = source.SourceRect;
+ Stretch = source.Stretch;
+ TileMode = source.TileMode;
+ }
+
+ public AlignmentX AlignmentX { get; }
+
+ public AlignmentY AlignmentY { get; }
+
+ public RelativeRect DestinationRect { get; }
+
+ public double Opacity { get; }
+
+ public IBitmap Source { get; }
+
+ public RelativeRect SourceRect { get; }
+
+ public Stretch Stretch { get; }
+
+ public TileMode TileMode { get; }
+ }
+}
diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/Media/SceneVisualBrush.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/Media/SceneVisualBrush.cs
new file mode 100644
index 0000000000..67407d01be
--- /dev/null
+++ b/src/Avalonia.Visuals/Rendering/SceneGraph/Media/SceneVisualBrush.cs
@@ -0,0 +1,37 @@
+using System;
+using Avalonia.Media;
+using Avalonia.VisualTree;
+
+namespace Avalonia.Rendering.SceneGraph.Media
+{
+ internal class SceneVisualBrush : IVisualBrush
+ {
+ public SceneVisualBrush(IVisualBrush source)
+ {
+ AlignmentX = source.AlignmentX;
+ AlignmentY = source.AlignmentY;
+ DestinationRect = source.DestinationRect;
+ Opacity = source.Opacity;
+ SourceRect = source.SourceRect;
+ Stretch = source.Stretch;
+ TileMode = source.TileMode;
+ Visual = source.Visual;
+ }
+
+ public AlignmentX AlignmentX { get; }
+
+ public AlignmentY AlignmentY { get; }
+
+ public RelativeRect DestinationRect { get; }
+
+ public double Opacity { get; }
+
+ public RelativeRect SourceRect { get; }
+
+ public Stretch Stretch { get; }
+
+ public TileMode TileMode { get; }
+
+ public IVisual Visual { get; }
+ }
+}
diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/RectangleNode.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/RectangleNode.cs
index e73684afa6..88756b34ab 100644
--- a/src/Avalonia.Visuals/Rendering/SceneGraph/RectangleNode.cs
+++ b/src/Avalonia.Visuals/Rendering/SceneGraph/RectangleNode.cs
@@ -6,19 +6,19 @@ using Avalonia.Media;
namespace Avalonia.Rendering.SceneGraph
{
- public class RectangleNode : IDrawOperation
+ public class RectangleNode : BrushDrawOperation
{
public RectangleNode(Matrix transform, IBrush brush, Pen pen, Rect rect, float cornerRadius)
{
Bounds = rect.TransformToAABB(transform).Inflate(pen?.Thickness ?? 0);
Transform = transform;
- Brush = brush;
- Pen = pen;
+ Brush = Convert(brush);
+ Pen = Convert(pen);
Rect = rect;
CornerRadius = cornerRadius;
}
- public Rect Bounds { get; }
+ public override Rect Bounds { get; }
public Matrix Transform { get; }
public IBrush Brush { get; }
public Pen Pen { get; }
@@ -34,7 +34,7 @@ namespace Avalonia.Rendering.SceneGraph
cornerRadius == CornerRadius;
}
- public void Render(IDrawingContextImpl context)
+ public override void Render(IDrawingContextImpl context)
{
context.Transform = Transform;
@@ -49,6 +49,6 @@ namespace Avalonia.Rendering.SceneGraph
}
}
- public bool HitTest(Point p) => Bounds.Contains(p);
+ public override bool HitTest(Point p) => Bounds.Contains(p);
}
}
diff --git a/src/Avalonia.Visuals/Rendering/Utilities/TileBrushCalculator.cs b/src/Avalonia.Visuals/Rendering/Utilities/TileBrushCalculator.cs
index 5a8adc5c45..52a8fb5ab7 100644
--- a/src/Avalonia.Visuals/Rendering/Utilities/TileBrushCalculator.cs
+++ b/src/Avalonia.Visuals/Rendering/Utilities/TileBrushCalculator.cs
@@ -18,7 +18,7 @@ namespace Avalonia.Rendering.Utilities
/// The brush to be rendered.
/// The size of the content of the tile brush.
/// The size of the control to which the brush is being rendered.
- public TileBrushCalculator(TileBrush brush, Size contentSize, Size targetSize)
+ public TileBrushCalculator(ITileBrush brush, Size contentSize, Size targetSize)
: this(
brush.TileMode,
brush.Stretch,
diff --git a/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs
index 9f3360155b..19d90d15f6 100644
--- a/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs
+++ b/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs
@@ -321,8 +321,8 @@ namespace Avalonia.Direct2D1.Media
var solidColorBrush = brush as Avalonia.Media.ISolidColorBrush;
var linearGradientBrush = brush as Avalonia.Media.LinearGradientBrush;
var radialGradientBrush = brush as Avalonia.Media.RadialGradientBrush;
- var imageBrush = brush as Avalonia.Media.ImageBrush;
- var visualBrush = brush as Avalonia.Media.VisualBrush;
+ var imageBrush = brush as Avalonia.Media.IImageBrush;
+ var visualBrush = brush as Avalonia.Media.IVisualBrush;
if (solidColorBrush != null)
{
diff --git a/src/Windows/Avalonia.Direct2D1/Media/ImageBrushImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/ImageBrushImpl.cs
index 6840d2327a..ed3d78b4fd 100644
--- a/src/Windows/Avalonia.Direct2D1/Media/ImageBrushImpl.cs
+++ b/src/Windows/Avalonia.Direct2D1/Media/ImageBrushImpl.cs
@@ -11,7 +11,7 @@ namespace Avalonia.Direct2D1.Media
public sealed class ImageBrushImpl : BrushImpl
{
public ImageBrushImpl(
- TileBrush brush,
+ ITileBrush brush,
SharpDX.Direct2D1.RenderTarget target,
BitmapImpl bitmap,
Size targetSize)
@@ -45,7 +45,7 @@ namespace Avalonia.Direct2D1.Media
base.Dispose();
}
- private static BitmapBrushProperties GetBitmapBrushProperties(TileBrush brush)
+ private static BitmapBrushProperties GetBitmapBrushProperties(ITileBrush brush)
{
var tileMode = brush.TileMode;
@@ -56,7 +56,7 @@ namespace Avalonia.Direct2D1.Media
};
}
- private static BrushProperties GetBrushProperties(TileBrush brush, Rect destinationRect)
+ private static BrushProperties GetBrushProperties(ITileBrush brush, Rect destinationRect)
{
var tileTransform =
brush.TileMode != TileMode.None ?
diff --git a/tests/Avalonia.RenderTests/Avalonia.Direct2D1.RenderTests.v3.ncrunchproject b/tests/Avalonia.RenderTests/Avalonia.Direct2D1.RenderTests.v3.ncrunchproject
index 5ca3dbf2e3..f4340c8042 100644
--- a/tests/Avalonia.RenderTests/Avalonia.Direct2D1.RenderTests.v3.ncrunchproject
+++ b/tests/Avalonia.RenderTests/Avalonia.Direct2D1.RenderTests.v3.ncrunchproject
@@ -2,51 +2,12 @@
1000
-
- Avalonia.Direct2D1.RenderTests.Media.ImageBrushTests.ImageBrush_NoStretch_FlipX_TopLeftDest
-
Avalonia.Direct2D1.RenderTests.Media.LinearGradientBrushTests
-
- Avalonia.Direct2D1.RenderTests.Media.VisualBrushTests
-
Avalonia.Direct2D1.RenderTests.Controls.BorderTests
-
- Avalonia.Direct2D1.RenderTests.Media.ImageBrushTests.ImageBrush_NoStretch_FlipXY_TopLeftDest
-
-
- Avalonia.Direct2D1.RenderTests.Media.ImageBrushTests.ImageBrush_NoStretch_FlipY_TopLeftDest
-
-
- Avalonia.Direct2D1.RenderTests.Media.ImageBrushTests.ImageBrush_NoStretch_NoTile_Alignment_BottomRight
-
-
- Avalonia.Direct2D1.RenderTests.Media.ImageBrushTests.ImageBrush_NoStretch_NoTile_Alignment_Center
-
-
- Avalonia.Direct2D1.RenderTests.Media.ImageBrushTests.ImageBrush_NoStretch_NoTile_Alignment_TopLeft
-
-
- Avalonia.Direct2D1.RenderTests.Media.ImageBrushTests.ImageBrush_NoStretch_NoTile_BottomRightQuarterDest
-
-
- Avalonia.Direct2D1.RenderTests.Media.ImageBrushTests.ImageBrush_NoStretch_NoTile_BottomRightQuarterSource
-
-
- Avalonia.Direct2D1.RenderTests.Media.ImageBrushTests.ImageBrush_NoStretch_NoTile_BottomRightQuarterSource_BottomRightQuarterDest
-
-
- Avalonia.Direct2D1.RenderTests.Media.ImageBrushTests.ImageBrush_NoStretch_Tile_BottomRightQuarterSource_CenterQuarterDest
-
-
- Avalonia.Direct2D1.RenderTests.Media.ImageBrushTests.ImageBrush_Uniform_NoTile
-
-
- Avalonia.Direct2D1.RenderTests.Media.ImageBrushTests.ImageBrush_UniformToFill_NoTile
-
Avalonia.Direct2D1.RenderTests.Controls.ImageTests