Browse Source

WIP: Working on getting VisualBrush working

Don't try to render `VisualBrush`es in TileBrushImpl - visual brushes
need first to be transformed into images and then rendered as an
`ImageBrush`. To this end, renamed `TileBrushImpl` as `ImageBrushImpl`
(in D2D backend only for now as that's what I'll get working first).
Actual visual brush implementation not yet done.
scenegraph-after-breakage
Steven Kirk 9 years ago
parent
commit
e79a144c14
  1. 4
      src/Avalonia.Controls/Image.cs
  2. 1
      src/Avalonia.Visuals/Avalonia.Visuals.csproj
  3. 2
      src/Avalonia.Visuals/Rect.cs
  4. 193
      src/Avalonia.Visuals/Rendering/Utilities/TileBrushCalculator.cs
  5. 16
      src/Avalonia.Visuals/Size.cs
  6. 4
      src/Gtk/Avalonia.Cairo/Media/DrawingContext.cs
  7. 58
      src/Gtk/Avalonia.Cairo/Media/TileBrushes.cs
  8. 2
      src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj
  9. 10
      src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs
  10. 86
      src/Windows/Avalonia.Direct2D1/Media/ImageBrushImpl.cs
  11. 65
      tests/Avalonia.RenderTests/Avalonia.Cairo.RenderTests.v2.ncrunchproject
  12. 1
      tests/Avalonia.Visuals.UnitTests/Avalonia.Visuals.UnitTests.csproj
  13. 139
      tests/Avalonia.Visuals.UnitTests/Rendering/Utilities/TileBrushCalculatorTests.cs

4
src/Avalonia.Controls/Image.cs

@ -63,10 +63,10 @@ namespace Avalonia.Controls
Vector scale = Stretch.CalculateScaling(Bounds.Size, sourceSize);
Size scaledSize = sourceSize * scale;
Rect destRect = viewPort
.CenterIn(new Rect(scaledSize))
.CenterRect(new Rect(scaledSize))
.Intersect(viewPort);
Rect sourceRect = new Rect(sourceSize)
.CenterIn(new Rect(destRect.Size / scale));
.CenterRect(new Rect(destRect.Size / scale));
context.DrawImage(source, 1, sourceRect, destRect);
}

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

@ -135,6 +135,7 @@
<Compile Include="Rendering\SceneGraph\SceneLayers.cs" />
<Compile Include="Rendering\SceneGraph\TextNode.cs" />
<Compile Include="Rendering\SceneGraph\VisualNode.cs" />
<Compile Include="Rendering\Utilities\TileBrushCalculator.cs" />
<Compile Include="Rendering\ZIndexComparer.cs" />
<Compile Include="RenderTargetCorruptedException.cs" />
<Compile Include="Size.cs" />

2
src/Avalonia.Visuals/Rect.cs

