Browse Source
Conflicts: src/Avalonia.Visuals/Platform/IRenderTarget.cs src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs src/Gtk/Avalonia.Cairo/Media/DrawingContext.cs src/Gtk/Avalonia.Cairo/Media/ImageBrushImpl.cs src/Shared/RenderHelpers/TileBrushImplHelper.cs src/Skia/Avalonia.Skia/BitmapImpl.cs src/Skia/Avalonia.Skia/DrawingContextImpl.cs src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs src/Windows/Avalonia.Direct2D1/Media/Imaging/RenderTargetBitmapImpl.cs src/Windows/Avalonia.Direct2D1/RenderTarget.cs src/Windows/Avalonia.Direct2D1/SwapChainRenderTarget.cs src/Windows/Avalonia.Win32/Win32Platform.cs tests/Avalonia.UnitTests/TestServices.cs tests/Avalonia.Visuals.UnitTests/VisualTests.cs tests/Avalonia.Visuals.UnitTests/VisualTree/VisualExtensionsTests_GetVisualsAt.csscenegraph-after-breakage
22 changed files with 41 additions and 420 deletions
@ -1,55 +0,0 @@ |
|||
// 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 Cairo; |
|||
using Avalonia.Cairo.Media.Imaging; |
|||
using Avalonia.Layout; |
|||
using Avalonia.Media; |
|||
using Avalonia.Platform; |
|||
using Avalonia.Rendering; |
|||
using Avalonia.RenderHelpers; |
|||
|
|||
namespace Avalonia.Cairo.Media |
|||
{ |
|||
internal static class TileBrushes |
|||
{ |
|||
public static SurfacePattern CreateTileBrush(ITileBrush brush, Size targetSize) |
|||
{ |
|||
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(ctx); |
|||
|
|||
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.None) |
|||
{ |
|||
var matrix = result.Matrix; |
|||
matrix.InitTranslate(-helper.DestinationRect.X, -helper.DestinationRect.Y); |
|||
result.Matrix = matrix; |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
} |
|||
|
|||
|
|||
} |
|||
} |
|||
@ -1,15 +0,0 @@ |
|||
using System; |
|||
using Avalonia.Media; |
|||
using global::Cairo; |
|||
|
|||
namespace Avalonia.Cairo.Media |
|||
{ |
|||
public class VisualBrushImpl : BrushImpl |
|||
{ |
|||
public VisualBrushImpl(IVisualBrush brush, Size destinationSize) |
|||
{ |
|||
this.PlatformBrush = TileBrushes.CreateTileBrush(brush, destinationSize); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,213 +0,0 @@ |
|||
// 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.Controls; |
|||
using Avalonia.Media; |
|||
using Avalonia.Rendering; |
|||
using Avalonia.VisualTree; |
|||
|
|||
namespace Avalonia.RenderHelpers |
|||
{ |
|||
internal class TileBrushImplHelper |
|||
{ |
|||
public Size IntermediateSize { get; } |
|||
public Rect DestinationRect { get; } |
|||
private readonly TileMode _tileMode; |
|||
private readonly Rect _sourceRect; |
|||
private readonly Vector _scale; |
|||
private readonly Vector _translate; |
|||
private readonly Size _imageSize; |
|||
private readonly IVisualBrush _visualBrush; |
|||
private readonly IImageBrush _imageBrush; |
|||
private readonly Matrix _transform; |
|||
private readonly Rect _drawRect; |
|||
|
|||
public bool IsValid { get; } |
|||
|
|||
public TileBrushImplHelper(ITileBrush brush, Size targetSize) |
|||
{ |
|||
_imageBrush = brush as IImageBrush; |
|||
_visualBrush = brush as IVisualBrush; |
|||
if (_imageBrush != null) |
|||
{ |
|||
if (_imageBrush.Source == null) |
|||
return; |
|||
_imageSize = new Size(_imageBrush.Source.PixelWidth, _imageBrush.Source.PixelHeight); |
|||
IsValid = true; |
|||
} |
|||
else if (_visualBrush != null) |
|||
{ |
|||
var control = _visualBrush.Visual as IControl; |
|||
|
|||
if (control != null) |
|||
{ |
|||
EnsureInitialized(control); |
|||
_imageSize = control.Bounds.Size; |
|||
IsValid = true; |
|||
} |
|||
} |
|||
else |
|||
return; |
|||
|
|||
_tileMode = brush.TileMode; |
|||
_sourceRect = brush.SourceRect.ToPixels(_imageSize); |
|||
DestinationRect = brush.DestinationRect.ToPixels(targetSize); |
|||
_scale = brush.Stretch.CalculateScaling(DestinationRect.Size, _sourceRect.Size); |
|||
_translate = CalculateTranslate(brush, _sourceRect, DestinationRect, _scale); |
|||
IntermediateSize = CalculateIntermediateSize(_tileMode, targetSize, DestinationRect.Size); |
|||
_transform = CalculateIntermediateTransform( |
|||
_tileMode, |
|||
_sourceRect, |
|||
DestinationRect, |
|||
_scale, |
|||
_translate, |
|||
out _drawRect); |
|||
} |
|||
|
|||
public bool NeedsIntermediateSurface |
|||
{ |
|||
get |
|||
{ |
|||
if (_imageBrush == null) |
|||
return true; |
|||
if (_transform != Matrix.Identity) |
|||
return true; |
|||
if (_sourceRect.Position != default(Point)) |
|||
return true; |
|||
if ((int) _sourceRect.Width != _imageBrush.Source.PixelWidth || |
|||
(int) _sourceRect.Height != _imageBrush.Source.PixelHeight) |
|||
return true; |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
public T GetDirect<T>() => (T) _imageBrush?.Source.PlatformImpl; |
|||
|
|||
public void DrawIntermediate(DrawingContext ctx) |
|||
{ |
|||
using (ctx.PushClip(_drawRect)) |
|||
using (ctx.PushPostTransform(_transform)) |
|||
{ |
|||
if (_imageBrush != null) |
|||
{ |
|||
var bmpRc = new Rect(0, 0, _imageBrush.Source.PixelWidth, _imageBrush.Source.PixelHeight); |
|||
ctx.DrawImage(_imageBrush.Source, 1, bmpRc, bmpRc); |
|||
} |
|||
else if (_visualBrush != null) |
|||
{ |
|||
using (ctx.PushPostTransform(Matrix.CreateTranslation(-_visualBrush.Visual.Bounds.Position))) |
|||
{ |
|||
ImmediateRenderer.Render(_visualBrush.Visual, ctx); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
/// <summary>
|
|||
/// Calculates a translate based on an <see cref="ITileBrush"/>, a source and destination
|
|||
/// rectangle and a scale.
|
|||
/// </summary>
|
|||
/// <param name="brush">The brush.</param>
|
|||
/// <param name="sourceRect">The source rectangle.</param>
|
|||
/// <param name="destinationRect">The destination rectangle.</param>
|
|||
/// <param name="scale">The _scale factor.</param>
|
|||
/// <returns>A vector with the X and Y _translate.</returns>
|
|||
|
|||
public static Vector CalculateTranslate( |
|||
ITileBrush brush, |
|||
Rect sourceRect, |
|||
Rect destinationRect, |
|||
Vector scale) |
|||
{ |
|||
var x = 0.0; |
|||
var y = 0.0; |
|||
var size = sourceRect.Size*scale; |
|||
|
|||
switch (brush.AlignmentX) |
|||
{ |
|||
case AlignmentX.Center: |
|||
x += (destinationRect.Width - size.Width)/2; |
|||
break; |
|||
case AlignmentX.Right: |
|||
x += destinationRect.Width - size.Width; |
|||
break; |
|||
} |
|||
|
|||
switch (brush.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; |
|||
} |
|||
|
|||
public static void EnsureInitialized(IVisual visual) |
|||
{ |
|||
var control = visual as IControl; |
|||
|
|||
if (control != null) |
|||
{ |
|||
foreach (var i in control.GetSelfAndVisualDescendents()) |
|||
{ |
|||
var c = i as IControl; |
|||
|
|||
if (c?.IsInitialized == false) |
|||
{ |
|||
var init = c as ISupportInitialize; |
|||
|
|||
if (init != null) |
|||
{ |
|||
init.BeginInit(); |
|||
init.EndInit(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
if (!control.IsArrangeValid) |
|||
{ |
|||
control.Measure(Size.Infinity); |
|||
control.Arrange(new Rect(control.DesiredSize)); |
|||
} |
|||
} |
|||
} |
|||
|
|||
private static Size CalculateIntermediateSize( |
|||
TileMode tileMode, |
|||
Size targetSize, |
|||
Size destinationSize) => tileMode == TileMode.None ? targetSize : destinationSize; |
|||
} |
|||
} |
|||
@ -1,78 +0,0 @@ |
|||
// 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; |
|||
using Avalonia.RenderHelpers; |
|||
using SharpDX.Direct2D1; |
|||
|
|||
namespace Avalonia.Direct2D1.Media |
|||
{ |
|||
public sealed class TileBrushImpl : BrushImpl |
|||
{ |
|||
public TileBrushImpl( |
|||
ITileBrush brush, |
|||
SharpDX.Direct2D1.RenderTarget target, |
|||
Size targetSize) |
|||
{ |
|||
var helper = new TileBrushImplHelper(brush, targetSize); |
|||
if (!helper.IsValid) |
|||
return; |
|||
|
|||
using (var intermediate = new BitmapRenderTarget(target, CompatibleRenderTargetOptions.None, helper.IntermediateSize.ToSharpDX())) |
|||
{ |
|||
using (var ctx = new RenderTarget(intermediate).CreateDrawingContext()) |
|||
{ |
|||
intermediate.Clear(null); |
|||
helper.DrawIntermediate(ctx); |
|||
} |
|||
|
|||
PlatformBrush = new BitmapBrush( |
|||
target, |
|||
intermediate.Bitmap, |
|||
GetBitmapBrushProperties(brush), |
|||
GetBrushProperties(brush, helper.DestinationRect)); |
|||
} |
|||
} |
|||
|
|||
private static BrushProperties GetBrushProperties(ITileBrush 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 BitmapBrushProperties GetBitmapBrushProperties(ITileBrush brush) |
|||
{ |
|||
var tileMode = brush.TileMode; |
|||
|
|||
return new BitmapBrushProperties |
|||
{ |
|||
ExtendModeX = GetExtendModeX(tileMode), |
|||
ExtendModeY = GetExtendModeY(tileMode), |
|||
}; |
|||
} |
|||
|
|||
private static ExtendMode GetExtendModeX(TileMode tileMode) |
|||
{ |
|||
return (tileMode & TileMode.FlipX) != 0 ? ExtendMode.Mirror : ExtendMode.Wrap; |
|||
} |
|||
|
|||
private static ExtendMode GetExtendModeY(TileMode tileMode) |
|||
{ |
|||
return (tileMode & TileMode.FlipY) != 0 ? ExtendMode.Mirror : ExtendMode.Wrap; |
|||
} |
|||
|
|||
public override void Dispose() |
|||
{ |
|||
((BitmapBrush)PlatformBrush)?.Bitmap.Dispose(); |
|||
base.Dispose(); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue