diff --git a/src/Gtk/Perspex.Cairo/Media/DrawingContext.cs b/src/Gtk/Perspex.Cairo/Media/DrawingContext.cs
index f8c74f3f8f..3efb60e5c5 100644
--- a/src/Gtk/Perspex.Cairo/Media/DrawingContext.cs
+++ b/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
///
/// Draws using Direct2D1.
///
- public class DrawingContext : IDrawingContext, IDisposable
+ public class DrawingContext : IDrawingContextImpl, IDisposable
{
///
/// The cairo context.
@@ -30,7 +31,6 @@ namespace Perspex.Cairo.Media
public DrawingContext(Cairo.Surface surface)
{
_context = new Cairo.Context(surface);
- CurrentTransform = Matrix.Identity;
}
///
@@ -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;
///
/// Gets the current transform of the drawing context.
///
- public Matrix CurrentTransform
+ public Matrix Transform
{
- get; }
+ get { return _transform; }
+ set
+ {
+ _transform = value;
+ _context.Matrix = value.ToCairo();
+
+ }
+ }
///
/// 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;
}
///
@@ -208,31 +218,37 @@ namespace Perspex.Cairo.Media
///
/// The clip rectangle.
/// A disposable used to undo the clip rectangle.
- 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 _opacityStack = new Stack();
+
///
/// Pushes an opacity value.
///
/// The opacity.
/// A disposable used to undo the opacity.
- 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();
}
///
diff --git a/src/Gtk/Perspex.Cairo/Media/Imaging/RenderTargetBitmapImpl.cs b/src/Gtk/Perspex.Cairo/Media/Imaging/RenderTargetBitmapImpl.cs
index 0b9183d928..4d8f05848a 100644
--- a/src/Gtk/Perspex.Cairo/Media/Imaging/RenderTargetBitmapImpl.cs
+++ b/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();
}
diff --git a/src/Gtk/Perspex.Cairo/RenderTarget.cs b/src/Gtk/Perspex.Cairo/RenderTarget.cs
index 333c558e8a..2daab33fbe 100644
--- a/src/Gtk/Perspex.Cairo/RenderTarget.cs
+++ b/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
///
/// Creates a cairo surface that targets a platform-specific resource.
///
- /// A surface wrapped in an .
- public IDrawingContext CreateDrawingContext()
+ /// A surface wrapped in an .
+ 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();
diff --git a/src/Perspex.Application/Application.cs b/src/Perspex.Application/Application.cs
index 88f3a23ffe..1e19736154 100644
--- a/src/Perspex.Application/Application.cs
+++ b/src/Perspex.Application/Application.cs
@@ -177,7 +177,7 @@ namespace Perspex
/// The value of Environment.OSVersion.Platform.
protected void InitializeSubsystems(int platformID)
{
- if (platformID == 4 || platformID == 6)
+ if (true)//platformID == 4 || platformID == 6)
{
InitializeSubsystem("Perspex.Cairo");
InitializeSubsystem("Perspex.Gtk");
diff --git a/src/Perspex.Controls/Border.cs b/src/Perspex.Controls/Border.cs
index 8a70987cb0..bcb1235f25 100644
--- a/src/Perspex.Controls/Border.cs
+++ b/src/Perspex.Controls/Border.cs
@@ -83,7 +83,7 @@ namespace Perspex.Controls
/// Renders the control.
///
/// The drawing context.
- public override void Render(IDrawingContext context)
+ public override void Render(DrawingContext context)
{
var background = Background;
var borderBrush = BorderBrush;
diff --git a/src/Perspex.Controls/Image.cs b/src/Perspex.Controls/Image.cs
index 79b79c6141..0b316689bd 100644
--- a/src/Perspex.Controls/Image.cs
+++ b/src/Perspex.Controls/Image.cs
@@ -46,7 +46,7 @@ namespace Perspex.Controls
/// Renders the control.
///
/// The drawing context.
- public override void Render(IDrawingContext context)
+ public override void Render(DrawingContext context)
{
Bitmap source = Source;
diff --git a/src/Perspex.Controls/Panel.cs b/src/Perspex.Controls/Panel.cs
index 08e6621adb..bd45bf1e3a 100644
--- a/src/Perspex.Controls/Panel.cs
+++ b/src/Perspex.Controls/Panel.cs
@@ -172,10 +172,10 @@ namespace Perspex.Controls
}
///
- /// Renders the visual to a .
+ /// Renders the visual to a .
///
/// The drawing context.
- public override void Render(IDrawingContext context)
+ public override void Render(DrawingContext context)
{
Brush background = Background;
if (background != null)
diff --git a/src/Perspex.Controls/Presenters/TextPresenter.cs b/src/Perspex.Controls/Presenters/TextPresenter.cs
index 1e6068fd7d..2948cd541a 100644
--- a/src/Perspex.Controls/Presenters/TextPresenter.cs
+++ b/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;
diff --git a/src/Perspex.Controls/Primitives/AccessText.cs b/src/Perspex.Controls/Primitives/AccessText.cs
index 33da32037f..0168974248 100644
--- a/src/Perspex.Controls/Primitives/AccessText.cs
+++ b/src/Perspex.Controls/Primitives/AccessText.cs
@@ -62,7 +62,7 @@ namespace Perspex.Controls.Primitives
/// Renders the to a drawing context.
///
/// The drawing context.
- public override void Render(IDrawingContext context)
+ public override void Render(DrawingContext context)
{
base.Render(context);
diff --git a/src/Perspex.Controls/Shapes/Shape.cs b/src/Perspex.Controls/Shapes/Shape.cs
index 5f5b989602..58dc24a738 100644
--- a/src/Perspex.Controls/Shapes/Shape.cs
+++ b/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;
diff --git a/src/Perspex.Controls/TextBlock.cs b/src/Perspex.Controls/TextBlock.cs
index e621369679..b6bec05240 100644
--- a/src/Perspex.Controls/TextBlock.cs
+++ b/src/Perspex.Controls/TextBlock.cs
@@ -214,7 +214,7 @@ namespace Perspex.Controls
/// Renders the to a drawing context.
///
/// The drawing context.
- public override void Render(IDrawingContext context)
+ public override void Render(DrawingContext context)
{
Brush background = Background;
diff --git a/src/Perspex.HtmlRenderer/Adapters/GraphicsAdapter.cs b/src/Perspex.HtmlRenderer/Adapters/GraphicsAdapter.cs
index 8b52a1b573..6fd918a69b 100644
--- a/src/Perspex.HtmlRenderer/Adapters/GraphicsAdapter.cs
+++ b/src/Perspex.HtmlRenderer/Adapters/GraphicsAdapter.cs
@@ -32,7 +32,7 @@ namespace TheArtOfDev.HtmlRenderer.Perspex.Adapters
///
/// The wrapped Perspex graphics object
///
- private readonly IDrawingContext _g;
+ private readonly DrawingContext _g;
///
/// if to release the graphics object on dispose
@@ -51,7 +51,7 @@ namespace TheArtOfDev.HtmlRenderer.Perspex.Adapters
/// the Perspex graphics object to use
/// the initial clip of the graphics
/// optional: if to release the graphics object on dispose (default - false)
- 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");
diff --git a/src/Perspex.HtmlRenderer/HtmlContainer.cs b/src/Perspex.HtmlRenderer/HtmlContainer.cs
index 9ada42d5ed..e30036b343 100644
--- a/src/Perspex.HtmlRenderer/HtmlContainer.cs
+++ b/src/Perspex.HtmlRenderer/HtmlContainer.cs
@@ -360,7 +360,7 @@ namespace TheArtOfDev.HtmlRenderer.Perspex
///
/// the device to use to render
/// the clip rectangle of the html container
- public void PerformPaint(IDrawingContext g, Rect clip)
+ public void PerformPaint(DrawingContext g, Rect clip)
{
ArgChecker.AssertArgNotNull(g, "g");
diff --git a/src/Perspex.HtmlRenderer/HtmlControl.cs b/src/Perspex.HtmlRenderer/HtmlControl.cs
index b720b17bc0..ddd7541923 100644
--- a/src/Perspex.HtmlRenderer/HtmlControl.cs
+++ b/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));
diff --git a/src/Perspex.SceneGraph/IVisual.cs b/src/Perspex.SceneGraph/IVisual.cs
index 7126558483..0491d63fad 100644
--- a/src/Perspex.SceneGraph/IVisual.cs
+++ b/src/Perspex.SceneGraph/IVisual.cs
@@ -76,10 +76,10 @@ namespace Perspex
int ZIndex { get; set; }
///
- /// Renders the scene graph node to a .
+ /// Renders the scene graph node to a .
///
/// The context.
- void Render(IDrawingContext context);
+ void Render(DrawingContext context);
///
/// Returns a transform that transforms the visual's coordinates into the coordinates
diff --git a/src/Perspex.SceneGraph/Media/DrawingContext.cs b/src/Perspex.SceneGraph/Media/DrawingContext.cs
new file mode 100644
index 0000000000..5f95ba021b
--- /dev/null
+++ b/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;
+ }
+
+ ///
+ /// Gets the current transform of the drawing context.
+ ///
+ public Matrix CurrentTransform => _impl.Transform;
+
+ ///
+ /// Draws a bitmap image.
+ ///
+ /// The bitmap image.
+ /// The opacity to draw with.
+ /// The rect in the image to draw.
+ /// The rect in the output to draw to.
+ public void DrawImage(IBitmap source, double opacity, Rect sourceRect, Rect destRect)
+ => _impl.DrawImage(source, opacity, sourceRect, destRect);
+
+ ///
+ /// Draws a line.
+ ///
+ /// The stroke pen.
+ /// The first point of the line.
+ /// The second point of the line.
+ public void DrawLine(Pen pen, Point p1, Point p2) => _impl.DrawLine(pen, p1, p2);
+
+ ///
+ /// Draws a geometry.
+ ///
+ /// The fill brush.
+ /// The stroke pen.
+ /// The geometry.
+ public void DrawGeometry(Brush brush, Pen pen, Geometry geometry) => _impl.DrawGeometry(brush, pen, geometry);
+
+ ///
+ /// Draws the outline of a rectangle.
+ ///
+ /// The pen.
+ /// The rectangle bounds.
+ /// The corner radius.
+ public void DrawRectangle(Pen pen, Rect rect, float cornerRadius = 0.0f)
+ => _impl.DrawRectangle(pen, rect, cornerRadius);
+
+ ///
+ /// Draws text.
+ ///
+ /// The foreground brush.
+ /// The upper-left corner of the text.
+ /// The text.
+ public void DrawText(Brush foreground, Point origin, FormattedText text)
+ => _impl.DrawText(foreground, origin, text);
+
+ ///
+ /// Draws a filled rectangle.
+ ///
+ /// The brush.
+ /// The rectangle bounds.
+ /// The corner radius.
+ 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();
+ }
+
+
+ }
+
+
+ ///
+ /// Pushes a clip rectange.
+ ///
+ /// The clip rectangle.
+ /// A disposable used to undo the clip rectangle.
+ public PushedState PushClip(Rect clip)
+ {
+ _impl.PushClip(clip);
+ return new PushedState(this, PushedState.PushedStateType.Clip);
+ }
+
+ ///
+ /// Pushes an opacity value.
+ ///
+ /// The opacity.
+ /// A disposable used to undo the opacity.
+ public PushedState PushOpacity(double opacity)
+ //TODO: Elimintate platform-specific push opacity call
+ {
+ _impl.PushOpacity(opacity);
+ return new PushedState(this, PushedState.PushedStateType.Opacity);
+ }
+
+ ///
+ /// Pushes a matrix transformation.
+ ///
+ /// The matrix
+ /// A disposable used to undo the transformation.
+ 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();
+ }
+}
diff --git a/src/Perspex.SceneGraph/Media/IDrawingContext.cs b/src/Perspex.SceneGraph/Media/IDrawingContext.cs
index 92d1fc4e98..4d144b33e0 100644
--- a/src/Perspex.SceneGraph/Media/IDrawingContext.cs
+++ b/src/Perspex.SceneGraph/Media/IDrawingContext.cs
@@ -9,12 +9,12 @@ namespace Perspex.Media
///
/// Defines the interface through which drawing occurs.
///
- public interface IDrawingContext : IDisposable
+ public interface IDrawingContextImpl : IDisposable
{
///
- /// Gets the current transform of the drawing context.
+ /// Gets or sets the current transform of the drawing context.
///
- Matrix CurrentTransform { get; }
+ Matrix Transform { get; set; }
///
/// Draws a bitmap image.
@@ -70,20 +70,17 @@ namespace Perspex.Media
///
/// The clip rectangle.
/// A disposable used to undo the clip rectangle.
- IDisposable PushClip(Rect clip);
+ void PushClip(Rect clip);
+
+ void PopClip();
///
/// Pushes an opacity value.
///
/// The opacity.
/// A disposable used to undo the opacity.
- IDisposable PushOpacity(double opacity);
+ void PushOpacity(double opacity);
- ///
- /// Pushes a matrix transformation.
- ///
- /// The matrix
- /// A disposable used to undo the transformation.
- IDisposable PushTransform(Matrix matrix);
+ void PopOpacity();
}
}
diff --git a/src/Perspex.SceneGraph/Media/Imaging/RenderTargetBitmap.cs b/src/Perspex.SceneGraph/Media/Imaging/RenderTargetBitmap.cs
index 5b8bbea6da..20fc55ebd8 100644
--- a/src/Perspex.SceneGraph/Media/Imaging/RenderTargetBitmap.cs
+++ b/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)
{
diff --git a/src/Perspex.SceneGraph/Media/ValidatingDrawingContext.cs b/src/Perspex.SceneGraph/Media/ValidatingDrawingContext.cs
deleted file mode 100644
index 86ae342894..0000000000
--- a/src/Perspex.SceneGraph/Media/ValidatingDrawingContext.cs
+++ /dev/null
@@ -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 _stateStack = new Stack();
-
- 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));
- }
-}
\ No newline at end of file
diff --git a/src/Perspex.SceneGraph/Perspex.SceneGraph.csproj b/src/Perspex.SceneGraph/Perspex.SceneGraph.csproj
index e09bed7d90..d2d897142f 100644
--- a/src/Perspex.SceneGraph/Perspex.SceneGraph.csproj
+++ b/src/Perspex.SceneGraph/Perspex.SceneGraph.csproj
@@ -64,6 +64,7 @@
+
@@ -99,7 +100,6 @@
-
diff --git a/src/Perspex.SceneGraph/Platform/IRenderTarget.cs b/src/Perspex.SceneGraph/Platform/IRenderTarget.cs
index fdbf391a05..a5c8f71d79 100644
--- a/src/Perspex.SceneGraph/Platform/IRenderTarget.cs
+++ b/src/Perspex.SceneGraph/Platform/IRenderTarget.cs
@@ -15,9 +15,9 @@ namespace Perspex.Platform
public interface IRenderTarget : IDisposable
{
///
- /// Creates an for a rendering session.
+ /// Creates an for a rendering session.
///
- IDrawingContext CreateDrawingContext();
+ DrawingContext CreateDrawingContext();
///
/// Resizes the rendered viewport.
diff --git a/src/Perspex.SceneGraph/Rendering/RendererBase.cs b/src/Perspex.SceneGraph/Rendering/RendererBase.cs
index ba4a0d35c1..679407f7bf 100644
--- a/src/Perspex.SceneGraph/Rendering/RendererBase.cs
+++ b/src/Perspex.SceneGraph/Rendering/RendererBase.cs
@@ -35,7 +35,7 @@ namespace Perspex.Rendering
/// The visual to render.
///
/// The drawing context.
- 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))
diff --git a/src/Perspex.SceneGraph/Visual.cs b/src/Perspex.SceneGraph/Visual.cs
index e835c6a76c..2bbc290685 100644
--- a/src/Perspex.SceneGraph/Visual.cs
+++ b/src/Perspex.SceneGraph/Visual.cs
@@ -229,10 +229,10 @@ namespace Perspex
}
///
- /// Renders the visual to a .
+ /// Renders the visual to a .
///
/// The drawing context.
- public virtual void Render(IDrawingContext context)
+ public virtual void Render(DrawingContext context)
{
Contract.Requires(context != null);
}
diff --git a/src/Windows/Perspex.Direct2D1/Media/DrawingContext.cs b/src/Windows/Perspex.Direct2D1/Media/DrawingContext.cs
index 0b6abe9353..b10208d7e0 100644
--- a/src/Windows/Perspex.Direct2D1/Media/DrawingContext.cs
+++ b/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
///
/// Draws using Direct2D1.
///
- public class DrawingContext : IDrawingContext, IDisposable
+ public class DrawingContext : IDrawingContextImpl, IDisposable
{
///
/// The Direct2D1 render target.
@@ -42,10 +44,10 @@ namespace Perspex.Direct2D1.Media
///
/// Gets the current transform of the drawing context.
///
- public Matrix CurrentTransform
+ public Matrix Transform
{
get { return _renderTarget.Transform.ToPerspex(); }
- private set { _renderTarget.Transform = value.ToDirect2D(); }
+ set { _renderTarget.Transform = value.ToDirect2D(); }
}
///
@@ -53,6 +55,8 @@ namespace Perspex.Direct2D1.Media
///
public void Dispose()
{
+ foreach (var layer in _layerPool)
+ layer.Dispose();
_renderTarget.EndDraw();
}
@@ -233,22 +237,24 @@ namespace Perspex.Direct2D1.Media
///
/// The clip rectangle.
/// A disposable used to undo the clip rectangle.
- 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 _layers = new Stack();
+ private readonly Stack _layerPool = new Stack();
///
/// Pushes an opacity value.
///
/// The opacity.
/// A disposable used to undo the opacity.
- 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);
}
- ///
- /// Pushes a matrix transformation.
- ///
- /// The matrix
- /// A disposable used to undo the transformation.
- 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);
+ }
}
///
diff --git a/src/Windows/Perspex.Direct2D1/Media/Imaging/RenderTargetBitmapImpl.cs b/src/Windows/Perspex.Direct2D1/Media/Imaging/RenderTargetBitmapImpl.cs
index 97efa00d47..cf785aa444 100644
--- a/src/Windows/Perspex.Direct2D1/Media/Imaging/RenderTargetBitmapImpl.cs
+++ b/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)
{
diff --git a/src/Windows/Perspex.Direct2D1/RenderTarget.cs b/src/Windows/Perspex.Direct2D1/RenderTarget.cs
index 5feabdde87..66ffe80448 100644
--- a/src/Windows/Perspex.Direct2D1/RenderTarget.cs
+++ b/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
- }
-
///
/// Creates a drawing context for a rendering session.
///
- /// An .
- public IDrawingContext CreateDrawingContext()
- {
- return Wrap(new DrawingContext(_renderTarget, DirectWriteFactory));
- }
+ /// An .
+ public DrawingContext CreateDrawingContext()
+ => new DrawingContext(new Media.DrawingContext(_renderTarget, DirectWriteFactory));
public void Dispose()
{