@ -238,7 +238,7 @@ namespace Avalonia
/// </summary>
/// <param name="rect">The rectangle to center.</param>
/// <returns>The centered rectangle.</returns>
public Rect CenterIn(Rect rect)
public Rect CenterRect(Rect rect)
{
return new Rect(
_x + ((_width - rect._width) / 2),

193
src/Avalonia.Visuals/Rendering/Utilities/TileBrushCalculator.cs

@ -0,0 +1,193 @@
// 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 Avalonia.Media;
namespace Avalonia.Rendering.Utilities
{
public class TileBrushCalculator
{
private readonly Size _imageSize;
private readonly Rect _drawRect;
public bool IsValid { get; }
/// <summary>
/// Initializes a new instance of the <see cref="TileBrushCalculator"/> class.
/// </summary>
/// <param name="brush">The brush to be rendered.</param>
/// <param name="contentSize">The size of the content of the tile brush.</param>
/// <param name="targetSize">The size of the control to which the brush is being rendered.</param>
public TileBrushCalculator(TileBrush brush, Size contentSize, Size targetSize)
: this(
brush.TileMode,
brush.Stretch,
brush.AlignmentX,
brush.AlignmentY,
brush.SourceRect,
brush.DestinationRect,
contentSize,
targetSize)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="TileBrushCalculator"/> class.
/// </summary>
/// <param name="tileMode">The brush's tile mode.</param>
/// <param name="stretch">The brush's stretch.</param>
/// <param name="alignmentX">The brush's horizontal alignment.</param>
/// <param name="alignmentY">The brush's vertical alignment.</param>
/// <param name="sourceRect">The brush's source rect</param>
/// <param name="destinationRect">The brush's destination rect.</param>
/// <param name="contentSize">The size of the content of the tile brush.</param>
/// <param name="targetSize">The size of the control to which the brush is being rendered.</param>
public TileBrushCalculator(
TileMode tileMode,
Stretch stretch,
AlignmentX alignmentX,
AlignmentY alignmentY,
RelativeRect sourceRect,
RelativeRect destinationRect,
Size contentSize,
Size targetSize)
{
_imageSize = contentSize;
SourceRect = sourceRect.ToPixels(_imageSize);
DestinationRect = destinationRect.ToPixels(targetSize);
var scale = stretch.CalculateScaling(DestinationRect.Size, SourceRect.Size);
var translate = CalculateTranslate(alignmentX, alignmentY, SourceRect, DestinationRect, scale);
IntermediateSize = tileMode == TileMode.None ? targetSize : DestinationRect.Size;
IntermediateTransform = CalculateIntermediateTransform(
tileMode,
SourceRect,
DestinationRect,
scale,
translate,
out _drawRect);
}
/// <summary>
/// Gets the rectangle on the destination control to which content should be rendered.
/// </summary>
/// <remarks>
/// If <see cref="TileMode"/> of the brush is repeating then this is describes rectangle
/// of a single repeat of the tiled content.
/// </remarks>
public Rect DestinationRect { get; }
/// <summary>
/// Gets the clip rectangle on the intermediate image with which the brush content should be
/// drawn when <see cref="NeedsIntermediate"/> is true.
/// </summary>
public Rect IntermediateClip => _drawRect;
/// <summary>
/// Gets the size of the intermediate image that should be created when
/// <see cref="NeedsIntermediate"/> is true.
/// </summary>
public Size IntermediateSize { get; }
/// <summary>
/// Gets the transform to be used when rendering to the intermediate image when
/// <see cref="NeedsIntermediate"/> is true.
/// </summary>
public Matrix IntermediateTransform { get; }
/// <summary>
/// Gets a value indicating whether an intermediate image should be created in order to
/// render the tile brush.
/// </summary>
/// <remarks>
/// Intermediate images are required when a brush's <see cref="TileMode"/> is not repeating
/// but the source and destination aspect ratios are unequal, as all of the currently
/// supported rendering backends do not support non-tiled image brushes.
/// </remarks>
public bool NeedsIntermediate
{
get
{
if (IntermediateTransform != Matrix.Identity)
return true;
if (SourceRect.Position != default(Point))
return true;
if (SourceRect.Size.AspectRatio == _imageSize.AspectRatio)
return false;
if ((int)SourceRect.Width != _imageSize.Width ||
(int)SourceRect.Height != _imageSize.Height)
return true;
return false;
}
}
/// <summary>
/// Gets the area of the source content to be rendered.
/// </summary>
public Rect SourceRect { get; }
public static Vector CalculateTranslate(
AlignmentX alignmentX,
AlignmentY alignmentY,
Rect sourceRect,
Rect destinationRect,
Vector scale)
{
var x = 0.0;
var y = 0.0;
var size = sourceRect.Size * scale;
switch (alignmentX)
{
case AlignmentX.Center:
x += (destinationRect.Width - size.Width) / 2;
break;
case AlignmentX.Right:
x += destinationRect.Width - size.Width;
break;
}
switch (alignmentY)
{
case AlignmentY.Center:
y += (destinationRect.Height - size.Height) / 2;
break;
case AlignmentY.Bottom:
y += destinationRect.Height - size.Height;
break;
}
return new Vector(x, y);
}
public static Matrix CalculateIntermediateTransform(
TileMode tileMode,
Rect sourceRect,
Rect destinationRect,
Vector scale,
Vector translate,
out Rect drawRect)
{
var transform = Matrix.CreateTranslation(-sourceRect.Position) *
Matrix.CreateScale(scale) *
Matrix.CreateTranslation(translate);
Rect dr;
if (tileMode == TileMode.None)
{
dr = destinationRect;
transform *= Matrix.CreateTranslation(destinationRect.Position);
}
else
{
dr = new Rect(destinationRect.Size);
}
drawRect = dr;
return transform;
}
}
}

16
src/Avalonia.Visuals/Size.cs

@ -43,6 +43,11 @@ namespace Avalonia
_height = height;
}
/// <summary>
/// Gets the aspect ratio of the size.
/// </summary>
public double AspectRatio => _width / _height;
/// <summary>
/// Gets the width.
/// </summary>
@ -97,6 +102,17 @@ namespace Avalonia
return new Size(size._width / scale.X, size._height / scale.Y);
}
/// <summary>
/// Divides a size by another size to produce a scaling factor.
/// </summary>
/// <param name="left">The first size</param>
/// <param name="right">The second size.</param>
/// <returns>The scaled size.</returns>
public static Vector operator /(Size left, Size right)
{
return new Vector(left._width / right._width, left._height / right._height);
}
/// <summary>
/// Scales a size.
/// </summary>

