Browse Source

Introduced DrawingContext class responsible for matrix transformation and push/pop order validation

pull/241/head
Nikita Tsukanov 11 years ago
parent
commit
3fc62506df
  1. 74
      src/Gtk/Perspex.Cairo/Media/DrawingContext.cs
  2. 2
      src/Gtk/Perspex.Cairo/Media/Imaging/RenderTargetBitmapImpl.cs
  3. 12
      src/Gtk/Perspex.Cairo/RenderTarget.cs
  4. 2
      src/Perspex.Application/Application.cs
  5. 2
      src/Perspex.Controls/Border.cs
  6. 2
      src/Perspex.Controls/Image.cs
  7. 4
      src/Perspex.Controls/Panel.cs
  8. 2
      src/Perspex.Controls/Presenters/TextPresenter.cs
  9. 2
      src/Perspex.Controls/Primitives/AccessText.cs
  10. 2
      src/Perspex.Controls/Shapes/Shape.cs
  11. 2
      src/Perspex.Controls/TextBlock.cs
  12. 4
      src/Perspex.HtmlRenderer/Adapters/GraphicsAdapter.cs
  13. 2
      src/Perspex.HtmlRenderer/HtmlContainer.cs
  14. 2
      src/Perspex.HtmlRenderer/HtmlControl.cs
  15. 4
      src/Perspex.SceneGraph/IVisual.cs
  16. 160
      src/Perspex.SceneGraph/Media/DrawingContext.cs
  17. 19
      src/Perspex.SceneGraph/Media/IDrawingContext.cs
  18. 2
      src/Perspex.SceneGraph/Media/Imaging/RenderTargetBitmap.cs
  19. 76
      src/Perspex.SceneGraph/Media/ValidatingDrawingContext.cs
  20. 2
      src/Perspex.SceneGraph/Perspex.SceneGraph.csproj
  21. 4
      src/Perspex.SceneGraph/Platform/IRenderTarget.cs
  22. 4
      src/Perspex.SceneGraph/Rendering/RendererBase.cs
  23. 4
      src/Perspex.SceneGraph/Visual.cs
  24. 59
      src/Windows/Perspex.Direct2D1/Media/DrawingContext.cs
  25. 2
      src/Windows/Perspex.Direct2D1/Media/Imaging/RenderTargetBitmapImpl.cs
  26. 19
      src/Windows/Perspex.Direct2D1/RenderTarget.cs

74
src/Gtk/Perspex.Cairo/Media/DrawingContext.cs

@ -2,6 +2,7 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Disposables;
using System.Runtime.InteropServices;
@ -16,7 +17,7 @@ namespace Perspex.Cairo.Media
/// <summary>
/// Draws using Direct2D1.
/// </summary>
public class DrawingContext : IDrawingContext, IDisposable
public class DrawingContext : IDrawingContextImpl, IDisposable
{
/// <summary>
/// The cairo context.
@ -30,7 +31,6 @@ namespace Perspex.Cairo.Media
public DrawingContext(Cairo.Surface surface)
{
_context = new Cairo.Context(surface);
CurrentTransform = Matrix.Identity;
}
/// <summary>
@ -40,15 +40,23 @@ namespace Perspex.Cairo.Media
public DrawingContext(Gdk.Drawable drawable)
{
_context = Gdk.CairoHelper.Create(drawable);
CurrentTransform = Matrix.Identity;
}
private Matrix _transform = Matrix.Identity;
/// <summary>
/// Gets the current transform of the drawing context.
/// </summary>
public Matrix CurrentTransform
public Matrix Transform
{
get; }
get { return _transform; }
set
{
_transform = value;
_context.Matrix = value.ToCairo();
}
}
/// <summary>
/// Ends a draw operation.
@ -131,29 +139,31 @@ namespace Perspex.Cairo.Media
{
var impl = geometry.PlatformImpl as StreamGeometryImpl;
using (var pop = PushTransform(impl.Transform))
var oldMatrix = Transform;
Transform *= impl.Transform;
if (brush != null)
{
_context.AppendPath(impl.Path);
if (brush != null)
using (var b = SetBrush(brush, geometry.Bounds.Size))
{
using (var b = SetBrush(brush, geometry.Bounds.Size))
{
if (pen != null)
_context.FillPreserve();
else
_context.Fill();
}
if (pen != null)
_context.FillPreserve();
else
_context.Fill();
}
}
if (pen != null)
{
using (var p = SetPen(pen, geometry.Bounds.Size))
{
_context.Stroke();
}
_context.AppendPath(impl.Path);
using (var p = SetPen(pen, geometry.Bounds.Size))
{
_context.Stroke();
}
}
Transform = oldMatrix;
}
/// <summary>
@ -208,31 +218,37 @@ namespace Perspex.Cairo.Media
/// </summary>
/// <param name="clip">The clip rectangle.</param>
/// <returns>A disposable used to undo the clip rectangle.</returns>
public IDisposable PushClip(Rect clip)
public void PushClip(Rect clip)
{
_context.Save();
_context.Rectangle(clip.ToCairo());
_context.Clip();
}
return Disposable.Create(() => _context.Restore());
public void PopClip()
{
_context.Restore();
}
readonly Stack<double> _opacityStack = new Stack<double>();
/// <summary>
/// Pushes an opacity value.
/// </summary>
/// <param name="opacity">The opacity.</param>
/// <returns>A disposable used to undo the opacity.</returns>
public IDisposable PushOpacity(double opacity)
public void PushOpacity(double opacity)
{
var tmp = opacityOverride;
_opacityStack.Push(opacityOverride);
if (opacity < 1.0f)
opacityOverride = opacity;
opacityOverride *= opacity;
return Disposable.Create(() =>
{
opacityOverride = tmp;
});
}
public void PopOpacity()
{
opacityOverride = _opacityStack.Pop();
}
/// <summary>

