From 141ce8796056e3ee5645b75f5e519e90df770932 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Tue, 3 Nov 2015 19:27:31 +0300 Subject: [PATCH 01/18] Extracted ImageBrush/VisualBrush parts from Direct2D backend --- Perspex.sln | 5 + Shared/RenderHelpers/RenderHelpers.projitems | 14 ++ Shared/RenderHelpers/RenderHelpers.shproj | 13 ++ Shared/RenderHelpers/TileBrushImplHelper.cs | 174 ++++++++++++++++++ .../Perspex.Direct2D1/Media/DrawingContext.cs | 4 +- .../Perspex.Direct2D1/Media/ImageBrushImpl.cs | 94 ---------- .../Perspex.Direct2D1/Media/TileBrushImpl.cs | 92 ++------- .../Media/VisualBrushImpl.cs | 73 -------- .../Perspex.Direct2D1.csproj | 3 +- 9 files changed, 227 insertions(+), 245 deletions(-) create mode 100644 Shared/RenderHelpers/RenderHelpers.projitems create mode 100644 Shared/RenderHelpers/RenderHelpers.shproj create mode 100644 Shared/RenderHelpers/TileBrushImplHelper.cs delete mode 100644 src/Windows/Perspex.Direct2D1/Media/ImageBrushImpl.cs delete mode 100644 src/Windows/Perspex.Direct2D1/Media/VisualBrushImpl.cs diff --git a/Perspex.sln b/Perspex.sln index 9ddce7d51e..fdba885ee8 100644 --- a/Perspex.sln +++ b/Perspex.sln @@ -104,12 +104,16 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BindingTest", "samples\Bind EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XamlTestApplicationPcl", "samples\XamlTestApplicationPcl\XamlTestApplicationPcl.csproj", "{EA113F1A-D8D7-4142-9948-353270E7EBAE}" EndProject +Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "RenderHelpers", "Shared\RenderHelpers\RenderHelpers.shproj", "{3C4C0CB4-0C0F-4450-A37B-148C84FF905F}" +EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution 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\PlatformSupport\PlatformSupport.projitems*{811a76cf-1cf6-440f-963b-bbe31bd72a82}*SharedItemsImports = 4 + Shared\RenderHelpers\RenderHelpers.projitems*{3e908f67-5543-4879-a1dc-08eace79b3cd}*SharedItemsImports = 4 EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -289,5 +293,6 @@ Global {8EF392D5-1416-45AA-9956-7CBBC3229E8A} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162} = {9B9E3891-2366-4253-A952-D08BCEB71098} {EA113F1A-D8D7-4142-9948-353270E7EBAE} = {9B9E3891-2366-4253-A952-D08BCEB71098} + {3C4C0CB4-0C0F-4450-A37B-148C84FF905F} = {A689DEF5-D50F-4975-8B72-124C9EB54066} EndGlobalSection EndGlobal diff --git a/Shared/RenderHelpers/RenderHelpers.projitems b/Shared/RenderHelpers/RenderHelpers.projitems new file mode 100644 index 0000000000..a34993265f --- /dev/null +++ b/Shared/RenderHelpers/RenderHelpers.projitems @@ -0,0 +1,14 @@ + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + true + 3c4c0cb4-0c0f-4450-a37b-148c84ff905f + + + Perspex.RenderHelpers + + + + + \ No newline at end of file diff --git a/Shared/RenderHelpers/RenderHelpers.shproj b/Shared/RenderHelpers/RenderHelpers.shproj new file mode 100644 index 0000000000..00bfd089b9 --- /dev/null +++ b/Shared/RenderHelpers/RenderHelpers.shproj @@ -0,0 +1,13 @@ + + + + 3c4c0cb4-0c0f-4450-a37b-148c84ff905f + 14.0 + + + + + + + + diff --git a/Shared/RenderHelpers/TileBrushImplHelper.cs b/Shared/RenderHelpers/TileBrushImplHelper.cs new file mode 100644 index 0000000000..bf5d3e96bf --- /dev/null +++ b/Shared/RenderHelpers/TileBrushImplHelper.cs @@ -0,0 +1,174 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using Perspex; +using Perspex.Media; +using Perspex.Rendering; +using Perspex.Layout; + + +namespace Perspex.RenderHelpers +{ + 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 VisualBrush _visualBrush; + private readonly ImageBrush _imageBrush; + + public bool IsValid { get; } + + + public TileBrushImplHelper(TileBrush brush, Size targetSize) + { + _imageBrush = brush as ImageBrush; + _visualBrush = brush as VisualBrush; + if (_imageBrush != null) + { + if (_imageBrush.Source == null) + return; + _imageSize = new Size(_imageBrush.Source.PixelWidth, _imageBrush.Source.PixelHeight); + IsValid = true; + } + else if (_visualBrush != null) + { + var visual = _visualBrush.Visual; + if (visual == null) + return; + var layoutable = visual as ILayoutable; + + if (layoutable?.IsArrangeValid == false) + { + layoutable.Measure(Size.Infinity); + layoutable.Arrange(new Rect(layoutable.DesiredSize)); + } + //I have no idea why are we using layoutable after `as` cast, but it was in original VisualBrush code by @grokys + _imageSize = layoutable.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); + } + + public void DrawIntermediate(DrawingContext ctx) + { + Rect drawRect; + var transform = CalculateIntermediateTransform( + _tileMode, + _sourceRect, + DestinationRect, + _scale, + _translate, + out drawRect); + 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) + { + ctx.FillRectangle(Brushes.Black, new Rect(new Point(0, 0), IntermediateSize)); + ctx.Render(_visualBrush.Visual); + } + } + } + + + /// + /// 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. + + public 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); + } + + + 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; + } + + + + + static Size CalculateIntermediateSize( + TileMode tileMode, + Size targetSize, + Size destinationSize) => tileMode == TileMode.None ? targetSize : destinationSize; + + } +} \ No newline at end of file diff --git a/src/Windows/Perspex.Direct2D1/Media/DrawingContext.cs b/src/Windows/Perspex.Direct2D1/Media/DrawingContext.cs index b10208d7e0..fc4418f682 100644 --- a/src/Windows/Perspex.Direct2D1/Media/DrawingContext.cs +++ b/src/Windows/Perspex.Direct2D1/Media/DrawingContext.cs @@ -312,11 +312,11 @@ namespace Perspex.Direct2D1.Media } else if (imageBrush != null) { - return new ImageBrushImpl(imageBrush, _renderTarget, destinationSize); + return new TileBrushImpl(imageBrush, _renderTarget, destinationSize); } else if (visualBrush != null) { - return new VisualBrushImpl(visualBrush, _renderTarget, destinationSize); + return new TileBrushImpl(visualBrush, _renderTarget, destinationSize); } else { diff --git a/src/Windows/Perspex.Direct2D1/Media/ImageBrushImpl.cs b/src/Windows/Perspex.Direct2D1/Media/ImageBrushImpl.cs deleted file mode 100644 index c518b6438f..0000000000 --- a/src/Windows/Perspex.Direct2D1/Media/ImageBrushImpl.cs +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using Perspex.Media; -using SharpDX.Direct2D1; - -namespace Perspex.Direct2D1.Media -{ - public class ImageBrushImpl : TileBrushImpl - { - public ImageBrushImpl( - ImageBrush brush, - SharpDX.Direct2D1.RenderTarget target, - Size targetSize) - { - if (brush.Source == null) - { - return; - } - - var image = ((BitmapImpl)brush.Source.PlatformImpl).GetDirect2DBitmap(target); - 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 brtOpts = CompatibleRenderTargetOptions.None; - - // TODO: There are times where we don't need to draw an intermediate bitmap. Identify - // them and directly use 'image' in those cases. - using (var intermediate = new BitmapRenderTarget(target, brtOpts, intermediateSize)) - { - Rect drawRect; - var transform = CalculateIntermediateTransform( - tileMode, - sourceRect, - destinationRect, - scale, - translate, - out drawRect); - - intermediate.BeginDraw(); - intermediate.PushAxisAlignedClip(drawRect.ToDirect2D(), AntialiasMode.Aliased); - intermediate.Transform = transform.ToDirect2D(); - intermediate.DrawBitmap(image, 1, BitmapInterpolationMode.Linear); - intermediate.PopAxisAlignedClip(); - intermediate.EndDraw(); - - this.PlatformBrush = new BitmapBrush( - target, - intermediate.Bitmap, - GetBitmapBrushProperties(brush), - GetBrushProperties(brush, destinationRect)); - } - } - - private BitmapBrush CreateDirectBrush( - ImageBrush brush, - SharpDX.Direct2D1.RenderTarget target, - Bitmap image, - Rect sourceRect, - Rect destinationRect) - { - var tileMode = brush.TileMode; - var scale = brush.Stretch.CalculateScaling(destinationRect.Size, sourceRect.Size); - var translate = CalculateTranslate(brush, sourceRect, destinationRect, scale); - var transform = Matrix.CreateTranslation(-sourceRect.Position) * - Matrix.CreateScale(scale) * - Matrix.CreateTranslation(translate); - - var opts = new BrushProperties - { - Transform = transform.ToDirect2D(), - Opacity = (float)brush.Opacity, - }; - - var bitmapOpts = new BitmapBrushProperties - { - ExtendModeX = GetExtendModeX(tileMode), - ExtendModeY = GetExtendModeY(tileMode), - }; - - return new BitmapBrush(target, image, bitmapOpts, opts); - } - - private BitmapBrush CreateIndirectBrush() - { - throw new NotImplementedException(); - } - } -} diff --git a/src/Windows/Perspex.Direct2D1/Media/TileBrushImpl.cs b/src/Windows/Perspex.Direct2D1/Media/TileBrushImpl.cs index fd9b938b2d..0f0d929b9e 100644 --- a/src/Windows/Perspex.Direct2D1/Media/TileBrushImpl.cs +++ b/src/Windows/Perspex.Direct2D1/Media/TileBrushImpl.cs @@ -6,94 +6,38 @@ using Perspex.Layout; using Perspex.Media; using SharpDX; using SharpDX.Direct2D1; +using Perspex.RenderHelpers; + namespace Perspex.Direct2D1.Media { - public class TileBrushImpl : BrushImpl + public sealed class TileBrushImpl : BrushImpl { - /// - /// 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. - protected static Vector CalculateTranslate( + public TileBrushImpl( TileBrush brush, - Rect sourceRect, - Rect destinationRect, - Vector scale) + SharpDX.Direct2D1.RenderTarget target, + Size targetSize) { - var x = 0.0; - var y = 0.0; - var size = sourceRect.Size * scale; + var helper = new TileBrushImplHelper(brush, targetSize); + if (!helper.IsValid) + return; - switch (brush.AlignmentX) + using (var intermediate = new BitmapRenderTarget(target, CompatibleRenderTargetOptions.None, helper.IntermediateSize.ToSharpDX())) { - case AlignmentX.Center: - x += (destinationRect.Width - size.Width) / 2; - break; - case AlignmentX.Right: - x += destinationRect.Width - size.Width; - break; + using (var ctx = new RenderTarget(intermediate).CreateDrawingContext()) + helper.DrawIntermediate(ctx); + + PlatformBrush = new BitmapBrush( + target, + intermediate.Bitmap, + GetBitmapBrushProperties(brush), + GetBrushProperties(brush, helper.DestinationRect)); } - - 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); } - protected static Size2F CalculateIntermediateSize( - TileMode tileMode, - Size targetSize, - Size destinationSize) - { - var result = tileMode == TileMode.None ? targetSize : destinationSize; - return result.ToSharpDX(); - } - - protected 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; - } protected static BrushProperties GetBrushProperties(TileBrush brush, Rect destinationRect) { - var tileMode = brush.TileMode; - return new BrushProperties { Opacity = (float)brush.Opacity, diff --git a/src/Windows/Perspex.Direct2D1/Media/VisualBrushImpl.cs b/src/Windows/Perspex.Direct2D1/Media/VisualBrushImpl.cs deleted file mode 100644 index b3eaa81b50..0000000000 --- a/src/Windows/Perspex.Direct2D1/Media/VisualBrushImpl.cs +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using Perspex.Layout; -using Perspex.Media; -using Perspex.Rendering; -using SharpDX; -using SharpDX.Direct2D1; - -namespace Perspex.Direct2D1.Media -{ - public class VisualBrushImpl : TileBrushImpl - { - public VisualBrushImpl( - VisualBrush brush, - SharpDX.Direct2D1.RenderTarget target, - Size targetSize) - { - var visual = brush.Visual; - - if (visual == null) - { - return; - } - - var layoutable = visual as ILayoutable; - - if (layoutable?.IsArrangeValid == false) - { - layoutable.Measure(Size.Infinity); - layoutable.Arrange(new Rect(layoutable.DesiredSize)); - } - - 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); - var brtOpts = CompatibleRenderTargetOptions.None; - - // TODO: There are times where we don't need to draw an intermediate bitmap. Identify - // them and directly use 'image' in those cases. - using (var intermediate = new BitmapRenderTarget(target, brtOpts, intermediateSize)) - { - Rect drawRect; - var transform = CalculateIntermediateTransform( - tileMode, - sourceRect, - destinationRect, - scale, - translate, - out drawRect); - var renderer = new RenderTarget(intermediate); - - using (var ctx = renderer.CreateDrawingContext()) - using (ctx.PushClip(drawRect)) - using (ctx.PushPostTransform(transform)) - { - intermediate.Clear(new Color4(0)); - ctx.Render(visual); - } - - this.PlatformBrush = new BitmapBrush( - target, - intermediate.Bitmap, - GetBitmapBrushProperties(brush), - GetBrushProperties(brush, destinationRect)); - } - } - } -} diff --git a/src/Windows/Perspex.Direct2D1/Perspex.Direct2D1.csproj b/src/Windows/Perspex.Direct2D1/Perspex.Direct2D1.csproj index 0f4ec68289..7d2091403c 100644 --- a/src/Windows/Perspex.Direct2D1/Perspex.Direct2D1.csproj +++ b/src/Windows/Perspex.Direct2D1/Perspex.Direct2D1.csproj @@ -79,9 +79,7 @@ - - @@ -113,6 +111,7 @@ Perspex.SceneGraph + From 78629373cd0f146e5236d081b1ede70bd8246e4e Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Tue, 3 Nov 2015 19:32:31 +0300 Subject: [PATCH 02/18] Fixed directory structure --- Perspex.sln | 4 ++-- {Shared => src/Shared}/RenderHelpers/RenderHelpers.projitems | 0 {Shared => src/Shared}/RenderHelpers/RenderHelpers.shproj | 0 {Shared => src/Shared}/RenderHelpers/TileBrushImplHelper.cs | 0 src/Windows/Perspex.Direct2D1/Perspex.Direct2D1.csproj | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) rename {Shared => src/Shared}/RenderHelpers/RenderHelpers.projitems (100%) rename {Shared => src/Shared}/RenderHelpers/RenderHelpers.shproj (100%) rename {Shared => src/Shared}/RenderHelpers/TileBrushImplHelper.cs (100%) diff --git a/Perspex.sln b/Perspex.sln index fdba885ee8..f5f1c367b4 100644 --- a/Perspex.sln +++ b/Perspex.sln @@ -104,7 +104,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BindingTest", "samples\Bind EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XamlTestApplicationPcl", "samples\XamlTestApplicationPcl\XamlTestApplicationPcl.csproj", "{EA113F1A-D8D7-4142-9948-353270E7EBAE}" EndProject -Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "RenderHelpers", "Shared\RenderHelpers\RenderHelpers.shproj", "{3C4C0CB4-0C0F-4450-A37B-148C84FF905F}" +Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "RenderHelpers", "src\Shared\RenderHelpers\RenderHelpers.shproj", "{3C4C0CB4-0C0F-4450-A37B-148C84FF905F}" EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution @@ -113,7 +113,7 @@ Global 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\PlatformSupport\PlatformSupport.projitems*{811a76cf-1cf6-440f-963b-bbe31bd72a82}*SharedItemsImports = 4 - Shared\RenderHelpers\RenderHelpers.projitems*{3e908f67-5543-4879-a1dc-08eace79b3cd}*SharedItemsImports = 4 + src\Shared\RenderHelpers\RenderHelpers.projitems*{3e908f67-5543-4879-a1dc-08eace79b3cd}*SharedItemsImports = 4 EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU diff --git a/Shared/RenderHelpers/RenderHelpers.projitems b/src/Shared/RenderHelpers/RenderHelpers.projitems similarity index 100% rename from Shared/RenderHelpers/RenderHelpers.projitems rename to src/Shared/RenderHelpers/RenderHelpers.projitems diff --git a/Shared/RenderHelpers/RenderHelpers.shproj b/src/Shared/RenderHelpers/RenderHelpers.shproj similarity index 100% rename from Shared/RenderHelpers/RenderHelpers.shproj rename to src/Shared/RenderHelpers/RenderHelpers.shproj diff --git a/Shared/RenderHelpers/TileBrushImplHelper.cs b/src/Shared/RenderHelpers/TileBrushImplHelper.cs similarity index 100% rename from Shared/RenderHelpers/TileBrushImplHelper.cs rename to src/Shared/RenderHelpers/TileBrushImplHelper.cs diff --git a/src/Windows/Perspex.Direct2D1/Perspex.Direct2D1.csproj b/src/Windows/Perspex.Direct2D1/Perspex.Direct2D1.csproj index 7d2091403c..f8f91ea467 100644 --- a/src/Windows/Perspex.Direct2D1/Perspex.Direct2D1.csproj +++ b/src/Windows/Perspex.Direct2D1/Perspex.Direct2D1.csproj @@ -111,7 +111,7 @@ Perspex.SceneGraph - + From 23b5706a21a7e5ff236f81db3ccf8cf71a5d3628 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Tue, 3 Nov 2015 19:39:00 +0300 Subject: [PATCH 03/18] 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 @@ + - \ No newline at end of file + From 4ea890e229f29aa67eaef340f8d16d993548c4fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20=C5=A0olt=C3=A9s?= Date: Thu, 5 Nov 2015 12:43:57 +0100 Subject: [PATCH 17/18] Update RelativeRectComparer.cs --- tests/Perspex.SceneGraph.UnitTests/RelativeRectComparer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Perspex.SceneGraph.UnitTests/RelativeRectComparer.cs b/tests/Perspex.SceneGraph.UnitTests/RelativeRectComparer.cs index cbde00e36c..667e2b4cbb 100644 --- a/tests/Perspex.SceneGraph.UnitTests/RelativeRectComparer.cs +++ b/tests/Perspex.SceneGraph.UnitTests/RelativeRectComparer.cs @@ -17,7 +17,7 @@ namespace Perspex.SceneGraph.UnitTests Math.Round(a.Rect.Height, 3) == Math.Round(b.Rect.Height, 3); } - public int GetHashCode(Rect obj) + public int GetHashCode(RelativeRect obj) { throw new NotImplementedException(); } From 8c0ea13520d07bfb2ec17851dfbe099cb243cf99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20=C5=A0olt=C3=A9s?= Date: Thu, 5 Nov 2015 14:20:54 +0100 Subject: [PATCH 18/18] Added QuadTo method --- src/Perspex.SceneGraph/Media/StreamGeometryContext.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/Perspex.SceneGraph/Media/StreamGeometryContext.cs b/src/Perspex.SceneGraph/Media/StreamGeometryContext.cs index 1a82149735..0d0c345389 100644 --- a/src/Perspex.SceneGraph/Media/StreamGeometryContext.cs +++ b/src/Perspex.SceneGraph/Media/StreamGeometryContext.cs @@ -64,6 +64,16 @@ namespace Perspex.Media _impl.BezierTo(point1, point2, point3); } + /// + /// Draws a quadratic Bezier curve to the specified point + /// + /// The control point used to specify the shape of the curve. + /// The destination point for the end of the curve. + public void QuadTo(Point control, Point endPoint) + { + _impl.QuadTo(control, endPoint); + } + /// /// Draws a line to the specified point. ///