4
src/Gtk/Avalonia.Cairo/Media/DrawingContext.cs

@ -317,10 +317,6 @@ namespace Avalonia.Cairo.Media
{
impl = new ImageBrushImpl(imageBrush, destinationSize);
}
else if (visualBrush != null)
{
impl = new VisualBrushImpl(visualBrush, destinationSize);
}
else
{
impl = new SolidColorBrushImpl(null, opacityOverride);

58
src/Gtk/Avalonia.Cairo/Media/TileBrushes.cs

@ -16,40 +16,40 @@ namespace Avalonia.Cairo.Media
{
public static SurfacePattern CreateTileBrush(TileBrush brush, Size targetSize)
{
var helper = new TileBrushImplHelper(brush, targetSize);
if (!helper.IsValid)
return null;
throw new NotImplementedException();
//// var helper = new TileBrushImplHelper(brush, targetSize);
//// if (!helper.IsValid)
//// return null;
using (var intermediate = new ImageSurface(Format.ARGB32, (int)helper.IntermediateSize.Width, (int)helper.IntermediateSize.Height))
using (var ctx = new RenderTarget(intermediate).CreateDrawingContext())
{
helper.DrawIntermediate(new Avalonia.Media.DrawingContext(ctx));
////using (var intermediate = new ImageSurface(Format.ARGB32, (int)helper.IntermediateSize.Width, (int)helper.IntermediateSize.Height))
//// using (var ctx = new RenderTarget(intermediate).CreateDrawingContext())
//// {
//// helper.DrawIntermediate(new Avalonia.Media.DrawingContext(ctx));
var result = new SurfacePattern(intermediate);
//// var result = new SurfacePattern(intermediate);
if ((brush.TileMode & TileMode.FlipXY) != 0)
{
// TODO: Currently always FlipXY as that's all cairo supports natively.
// Support separate FlipX and FlipY by drawing flipped images to intermediate
// surface.
result.Extend = Extend.Reflect;
}
else
{
result.Extend = Extend.Repeat;
}
//// if ((brush.TileMode & TileMode.FlipXY) != 0)
//// {
//// // TODO: Currently always FlipXY as that's all cairo supports natively.
//// // Support separate FlipX and FlipY by drawing flipped images to intermediate
//// // surface.
//// result.Extend = Extend.Reflect;
//// }
//// else
//// {
//// result.Extend = Extend.Repeat;
//// }
if (brush.TileMode != TileMode.None)
{
var matrix = result.Matrix;
matrix.InitTranslate(-helper.DestinationRect.X, -helper.DestinationRect.Y);
result.Matrix = matrix;
}
//// if (brush.TileMode != TileMode.None)
//// {
//// var matrix = result.Matrix;
//// matrix.InitTranslate(-helper.DestinationRect.X, -helper.DestinationRect.Y);
//// result.Matrix = matrix;
//// }
return result;
}
//// return result;
//// }
}
}
}