2
src/Gtk/Perspex.Cairo/Media/Imaging/RenderTargetBitmapImpl.cs

@ -39,7 +39,7 @@ namespace Perspex.Cairo.Media.Imaging
Surface.WriteToPng(fileName);
}
public IDrawingContext CreateDrawingContext()
public Perspex.Media.DrawingContext CreateDrawingContext()
{
return _renderTarget.CreateDrawingContext();
}

12
src/Gtk/Perspex.Cairo/RenderTarget.cs

@ -7,6 +7,7 @@ using Perspex.Cairo.Media;
using Perspex.Media;
using Perspex.Platform;
using Perspex.Rendering;
using DrawingContext = Perspex.Media.DrawingContext;
namespace Perspex.Cairo
{
@ -50,12 +51,13 @@ namespace Perspex.Cairo
/// <summary>
/// Creates a cairo surface that targets a platform-specific resource.
/// </summary>
/// <returns>A surface wrapped in an <see cref="IDrawingContext"/>.</returns>
public IDrawingContext CreateDrawingContext()
/// <returns>A surface wrapped in an <see cref="Perspex.Media.DrawingContext"/>.</returns>
public DrawingContext CreateDrawingContext()
{
if(_surface != null)
return new DrawingContext(_surface);
return new DrawingContext(_window.GdkWindow);
var ctx = _surface != null
? new Media.DrawingContext(_surface)
: new Media.DrawingContext(_window.GdkWindow);
return new DrawingContext(ctx);
}
public void Dispose() => _surface?.Dispose();

2
src/Perspex.Application/Application.cs

@ -177,7 +177,7 @@ namespace Perspex
/// <param name="platformID">The value of Environment.OSVersion.Platform.</param>
protected void InitializeSubsystems(int platformID)
{
if (platformID == 4 || platformID == 6)
if (true)//platformID == 4 || platformID == 6)
{
InitializeSubsystem("Perspex.Cairo");
InitializeSubsystem("Perspex.Gtk");

2
src/Perspex.Controls/Border.cs

@ -83,7 +83,7 @@ namespace Perspex.Controls
/// Renders the control.
/// </summary>
/// <param name="context">The drawing context.</param>
public override void Render(IDrawingContext context)
public override void Render(DrawingContext context)
{
var background = Background;
var borderBrush = BorderBrush;

2
src/Perspex.Controls/Image.cs

@ -46,7 +46,7 @@ namespace Perspex.Controls
/// Renders the control.
/// </summary>
/// <param name="context">The drawing context.</param>
public override void Render(IDrawingContext context)
public override void Render(DrawingContext context)
{
Bitmap source = Source;

4
src/Perspex.Controls/Panel.cs

@ -172,10 +172,10 @@ namespace Perspex.Controls
}
/// <summary>
/// Renders the visual to a <see cref="IDrawingContext"/>.
/// Renders the visual to a <see cref="DrawingContext"/>.
/// </summary>
/// <param name="context">The drawing context.</param>
public override void Render(IDrawingContext context)
public override void Render(DrawingContext context)
{
Brush background = Background;
if (background != null)

2
src/Perspex.Controls/Presenters/TextPresenter.cs

@ -69,7 +69,7 @@ namespace Perspex.Controls.Presenters
return hit.TextPosition + (hit.IsTrailing ? 1 : 0);
}
public override void Render(IDrawingContext context)
public override void Render(DrawingContext context)
{
var selectionStart = SelectionStart;
var selectionEnd = SelectionEnd;

2
src/Perspex.Controls/Primitives/AccessText.cs

@ -62,7 +62,7 @@ namespace Perspex.Controls.Primitives
/// Renders the <see cref="AccessText"/> to a drawing context.
/// </summary>
/// <param name="context">The drawing context.</param>
public override void Render(IDrawingContext context)
public override void Render(DrawingContext context)
{
base.Render(context);

2
src/Perspex.Controls/Shapes/Shape.cs

@ -90,7 +90,7 @@ namespace Perspex.Controls.Shapes
set { SetValue(StrokeThicknessProperty, value); }
}
public override void Render(IDrawingContext context)
public override void Render(DrawingContext context)
{
var geometry = RenderedGeometry;

2
src/Perspex.Controls/TextBlock.cs

@ -214,7 +214,7 @@ namespace Perspex.Controls
/// Renders the <see cref="TextBlock"/> to a drawing context.
/// </summary>
/// <param name="context">The drawing context.</param>
public override void Render(IDrawingContext context)
public override void Render(DrawingContext context)
{
Brush background = Background;

4
src/Perspex.HtmlRenderer/Adapters/GraphicsAdapter.cs

@ -32,7 +32,7 @@ namespace TheArtOfDev.HtmlRenderer.Perspex.Adapters
/// <summary>
/// The wrapped Perspex graphics object
/// </summary>
private readonly IDrawingContext _g;
private readonly DrawingContext _g;
/// <summary>
/// if to release the graphics object on dispose
@ -51,7 +51,7 @@ namespace TheArtOfDev.HtmlRenderer.Perspex.Adapters
/// <param name="g">the Perspex graphics object to use</param>
/// <param name="initialClip">the initial clip of the graphics</param>
/// <param name="releaseGraphics">optional: if to release the graphics object on dispose (default - false)</param>
public GraphicsAdapter(IDrawingContext g, RRect initialClip, bool releaseGraphics = false)
public GraphicsAdapter(DrawingContext g, RRect initialClip, bool releaseGraphics = false)
: base(PerspexAdapter.Instance, initialClip)
{
ArgChecker.AssertArgNotNull(g, "g");

2
src/Perspex.HtmlRenderer/HtmlContainer.cs

@ -360,7 +360,7 @@ namespace TheArtOfDev.HtmlRenderer.Perspex
/// </summary>
/// <param name="g">the device to use to render</param>
/// <param name="clip">the clip rectangle of the html container</param>
public void PerformPaint(IDrawingContext g, Rect clip)
public void PerformPaint(DrawingContext g, Rect clip)
{
ArgChecker.AssertArgNotNull(g, "g");

2
src/Perspex.HtmlRenderer/HtmlControl.cs

@ -327,7 +327,7 @@ namespace Perspex.Controls.Html
private Size RenderSize => new Size(Bounds.Width, Bounds.Height);
public override void Render(IDrawingContext context)
public override void Render(DrawingContext context)
{
context.FillRectangle(Background, new Rect(RenderSize));

4
src/Perspex.SceneGraph/IVisual.cs

@ -76,10 +76,10 @@ namespace Perspex
int ZIndex { get; set; }
/// <summary>
/// Renders the scene graph node to a <see cref="IDrawingContext"/>.
/// Renders the scene graph node to a <see cref="DrawingContext"/>.
/// </summary>
/// <param name="context">The context.</param>
void Render(IDrawingContext context);
void Render(DrawingContext context);
/// <summary>
/// Returns a transform that transforms the visual's coordinates into the coordinates

160
src/Perspex.SceneGraph/Media/DrawingContext.cs

@ -0,0 +1,160 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Perspex.Media.Imaging;
namespace Perspex.Media
{
public sealed class DrawingContext : IDisposable
{
private readonly IDrawingContextImpl _impl;
private int _currentLevel;
public DrawingContext(IDrawingContextImpl impl)
{
_impl = impl;
}
/// <summary>
/// Gets the current transform of the drawing context.
/// </summary>
public Matrix CurrentTransform => _impl.Transform;
/// <summary>
/// Draws a bitmap image.
/// </summary>
/// <param name="source">The bitmap image.</param>
/// <param name="opacity">The opacity to draw with.</param>
/// <param name="sourceRect">The rect in the image to draw.</param>
/// <param name="destRect">The rect in the output to draw to.</param>
public void DrawImage(IBitmap source, double opacity, Rect sourceRect, Rect destRect)
=> _impl.DrawImage(source, opacity, sourceRect, destRect);
/// <summary>
/// Draws a line.
/// </summary>
/// <param name="pen">The stroke pen.</param>
/// <param name="p1">The first point of the line.</param>
/// <param name="p2">The second point of the line.</param>
public void DrawLine(Pen pen, Point p1, Point p2) => _impl.DrawLine(pen, p1, p2);
/// <summary>
/// Draws a geometry.
/// </summary>
/// <param name="brush">The fill brush.</param>
/// <param name="pen">The stroke pen.</param>
/// <param name="geometry">The geometry.</param>
public void DrawGeometry(Brush brush, Pen pen, Geometry geometry) => _impl.DrawGeometry(brush, pen, geometry);
/// <summary>
/// Draws the outline of a rectangle.
/// </summary>
/// <param name="pen">The pen.</param>
/// <param name="rect">The rectangle bounds.</param>
/// <param name="cornerRadius">The corner radius.</param>
public void DrawRectangle(Pen pen, Rect rect, float cornerRadius = 0.0f)
=> _impl.DrawRectangle(pen, rect, cornerRadius);
/// <summary>
/// Draws text.
/// </summary>
/// <param name="foreground">The foreground brush.</param>
/// <param name="origin">The upper-left corner of the text.</param>
/// <param name="text">The text.</param>
public void DrawText(Brush foreground, Point origin, FormattedText text)
=> _impl.DrawText(foreground, origin, text);
/// <summary>
/// Draws a filled rectangle.
/// </summary>
/// <param name="brush">The brush.</param>
/// <param name="rect">The rectangle bounds.</param>
/// <param name="cornerRadius">The corner radius.</param>
public void FillRectangle(Brush brush, Rect rect, float cornerRadius = 0.0f)
=> _impl.FillRectangle(brush, rect, cornerRadius);
public struct PushedState : IDisposable
{
private readonly int _level;
private readonly DrawingContext _context;
private readonly Matrix _matrix;
private readonly PushedStateType _type;
public enum PushedStateType
{
None,
Matrix,
Opacity,
Clip
}
public PushedState(DrawingContext context, PushedStateType type, Matrix matrix = default(Matrix))
{
_level = context._currentLevel += 1;
_context = context;
_type = type;
_matrix = matrix;
}
public void Dispose()
{
if(_type == PushedStateType.None)
return;
if (_context._currentLevel != _level)
throw new InvalidOperationException("Wrong Push/Pop state order");
_context._currentLevel--;
if (_type == PushedStateType.Matrix)
_context._impl.Transform = _matrix;
else if(_type == PushedStateType.Clip)
_context._impl.PopClip();
else if(_type == PushedStateType.Opacity)
_context._impl.PopOpacity();
}
}
/// <summary>
/// Pushes a clip rectange.
/// </summary>
/// <param name="clip">The clip rectangle.</param>
/// <returns>A disposable used to undo the clip rectangle.</returns>
public PushedState PushClip(Rect clip)
{
_impl.PushClip(clip);
return new PushedState(this, PushedState.PushedStateType.Clip);
}
/// <summary>
/// Pushes an opacity value.
/// </summary>
/// <param name="opacity">The opacity.</param>
/// <returns>A disposable used to undo the opacity.</returns>
public PushedState PushOpacity(double opacity)
//TODO: Elimintate platform-specific push opacity call
{
_impl.PushOpacity(opacity);
return new PushedState(this, PushedState.PushedStateType.Opacity);
}
/// <summary>
/// Pushes a matrix transformation.
/// </summary>
/// <param name="matrix">The matrix</param>
/// <returns>A disposable used to undo the transformation.</returns>
public PushedState PushTransform(Matrix matrix)
{
var oldMatrix = CurrentTransform;
matrix = oldMatrix*matrix;
_impl.Transform = matrix;
return new PushedState(this, PushedState.PushedStateType.Matrix, oldMatrix);
}
public void Dispose() => _impl.Dispose();
}
}

19
src/Perspex.SceneGraph/Media/IDrawingContext.cs

@ -9,12 +9,12 @@ namespace Perspex.Media
/// <summary>
/// Defines the interface through which drawing occurs.
/// </summary>
public interface IDrawingContext : IDisposable
public interface IDrawingContextImpl : IDisposable
{
/// <summary>
/// Gets the current transform of the drawing context.
/// Gets or sets the current transform of the drawing context.
/// </summary>
Matrix CurrentTransform { get; }
Matrix Transform { get; set; }
/// <summary>
/// Draws a bitmap image.
@ -70,20 +70,17 @@ namespace Perspex.Media
/// </summary>
/// <param name="clip">The clip rectangle.</param>
/// <returns>A disposable used to undo the clip rectangle.</returns>
IDisposable PushClip(Rect clip);
void PushClip(Rect clip);
void PopClip();
/// <summary>
/// Pushes an opacity value.
/// </summary>
/// <param name="opacity">The opacity.</param>
/// <returns>A disposable used to undo the opacity.</returns>
IDisposable PushOpacity(double opacity);
void PushOpacity(double opacity);
/// <summary>
/// Pushes a matrix transformation.
/// </summary>
/// <param name="matrix">The matrix</param>
/// <returns>A disposable used to undo the transformation.</returns>
IDisposable PushTransform(Matrix matrix);
void PopOpacity();
}
}

2
src/Perspex.SceneGraph/Media/Imaging/RenderTargetBitmap.cs

@ -47,7 +47,7 @@ namespace Perspex.Media.Imaging
return factory.CreateRenderTargetBitmap(width, height);
}
public IDrawingContext CreateDrawingContext() => PlatformImpl.CreateDrawingContext();
public DrawingContext CreateDrawingContext() => PlatformImpl.CreateDrawingContext();
void IRenderTarget.Resize(int width, int height)
{

76
src/Perspex.SceneGraph/Media/ValidatingDrawingContext.cs

@ -1,76 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Reactive.Disposables;
using Perspex.Media.Imaging;
namespace Perspex.Media
{
public class ValidatingDrawingContext : IDrawingContext
{
private readonly IDrawingContext _base;
public ValidatingDrawingContext(IDrawingContext @base)
{
_base = @base;
}
public void Dispose()
{
_base.Dispose();
}
public Matrix CurrentTransform => _base.CurrentTransform;
public void DrawImage(IBitmap source, double opacity, Rect sourceRect, Rect destRect)
{
_base.DrawImage(source, opacity, sourceRect, destRect);
}
public void DrawLine(Pen pen, Point p1, Point p2)
{
_base.DrawLine(pen, p1, p2);
}
public void DrawGeometry(Brush brush, Pen pen, Geometry geometry)
{
_base.DrawGeometry(brush, pen, geometry);
}
public void DrawRectangle(Pen pen, Rect rect, float cornerRadius = 0)
{
_base.DrawRectangle(pen, rect, cornerRadius);
}
public void DrawText(Brush foreground, Point origin, FormattedText text)
{
_base.DrawText(foreground, origin, text);
}
public void FillRectangle(Brush brush, Rect rect, float cornerRadius = 0)
{
_base.FillRectangle(brush, rect, cornerRadius);
}
Stack<IDisposable> _stateStack = new Stack<IDisposable>();
IDisposable Transform(IDisposable disposable)
{
_stateStack.Push(disposable);
return Disposable.Create(() =>
{
var current = _stateStack.Peek();
if (current != disposable)
throw new InvalidOperationException("Invalid push/pop order");
current.Dispose();
_stateStack.Pop();
});
}
public IDisposable PushClip(Rect clip) => Transform(_base.PushClip(clip));
public IDisposable PushOpacity(double opacity) => Transform(_base.PushOpacity(opacity));
public IDisposable PushTransform(Matrix matrix) => Transform(_base.PushTransform(matrix));
}
}

2
src/Perspex.SceneGraph/Perspex.SceneGraph.csproj

@ -64,6 +64,7 @@
<Compile Include="Media\Color.cs" />
<Compile Include="Media\Colors.cs" />
<Compile Include="Media\DashStyle.cs" />
<Compile Include="Media\DrawingContext.cs" />
<Compile Include="Media\GradientBrush.cs" />
<Compile Include="Media\GradientSpreadMethod.cs" />
<Compile Include="Media\GradientStop.cs" />
@ -99,7 +100,6 @@
<Compile Include="Media\Transform.cs" />
<Compile Include="Media\TileBrush.cs" />
<Compile Include="Media\ImageBush.cs" />
<Compile Include="Media\ValidatingDrawingContext.cs" />
<Compile Include="Media\VisualBrush.cs" />
<Compile Include="RelativePoint.cs" />
<Compile Include="Platform\IFormattedTextImpl.cs" />

4
src/Perspex.SceneGraph/Platform/IRenderTarget.cs

@ -15,9 +15,9 @@ namespace Perspex.Platform
public interface IRenderTarget : IDisposable
{
/// <summary>
/// Creates an <see cref="IDrawingContext"/> for a rendering session.
/// Creates an <see cref="DrawingContext"/> for a rendering session.
/// </summary>
IDrawingContext CreateDrawingContext();
DrawingContext CreateDrawingContext();
/// <summary>
/// Resizes the rendered viewport.

4
src/Perspex.SceneGraph/Rendering/RendererBase.cs

@ -35,7 +35,7 @@ namespace Perspex.Rendering
/// <param name="visual">The visual to render.</param>
///
/// <param name="context">The drawing context.</param>
public static void Render(this IDrawingContext context, IVisual visual)
public static void Render(this DrawingContext context, IVisual visual)
{
var opacity = visual.Opacity;
if (visual.IsVisible && opacity > 0)
@ -54,7 +54,7 @@ namespace Perspex.Rendering
using (context.PushTransform(m))
using (context.PushOpacity(opacity))
using (visual.ClipToBounds ? context.PushClip(new Rect(visual.Bounds.Size)) : null)
using (visual.ClipToBounds ? context.PushClip(new Rect(visual.Bounds.Size)) : default(DrawingContext.PushedState))
{
visual.Render(context);
foreach (var child in visual.VisualChildren.OrderBy(x => x.ZIndex))

4
src/Perspex.SceneGraph/Visual.cs

@ -229,10 +229,10 @@ namespace Perspex
}
/// <summary>
/// Renders the visual to a <see cref="IDrawingContext"/>.
/// Renders the visual to a <see cref="DrawingContext"/>.
/// </summary>
/// <param name="context">The drawing context.</param>
public virtual void Render(IDrawingContext context)
public virtual void Render(DrawingContext context)
{
Contract.Requires<ArgumentNullException>(context != null);
}

59
src/Windows/Perspex.Direct2D1/Media/DrawingContext.cs

@ -2,6 +2,8 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reactive.Disposables;
using Perspex.Media;
using SharpDX;
@ -13,7 +15,7 @@ namespace Perspex.Direct2D1.Media
/// <summary>
/// Draws using Direct2D1.
/// </summary>
public class DrawingContext : IDrawingContext, IDisposable
public class DrawingContext : IDrawingContextImpl, IDisposable
{
/// <summary>
/// The Direct2D1 render target.
@ -42,10 +44,10 @@ namespace Perspex.Direct2D1.Media
/// <summary>
/// Gets the current transform of the drawing context.
/// </summary>
public Matrix CurrentTransform
public Matrix Transform
{
get { return _renderTarget.Transform.ToPerspex(); }
private set { _renderTarget.Transform = value.ToDirect2D(); }
set { _renderTarget.Transform = value.ToDirect2D(); }
}
/// <summary>
@ -53,6 +55,8 @@ namespace Perspex.Direct2D1.Media
/// </summary>
public void Dispose()
{
foreach (var layer in _layerPool)
layer.Dispose();
_renderTarget.EndDraw();
}
@ -233,22 +237,24 @@ namespace Perspex.Direct2D1.Media
/// </summary>
/// <param name="clip">The clip rectangle.</param>
/// <returns>A disposable used to undo the clip rectangle.</returns>
public IDisposable PushClip(Rect clip)
public void PushClip(Rect clip)
{
_renderTarget.PushAxisAlignedClip(clip.ToSharpDX(), AntialiasMode.PerPrimitive);
}
return Disposable.Create(() =>
{
_renderTarget.PopAxisAlignedClip();
});
public void PopClip()
{
_renderTarget.PopAxisAlignedClip();
}
Stack<Layer> _layers = new Stack<Layer>();
private readonly Stack<Layer> _layerPool = new Stack<Layer>();
/// <summary>
/// Pushes an opacity value.
/// </summary>
/// <param name="opacity">The opacity.</param>
/// <returns>A disposable used to undo the opacity.</returns>
public IDisposable PushOpacity(double opacity)
public void PushOpacity(double opacity)
{
if (opacity < 1)
{
@ -256,41 +262,26 @@ namespace Perspex.Direct2D1.Media
{
ContentBounds = RectangleF.Infinite,
MaskTransform = Matrix3x2.Identity,
Opacity = (float)opacity,
Opacity = (float) opacity,
};
var layer = new Layer(_renderTarget);
var layer = _layerPool.Count != 0 ? _layerPool.Pop() : new Layer(_renderTarget);
_renderTarget.PushLayer(ref parameters, layer);
return Disposable.Create(() =>
{
_renderTarget.PopLayer();
layer.Dispose();
});
_layers.Push(layer);
}
else
{
return Disposable.Empty;
}
_layers.Push(null);
}
/// <summary>
/// Pushes a matrix transformation.
/// </summary>
/// <param name="matrix">The matrix</param>
/// <returns>A disposable used to undo the transformation.</returns>
public IDisposable PushTransform(Matrix matrix)
public void PopOpacity()
{
Matrix3x2 m3x2 = matrix.ToDirect2D();
Matrix3x2 transform = _renderTarget.Transform * m3x2;
_renderTarget.Transform = transform;
return Disposable.Create(() =>
var layer = _layers.Pop();
if (layer != null)
{
m3x2.Invert();
_renderTarget.Transform = transform * m3x2;
});
_renderTarget.PopLayer();
_layerPool.Push(layer);
}
}
/// <summary>

2
src/Windows/Perspex.Direct2D1/Media/Imaging/RenderTargetBitmapImpl.cs

@ -38,7 +38,7 @@ namespace Perspex.Direct2D1.Media
// TODO:
}
public IDrawingContext CreateDrawingContext() => new RenderTarget(_target).CreateDrawingContext();
public Perspex.Media.DrawingContext CreateDrawingContext() => new RenderTarget(_target).CreateDrawingContext();
void IRenderTarget.Resize(int width, int height)
{

19
src/Windows/Perspex.Direct2D1/RenderTarget.cs

@ -8,6 +8,7 @@ using Perspex.Platform;
using Perspex.Rendering;
using SharpDX;
using SharpDX.Direct2D1;
using DrawingContext = Perspex.Media.DrawingContext;
using DwFactory = SharpDX.DirectWrite.Factory;
namespace Perspex.Direct2D1
@ -91,24 +92,12 @@ namespace Perspex.Direct2D1
window.Resize(new Size2(width, height));
}
IDrawingContext Wrap(IDrawingContext ctx)
{
#if DEBUG
return new ValidatingDrawingContext(ctx);
#endif
#pragma warning disable 162
return ctx;
#pragma warning restore 162
}
/// <summary>
/// Creates a drawing context for a rendering session.
/// </summary>
/// <returns>An <see cref="IDrawingContext"/>.</returns>
public IDrawingContext CreateDrawingContext()
{
return Wrap(new DrawingContext(_renderTarget, DirectWriteFactory));
}
/// <returns>An <see cref="Perspex.Media.DrawingContext"/>.</returns>
public DrawingContext CreateDrawingContext()
=> new DrawingContext(new Media.DrawingContext(_renderTarget, DirectWriteFactory));
public void Dispose()
{

Loading…
Cancel
Save