Browse Source

Switched cairo to use xplat Visual/ImageBrush code

pull/301/head
Nikita Tsukanov 11 years ago
parent
commit
23b5706a21
  1. 3
      Perspex.sln
  2. 2
      src/Gtk/Perspex.Cairo/Media/ImageBrushImpl.cs
  3. 186
      src/Gtk/Perspex.Cairo/Media/TileBrushes.cs
  4. 2
      src/Gtk/Perspex.Cairo/Media/VisualBrushImpl.cs
  5. 1
      src/Gtk/Perspex.Cairo/Perspex.Cairo.csproj

3
Perspex.sln

@ -108,10 +108,11 @@ Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "RenderHelpers", "src\Shared
EndProject EndProject
Global Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution 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*{e4d9629c-f168-4224-3f51-a5e482ffbc42}*SharedItemsImports = 13
src\Shared\PlatformSupport\PlatformSupport.projitems*{db070a10-bf39-4752-8456-86e9d5928478}*SharedItemsImports = 4 src\Shared\PlatformSupport\PlatformSupport.projitems*{db070a10-bf39-4752-8456-86e9d5928478}*SharedItemsImports = 4
src\Shared\PlatformSupport\PlatformSupport.projitems*{54f237d5-a70a-4752-9656-0c70b1a7b047}*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\PlatformSupport\PlatformSupport.projitems*{811a76cf-1cf6-440f-963b-bbe31bd72a82}*SharedItemsImports = 4
src\Shared\RenderHelpers\RenderHelpers.projitems*{3e908f67-5543-4879-a1dc-08eace79b3cd}*SharedItemsImports = 4 src\Shared\RenderHelpers\RenderHelpers.projitems*{3e908f67-5543-4879-a1dc-08eace79b3cd}*SharedItemsImports = 4
EndGlobalSection EndGlobalSection

2
src/Gtk/Perspex.Cairo/Media/ImageBrushImpl.cs

@ -7,7 +7,7 @@ namespace Perspex.Cairo.Media
{ {
public ImageBrushImpl(Perspex.Media.ImageBrush brush, Size destinationSize) public ImageBrushImpl(Perspex.Media.ImageBrush brush, Size destinationSize)
{ {
this.PlatformBrush = TileBrushes.CreateImageBrush(brush, destinationSize); this.PlatformBrush = TileBrushes.CreateTileBrush(brush, destinationSize);
} }
} }
} }

186
src/Gtk/Perspex.Cairo/Media/TileBrushes.cs

@ -8,115 +8,22 @@ using Perspex.Layout;
using Perspex.Media; using Perspex.Media;
using Perspex.Platform; using Perspex.Platform;
using Perspex.Rendering; using Perspex.Rendering;
using Perspex.RenderHelpers;
namespace Perspex.Cairo.Media namespace Perspex.Cairo.Media
{ {
internal static class TileBrushes 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; 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()) using (var ctx = new RenderTarget(intermediate).CreateDrawingContext())
{ {
Rect drawRect; helper.DrawIntermediate(ctx);
var transform = CalculateIntermediateTransform(
tileMode,
sourceRect,
destinationRect,
scale,
translate,
out drawRect);
using (ctx.PushClip(drawRect))
using (ctx.PushPostTransform(transform))
{
ctx.Render(visual);
}
var result = new SurfacePattern(intermediate); var result = new SurfacePattern(intermediate);
@ -135,7 +42,7 @@ namespace Perspex.Cairo.Media
if (brush.TileMode != TileMode.None) if (brush.TileMode != TileMode.None)
{ {
var matrix = result.Matrix; var matrix = result.Matrix;
matrix.InitTranslate(-destinationRect.X, -destinationRect.Y); matrix.InitTranslate(-helper.DestinationRect.X, -helper.DestinationRect.Y);
result.Matrix = matrix; result.Matrix = matrix;
} }
@ -143,83 +50,6 @@ namespace Perspex.Cairo.Media
} }
} }
/// <summary>
/// Calculates a translate based on a <see cref="TileBrush"/>, 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>
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;
}
} }
} }

2
src/Gtk/Perspex.Cairo/Media/VisualBrushImpl.cs

@ -7,7 +7,7 @@ namespace Perspex.Cairo.Media
{ {
public VisualBrushImpl(Perspex.Media.VisualBrush brush, Size destinationSize) public VisualBrushImpl(Perspex.Media.VisualBrush brush, Size destinationSize)
{ {
this.PlatformBrush = TileBrushes.CreateVisualBrush(brush, destinationSize); this.PlatformBrush = TileBrushes.CreateTileBrush(brush, destinationSize);
} }
} }
} }

1
src/Gtk/Perspex.Cairo/Perspex.Cairo.csproj

@ -93,6 +93,7 @@
<None Include="app.config" /> <None Include="app.config" />
<None Include="packages.config" /> <None Include="packages.config" />
</ItemGroup> </ItemGroup>
<Import Project="..\..\Shared\RenderHelpers\RenderHelpers.projitems" Label="Shared" />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. Other similar extension points exist, see Microsoft.Common.targets.

Loading…
Cancel
Save