2
src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj

@ -88,7 +88,7 @@
<Compile Include="Media\LinearGradientBrushImpl.cs" />
<Compile Include="Media\AvaloniaTextRenderer.cs" />
<Compile Include="Media\TransformedGeometryImpl.cs" />
<Compile Include="Media\TileBrushImpl.cs" />
<Compile Include="Media\ImageBrushImpl.cs" />
<Compile Include="Media\SolidColorBrushImpl.cs" />
<Compile Include="Media\StreamGeometryContextImpl.cs" />
<Compile Include="Media\StreamGeometryImpl.cs" />

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

@ -332,11 +332,11 @@ namespace Avalonia.Direct2D1.Media
}
else if (imageBrush != null)
{
return new TileBrushImpl(imageBrush, _renderTarget, destinationSize);
}
else if (visualBrush != null)
{
return new TileBrushImpl(visualBrush, _renderTarget, destinationSize);
return new ImageBrushImpl(
imageBrush,
_renderTarget,
(BitmapImpl)imageBrush.Source.PlatformImpl,
destinationSize);
}
else
{

86
src/Windows/Avalonia.Direct2D1/Media/TileBrushImpl.cs → src/Windows/Avalonia.Direct2D1/Media/ImageBrushImpl.cs

@ -3,50 +3,46 @@
using System;
using Avalonia.Media;
using Avalonia.RenderHelpers;
using Avalonia.Rendering.Utilities;
using SharpDX.Direct2D1;
namespace Avalonia.Direct2D1.Media
{
public sealed class TileBrushImpl : BrushImpl
public sealed class ImageBrushImpl : BrushImpl
{
public TileBrushImpl(
public ImageBrushImpl(
TileBrush brush,
SharpDX.Direct2D1.RenderTarget target,
BitmapImpl bitmap,
Size targetSize)
{
var helper = new TileBrushImplHelper(brush, targetSize);
if (!helper.IsValid)
return;
var calc = new TileBrushCalculator(brush, new Size(bitmap.PixelWidth, bitmap.PixelHeight), targetSize);
using (var intermediate = new BitmapRenderTarget(target, CompatibleRenderTargetOptions.None, helper.IntermediateSize.ToSharpDX()))
if (!calc.NeedsIntermediate)
{
using (var ctx = new RenderTarget(intermediate).CreateDrawingContext())
{
intermediate.Clear(null);
helper.DrawIntermediate(new DrawingContext(ctx));
}
PlatformBrush = new BitmapBrush(
target,
intermediate.Bitmap,
bitmap.GetDirect2DBitmap(target),
GetBitmapBrushProperties(brush),
GetBrushProperties(brush, helper.DestinationRect));
GetBrushProperties(brush, calc.DestinationRect));
}
else
{
using (var intermediate = RenderIntermediate(target, bitmap, calc))
{
PlatformBrush = new BitmapBrush(
target,
intermediate.Bitmap,
GetBitmapBrushProperties(brush),
GetBrushProperties(brush, calc.DestinationRect));
}
}
}
private static BrushProperties GetBrushProperties(TileBrush brush, Rect destinationRect)
public override void Dispose()
{
var tileTransform =
brush.TileMode != TileMode.None ?
Matrix.CreateTranslation(destinationRect.X, destinationRect.Y) :
Matrix.Identity;
return new BrushProperties
{
Opacity = (float)brush.Opacity,
Transform = tileTransform.ToDirect2D(),
};
((BitmapBrush)PlatformBrush)?.Bitmap.Dispose();
base.Dispose();
}
private static BitmapBrushProperties GetBitmapBrushProperties(TileBrush brush)
@ -60,6 +56,20 @@ namespace Avalonia.Direct2D1.Media
};
}
private static BrushProperties GetBrushProperties(TileBrush brush, Rect destinationRect)
{
var tileTransform =
brush.TileMode != TileMode.None ?
Matrix.CreateTranslation(destinationRect.X, destinationRect.Y) :
Matrix.Identity;
return new BrushProperties
{
Opacity = (float)brush.Opacity,
Transform = tileTransform.ToDirect2D(),
};
}
private static ExtendMode GetExtendModeX(TileMode tileMode)
{
return (tileMode & TileMode.FlipX) != 0 ? ExtendMode.Mirror : ExtendMode.Wrap;
@ -70,10 +80,28 @@ namespace Avalonia.Direct2D1.Media
return (tileMode & TileMode.FlipY) != 0 ? ExtendMode.Mirror : ExtendMode.Wrap;
}
public override void Dispose()
private BitmapRenderTarget RenderIntermediate(
SharpDX.Direct2D1.RenderTarget target,
BitmapImpl bitmap,
TileBrushCalculator calc)
{
((BitmapBrush)PlatformBrush)?.Bitmap.Dispose();
base.Dispose();
var result = new BitmapRenderTarget(
target,
CompatibleRenderTargetOptions.None,
calc.IntermediateSize.ToSharpDX());
using (var context = new RenderTarget(result).CreateDrawingContext())
{
var rect = new Rect(0, 0, bitmap.PixelWidth, bitmap.PixelHeight);
context.Clear(Colors.Transparent);
context.PushClip(calc.IntermediateClip);
context.Transform = calc.IntermediateTransform;
context.DrawImage(bitmap, 1, rect, rect);
context.PopClip();
}
return result;
}
}
}

