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 @@
+