From 23b5706a21a7e5ff236f81db3ccf8cf71a5d3628 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Tue, 3 Nov 2015 19:39:00 +0300 Subject: [PATCH] Switched cairo to use xplat Visual/ImageBrush code --- Perspex.sln | 3 +- src/Gtk/Perspex.Cairo/Media/ImageBrushImpl.cs | 2 +- src/Gtk/Perspex.Cairo/Media/TileBrushes.cs | 186 +----------------- .../Perspex.Cairo/Media/VisualBrushImpl.cs | 2 +- src/Gtk/Perspex.Cairo/Perspex.Cairo.csproj | 1 + 5 files changed, 13 insertions(+), 181 deletions(-) diff --git a/Perspex.sln b/Perspex.sln index f5f1c367b4..e3fa298f74 100644 --- a/Perspex.sln +++ b/Perspex.sln @@ -108,10 +108,11 @@ Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "RenderHelpers", "src\Shared EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution + src\Shared\RenderHelpers\RenderHelpers.projitems*{fb05ac90-89ba-4f2f-a924-f37875fb547c}*SharedItemsImports = 4 src\Shared\PlatformSupport\PlatformSupport.projitems*{e4d9629c-f168-4224-3f51-a5e482ffbc42}*SharedItemsImports = 13 src\Shared\PlatformSupport\PlatformSupport.projitems*{db070a10-bf39-4752-8456-86e9d5928478}*SharedItemsImports = 4 src\Shared\PlatformSupport\PlatformSupport.projitems*{54f237d5-a70a-4752-9656-0c70b1a7b047}*SharedItemsImports = 4 - Shared\RenderHelpers\RenderHelpers.projitems*{3c4c0cb4-0c0f-4450-a37b-148c84ff905f}*SharedItemsImports = 13 + src\Shared\RenderHelpers\RenderHelpers.projitems*{3c4c0cb4-0c0f-4450-a37b-148c84ff905f}*SharedItemsImports = 13 src\Shared\PlatformSupport\PlatformSupport.projitems*{811a76cf-1cf6-440f-963b-bbe31bd72a82}*SharedItemsImports = 4 src\Shared\RenderHelpers\RenderHelpers.projitems*{3e908f67-5543-4879-a1dc-08eace79b3cd}*SharedItemsImports = 4 EndGlobalSection diff --git a/src/Gtk/Perspex.Cairo/Media/ImageBrushImpl.cs b/src/Gtk/Perspex.Cairo/Media/ImageBrushImpl.cs index d6c781619c..0a7dedc1a7 100644 --- a/src/Gtk/Perspex.Cairo/Media/ImageBrushImpl.cs +++ b/src/Gtk/Perspex.Cairo/Media/ImageBrushImpl.cs @@ -7,7 +7,7 @@ namespace Perspex.Cairo.Media { public ImageBrushImpl(Perspex.Media.ImageBrush brush, Size destinationSize) { - this.PlatformBrush = TileBrushes.CreateImageBrush(brush, destinationSize); + this.PlatformBrush = TileBrushes.CreateTileBrush(brush, destinationSize); } } } diff --git a/src/Gtk/Perspex.Cairo/Media/TileBrushes.cs b/src/Gtk/Perspex.Cairo/Media/TileBrushes.cs index 98361427f0..91262ce714 100644 --- a/src/Gtk/Perspex.Cairo/Media/TileBrushes.cs +++ b/src/Gtk/Perspex.Cairo/Media/TileBrushes.cs @@ -8,115 +8,22 @@ using Perspex.Layout; using Perspex.Media; using Perspex.Platform; using Perspex.Rendering; +using Perspex.RenderHelpers; namespace Perspex.Cairo.Media { internal static class TileBrushes { - public static SurfacePattern CreateImageBrush(ImageBrush brush, Size targetSize) + public static SurfacePattern CreateTileBrush(TileBrush brush, Size targetSize) { - if (brush.Source == null) - { + var helper = new TileBrushImplHelper(brush, targetSize); + if (!helper.IsValid) return null; - } - - // TODO: This is directly ported from Direct2D and could probably be made more - // efficient on cairo by taking advantage of the fact that cairo has Extend.None. - var image = ((BitmapImpl)brush.Source.PlatformImpl).Surface; - var imageSize = new Size(brush.Source.PixelWidth, brush.Source.PixelHeight); - var tileMode = brush.TileMode; - var sourceRect = brush.SourceRect.ToPixels(imageSize); - var destinationRect = brush.DestinationRect.ToPixels(targetSize); - var scale = brush.Stretch.CalculateScaling(destinationRect.Size, sourceRect.Size); - var translate = CalculateTranslate(brush, sourceRect, destinationRect, scale); - var intermediateSize = CalculateIntermediateSize(tileMode, targetSize, destinationRect.Size); - - var intermediate = new ImageSurface (Format.ARGB32, (int)intermediateSize.Width, (int)intermediateSize.Height); - using (var context = new Context(intermediate)) - { - Rect drawRect; - var transform = CalculateIntermediateTransform( - tileMode, - sourceRect, - destinationRect, - scale, - translate, - out drawRect); - context.Rectangle(drawRect.ToCairo()); - context.Clip(); - context.Transform(transform.ToCairo()); - Gdk.CairoHelper.SetSourcePixbuf(context, image, 0, 0); - context.Rectangle(0, 0, imageSize.Width, imageSize.Height); - context.Fill(); - - 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(-destinationRect.X, -destinationRect.Y); - result.Matrix = matrix; - } - - return result; - } - } - - public static SurfacePattern CreateVisualBrush(VisualBrush brush, Size targetSize) - { - var visual = brush.Visual; - - if (visual == null) - { - return null; - } - - var layoutable = visual as ILayoutable; - - if (layoutable?.IsArrangeValid == false) - { - layoutable.Measure(Size.Infinity); - layoutable.Arrange(new Rect(layoutable.DesiredSize)); - } - - // TODO: This is directly ported from Direct2D and could probably be made more - // efficient on cairo by taking advantage of the fact that cairo has Extend.None. - var tileMode = brush.TileMode; - var sourceRect = brush.SourceRect.ToPixels(layoutable.Bounds.Size); - var destinationRect = brush.DestinationRect.ToPixels(targetSize); - var scale = brush.Stretch.CalculateScaling(destinationRect.Size, sourceRect.Size); - var translate = CalculateTranslate(brush, sourceRect, destinationRect, scale); - var intermediateSize = CalculateIntermediateSize(tileMode, targetSize, destinationRect.Size); - using (var intermediate = new ImageSurface(Format.ARGB32, (int)intermediateSize.Width, (int)intermediateSize.Height)) + using (var intermediate = new ImageSurface(Format.ARGB32, (int)helper.IntermediateSize.Width, (int)helper.IntermediateSize.Height)) using (var ctx = new RenderTarget(intermediate).CreateDrawingContext()) { - Rect drawRect; - var transform = CalculateIntermediateTransform( - tileMode, - sourceRect, - destinationRect, - scale, - translate, - out drawRect); - - using (ctx.PushClip(drawRect)) - using (ctx.PushPostTransform(transform)) - { - ctx.Render(visual); - } + helper.DrawIntermediate(ctx); var result = new SurfacePattern(intermediate); @@ -135,7 +42,7 @@ namespace Perspex.Cairo.Media if (brush.TileMode != TileMode.None) { var matrix = result.Matrix; - matrix.InitTranslate(-destinationRect.X, -destinationRect.Y); + matrix.InitTranslate(-helper.DestinationRect.X, -helper.DestinationRect.Y); result.Matrix = matrix; } @@ -143,83 +50,6 @@ namespace Perspex.Cairo.Media } } - /// - /// Calculates a translate based on a , a source and destination - /// rectangle and a scale. - /// - /// The brush. - /// The source rectangle. - /// The destination rectangle. - /// The scale factor. - /// A vector with the X and Y translate. - private static Vector CalculateTranslate( - TileBrush 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); - } - - private static Size CalculateIntermediateSize( - TileMode tileMode, - Size targetSize, - Size destinationSize) - { - var result = tileMode == TileMode.None ? targetSize : destinationSize; - return result; - } - - private 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; - } + } } diff --git a/src/Gtk/Perspex.Cairo/Media/VisualBrushImpl.cs b/src/Gtk/Perspex.Cairo/Media/VisualBrushImpl.cs index 634b2b38a5..39a3c9afde 100644 --- a/src/Gtk/Perspex.Cairo/Media/VisualBrushImpl.cs +++ b/src/Gtk/Perspex.Cairo/Media/VisualBrushImpl.cs @@ -7,7 +7,7 @@ namespace Perspex.Cairo.Media { public VisualBrushImpl(Perspex.Media.VisualBrush brush, Size destinationSize) { - this.PlatformBrush = TileBrushes.CreateVisualBrush(brush, destinationSize); + this.PlatformBrush = TileBrushes.CreateTileBrush(brush, destinationSize); } } } diff --git a/src/Gtk/Perspex.Cairo/Perspex.Cairo.csproj b/src/Gtk/Perspex.Cairo/Perspex.Cairo.csproj index 77deb8f6b3..a27683de49 100644 --- a/src/Gtk/Perspex.Cairo/Perspex.Cairo.csproj +++ b/src/Gtk/Perspex.Cairo/Perspex.Cairo.csproj @@ -93,6 +93,7 @@ +