65
tests/Avalonia.RenderTests/Avalonia.Cairo.RenderTests.v2.ncrunchproject

@ -23,5 +23,70 @@
<UseCPUArchitecture>AutoDetect</UseCPUArchitecture>
<MSTestThreadApartmentState>STA</MSTestThreadApartmentState>
<BuildProcessArchitecture>x86</BuildProcessArchitecture>
<IgnoredTests>
<FixtureTestSelector>
<FixtureName>Avalonia.Cairo.RenderTests.Controls.BorderTests</FixtureName>
</FixtureTestSelector>
<NamedTestSelector>
<TestName>Avalonia.Cairo.RenderTests.Media.ImageBrushTests.ImageBrush_Fill_NoTile</TestName>
</NamedTestSelector>
<NamedTestSelector>
<TestName>Avalonia.Cairo.RenderTests.Media.ImageBrushTests.ImageBrush_NoStretch_FlipXY_TopLeftDest</TestName>
</NamedTestSelector>
<NamedTestSelector>
<TestName>Avalonia.Cairo.RenderTests.Media.ImageBrushTests.ImageBrush_NoStretch_NoTile_Alignment_BottomRight</TestName>
</NamedTestSelector>
<NamedTestSelector>
<TestName>Avalonia.Cairo.RenderTests.Media.ImageBrushTests.ImageBrush_NoStretch_NoTile_Alignment_Center</TestName>
</NamedTestSelector>
<NamedTestSelector>
<TestName>Avalonia.Cairo.RenderTests.Media.ImageBrushTests.ImageBrush_NoStretch_NoTile_BottomRightQuarterDest</TestName>
</NamedTestSelector>
<NamedTestSelector>
<TestName>Avalonia.Cairo.RenderTests.Media.ImageBrushTests.ImageBrush_NoStretch_NoTile_BottomRightQuarterSource</TestName>
</NamedTestSelector>
<NamedTestSelector>
<TestName>Avalonia.Cairo.RenderTests.Media.ImageBrushTests.ImageBrush_NoStretch_NoTile_BottomRightQuarterSource_BottomRightQuarterDest</TestName>
</NamedTestSelector>
<NamedTestSelector>
<TestName>Avalonia.Cairo.RenderTests.Media.ImageBrushTests.ImageBrush_NoStretch_Tile_BottomRightQuarterSource_CenterQuarterDest</TestName>
</NamedTestSelector>
<NamedTestSelector>
<TestName>Avalonia.Cairo.RenderTests.Media.ImageBrushTests.ImageBrush_Uniform_NoTile</TestName>
</NamedTestSelector>
<NamedTestSelector>
<TestName>Avalonia.Cairo.RenderTests.Media.ImageBrushTests.ImageBrush_UniformToFill_NoTile</TestName>
</NamedTestSelector>
<FixtureTestSelector>
<FixtureName>Avalonia.Cairo.RenderTests.Controls.ImageTests</FixtureName>
</FixtureTestSelector>
<FixtureTestSelector>
<FixtureName>Avalonia.Cairo.RenderTests.GeometryClippingTests</FixtureName>
</FixtureTestSelector>
<FixtureTestSelector>
<FixtureName>Avalonia.Cairo.RenderTests.Media.LinearGradientBrushTests</FixtureName>
</FixtureTestSelector>
<FixtureTestSelector>
<FixtureName>Avalonia.Cairo.RenderTests.Media.VisualBrushTests</FixtureName>
</FixtureTestSelector>
<FixtureTestSelector>
<FixtureName>Avalonia.Cairo.RenderTests.OpacityMaskTests</FixtureName>
</FixtureTestSelector>
<FixtureTestSelector>
<FixtureName>Avalonia.Cairo.RenderTests.Shapes.EllipseTests</FixtureName>
</FixtureTestSelector>
<FixtureTestSelector>
<FixtureName>Avalonia.Cairo.RenderTests.Shapes.LineTests</FixtureName>
</FixtureTestSelector>
<FixtureTestSelector>
<FixtureName>Avalonia.Cairo.RenderTests.Shapes.PathTests</FixtureName>
</FixtureTestSelector>
<FixtureTestSelector>
<FixtureName>Avalonia.Cairo.RenderTests.Shapes.RectangleTests</FixtureName>
</FixtureTestSelector>
<NamedTestSelector>
<TestName>Avalonia.Cairo.RenderTests.Media.ImageBrushTests.ImageBrush_NoStretch_NoTile_Alignment_TopLeft</TestName>
</NamedTestSelector>
</IgnoredTests>
<HiddenWarnings>AbnormalReferenceResolution</HiddenWarnings>
</ProjectConfiguration>

1
tests/Avalonia.Visuals.UnitTests/Avalonia.Visuals.UnitTests.csproj

@ -88,6 +88,7 @@
<Compile Include="Rendering\SceneGraph\SceneLayersTests.cs" />
<Compile Include="Rendering\SceneGraph\SceneTests.cs" />
<Compile Include="Rendering\SceneGraph\VisualNodeTests.cs" />
<Compile Include="Rendering\Utilities\TileBrushCalculatorTests.cs" />
<Compile Include="ThicknessTests.cs" />
<Compile Include="Media\BrushTests.cs" />
<Compile Include="Media\ColorTests.cs" />

139
tests/Avalonia.Visuals.UnitTests/Rendering/Utilities/TileBrushCalculatorTests.cs

@ -0,0 +1,139 @@
using System;
using Avalonia.Controls;
using Avalonia.Media;
using Avalonia.Rendering.Utilities;
using Xunit;
namespace Avalonia.Visuals.UnitTests.Rendering.Utilities
{
public class TileBrushCalculatorTests
{
[Fact]
public void NoTile_Fill_1x()
{
var result = new TileBrushCalculator(
TileMode.None,
Stretch.Fill,
AlignmentX.Center,
AlignmentY.Center,
RelativeRect.Fill,
RelativeRect.Fill,
new Size(100, 100),
new Size(100, 100));
Assert.False(result.NeedsIntermediate);
Assert.Equal(new Rect(0, 0, 100, 100), result.SourceRect);
Assert.Equal(new Rect(0, 0, 100, 100), result.DestinationRect);
}
[Fact]
public void NoTile_Fill_2x()
{
var result = new TileBrushCalculator(
TileMode.None,
Stretch.Fill,
AlignmentX.Center,
AlignmentY.Center,
RelativeRect.Fill,
RelativeRect.Fill,
new Size(100, 100),
new Size(200, 200));
// TODO: This doesn't need an intermediate render target.
Assert.True(result.NeedsIntermediate);
Assert.Equal(new Rect(0, 0, 100, 100), result.SourceRect);
Assert.Equal(new Rect(0, 0, 200, 200), result.DestinationRect);
}
[Fact]
public void NoTile_Uniform_CenterHoriz()
{
var result = new TileBrushCalculator(
TileMode.None,
Stretch.Uniform,
AlignmentX.Center,
AlignmentY.Center,
RelativeRect.Fill,
RelativeRect.Fill,
new Size(100, 100),
new Size(200, 100));
Assert.True(result.NeedsIntermediate);
Assert.Equal(new Rect(0, 0, 100, 100), result.SourceRect);
Assert.Equal(new Rect(0, 0, 200, 100), result.DestinationRect);
Assert.Equal(new Size(200, 100), result.IntermediateSize);
Assert.Equal(Matrix.CreateTranslation(50, 0), result.IntermediateTransform);
}
[Fact]
public void NoTile_Uniform_CenterVert()
{
var result = new TileBrushCalculator(
TileMode.None,
Stretch.Uniform,
AlignmentX.Center,
AlignmentY.Center,
RelativeRect.Fill,
RelativeRect.Fill,
new Size(100, 100),
new Size(100, 200));
Assert.True(result.NeedsIntermediate);
Assert.Equal(new Rect(0, 0, 100, 100), result.SourceRect);
Assert.Equal(new Rect(0, 0, 100, 200), result.DestinationRect);
Assert.Equal(new Size(100, 200), result.IntermediateSize);
Assert.Equal(Matrix.CreateTranslation(0, 50), result.IntermediateTransform);
}
[Fact]
public void NoTile_NoStretch_BottomRightQuarterDest()
{
var result = new TileBrushCalculator(
TileMode.None,
Stretch.None,
AlignmentX.Center,
AlignmentY.Center,
RelativeRect.Fill,
new RelativeRect(0.5, 0.5, 0.5, 0.5, RelativeUnit.Relative),
new Size(800, 800),
new Size(400, 400));
Assert.True(result.NeedsIntermediate);
Assert.Equal(new Rect(0, 0, 800, 800), result.SourceRect);
Assert.Equal(new Rect(200, 200, 200, 200), result.DestinationRect);
Assert.Equal(new Size(400, 400), result.IntermediateSize);
Assert.Equal(new Rect(200, 200, 200, 200), result.IntermediateClip);
Assert.Equal(Matrix.CreateTranslation(-100, -100), result.IntermediateTransform);
}
[Fact]
public void Tile_NoStretch_BottomRightQuarterSource_CenterQuarterDest()
{
var result = new TileBrushCalculator(
TileMode.Tile,
Stretch.None,
AlignmentX.Center,
AlignmentY.Center,
new RelativeRect(0.5, 0.5, 0.5, 0.5, RelativeUnit.Relative),
new RelativeRect(0.25, 0.25, 0.5, 0.5, RelativeUnit.Relative),
new Size(800, 800),
new Size(400, 400));
var b = new VisualBrush
{
TileMode = TileMode.Tile,
Stretch = Stretch.None,
SourceRect = new RelativeRect(0.5, 0.5, 0.5, 0.5, RelativeUnit.Relative),
DestinationRect = new RelativeRect(0.25, 0.25, 0.5, 0.5, RelativeUnit.Relative),
Visual = new Border { Width = 400, Height = 400 },
};
Assert.True(result.NeedsIntermediate);
Assert.Equal(new Rect(400, 400, 400, 400), result.SourceRect);
Assert.Equal(new Rect(100, 100, 200, 200), result.DestinationRect);
Assert.Equal(new Size(200, 200), result.IntermediateSize);
Assert.Equal(new Rect(0, 0, 200, 200), result.IntermediateClip);
Assert.Equal(Matrix.CreateTranslation(-500, -500), result.IntermediateTransform);
}
}
}
Loading…
Cancel
Save