From 4e7b743ecd9a78f2c495b5e58963767bcb5a89b9 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Sun, 5 Mar 2017 20:27:36 +0100 Subject: [PATCH] Ported changes to DrawingContext from scenegraph Ported changes to `DrawingContext` and `DrawingContextImpl` from the `scenegraph` branch. --- src/Avalonia.Visuals/Avalonia.Visuals.csproj | 2 +- src/Avalonia.Visuals/Media/DrawingContext.cs | 100 ++++++++++++------ ...awingContext.cs => IDrawingContextImpl.cs} | 18 ++-- .../Platform/IFormattedTextImpl.cs | 5 + .../Avalonia.Cairo/Media/DrawingContext.cs | 25 +++-- .../Avalonia.Cairo/Media/FormattedTextImpl.cs | 8 +- src/Skia/Avalonia.Skia/DrawingContextImpl.cs | 22 ++-- src/Skia/Avalonia.Skia/FormattedTextImpl.cs | 29 ++--- .../Avalonia.Direct2D1.csproj | 2 +- .../Media/AvaloniaTextRenderer.cs | 4 +- ...rawingContext.cs => DrawingContextImpl.cs} | 31 +++--- .../Media/FormattedTextImpl.cs | 3 + .../Avalonia.Direct2D1/RenderTarget.cs | 2 +- .../SwapChainRenderTarget.cs | 2 +- 14 files changed, 160 insertions(+), 93 deletions(-) rename src/Avalonia.Visuals/Media/{IDrawingContext.cs => IDrawingContextImpl.cs} (85%) rename src/Windows/Avalonia.Direct2D1/Media/{DrawingContext.cs => DrawingContextImpl.cs} (93%) diff --git a/src/Avalonia.Visuals/Avalonia.Visuals.csproj b/src/Avalonia.Visuals/Avalonia.Visuals.csproj index d5a8a261bd..514fa6f481 100644 --- a/src/Avalonia.Visuals/Avalonia.Visuals.csproj +++ b/src/Avalonia.Visuals/Avalonia.Visuals.csproj @@ -107,7 +107,7 @@ - + diff --git a/src/Avalonia.Visuals/Media/DrawingContext.cs b/src/Avalonia.Visuals/Media/DrawingContext.cs index 3d6f14cfce..8c3f41aec7 100644 --- a/src/Avalonia.Visuals/Media/DrawingContext.cs +++ b/src/Avalonia.Visuals/Media/DrawingContext.cs @@ -1,18 +1,13 @@ using System; using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Avalonia.Media.Imaging; namespace Avalonia.Media { public sealed class DrawingContext : IDisposable { - private readonly IDrawingContextImpl _impl; private int _currentLevel; - + static readonly Stack> StateStackPool = new Stack>(); static readonly Stack> TransformStackPool = new Stack>(); @@ -37,14 +32,15 @@ namespace Avalonia.Media public DrawingContext(IDrawingContextImpl impl) { - _impl = impl; + PlatformImpl = impl; } + public IDrawingContextImpl PlatformImpl { get; } private Matrix _currentTransform = Matrix.Identity; private Matrix _currentContainerTransform = Matrix.Identity; - + /// /// Gets the current transform of the drawing context. /// @@ -54,15 +50,15 @@ namespace Avalonia.Media private set { _currentTransform = value; - var transform = _currentTransform*_currentContainerTransform; - _impl.Transform = transform; + var transform = _currentTransform * _currentContainerTransform; + PlatformImpl.Transform = transform; } } //HACK: This is a temporary hack that is used in the render loop //to update TransformedBounds property [Obsolete("HACK for render loop, don't use")] - internal Matrix CurrentContainerTransform => _currentContainerTransform; + internal Matrix CurrentContainerTransform => _currentContainerTransform; /// /// Draws a bitmap image. @@ -72,7 +68,11 @@ namespace Avalonia.Media /// 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); + { + Contract.Requires(source != null); + + PlatformImpl.DrawImage(source.PlatformImpl, opacity, sourceRect, destRect); + } /// /// Draws a line. @@ -80,7 +80,13 @@ namespace Avalonia.Media /// 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); + public void DrawLine(Pen pen, Point p1, Point p2) + { + if (PenIsVisible(pen)) + { + PlatformImpl.DrawLine(pen, p1, p2); + } + } /// /// Draws a geometry. @@ -88,7 +94,13 @@ namespace Avalonia.Media /// The fill brush. /// The stroke pen. /// The geometry. - public void DrawGeometry(IBrush brush, Pen pen, Geometry geometry) => _impl.DrawGeometry(brush, pen, geometry); + public void DrawGeometry(IBrush brush, Pen pen, Geometry geometry) + { + if (brush != null || PenIsVisible(pen)) + { + PlatformImpl.DrawGeometry(brush, pen, geometry.PlatformImpl); + } + } /// /// Draws the outline of a rectangle. @@ -97,7 +109,12 @@ namespace Avalonia.Media /// The rectangle bounds. /// The corner radius. public void DrawRectangle(Pen pen, Rect rect, float cornerRadius = 0.0f) - => _impl.DrawRectangle(pen, rect, cornerRadius); + { + if (PenIsVisible(pen)) + { + PlatformImpl.DrawRectangle(pen, rect, cornerRadius); + } + } /// /// Draws text. @@ -106,7 +123,14 @@ namespace Avalonia.Media /// The upper-left corner of the text. /// The text. public void DrawText(IBrush foreground, Point origin, FormattedText text) - => _impl.DrawText(foreground, origin, text); + { + Contract.Requires(text != null); + + if (foreground != null) + { + PlatformImpl.DrawText(foreground, origin, text.PlatformImpl); + } + } /// /// Draws a filled rectangle. @@ -115,7 +139,12 @@ namespace Avalonia.Media /// The rectangle bounds. /// The corner radius. public void FillRectangle(IBrush brush, Rect rect, float cornerRadius = 0.0f) - => _impl.FillRectangle(brush, rect, cornerRadius); + { + if (brush != null && rect != Rect.Empty) + { + PlatformImpl.FillRectangle(brush, rect, cornerRadius); + } + } public struct PushedState : IDisposable { @@ -146,7 +175,7 @@ namespace Avalonia.Media public void Dispose() { - if(_type == PushedStateType.None) + if (_type == PushedStateType.None) return; if (_context._currentLevel != _level) throw new InvalidOperationException("Wrong Push/Pop state order"); @@ -155,13 +184,13 @@ namespace Avalonia.Media if (_type == PushedStateType.Matrix) _context.CurrentTransform = _matrix; else if (_type == PushedStateType.Clip) - _context._impl.PopClip(); + _context.PlatformImpl.PopClip(); else if (_type == PushedStateType.Opacity) - _context._impl.PopOpacity(); + _context.PlatformImpl.PopOpacity(); else if (_type == PushedStateType.GeometryClip) - _context._impl.PopGeometryClip(); + _context.PlatformImpl.PopGeometryClip(); else if (_type == PushedStateType.OpacityMask) - _context._impl.PopOpacityMask(); + _context.PlatformImpl.PopOpacityMask(); else if (_type == PushedStateType.MatrixContainer) { var cont = _context._transformContainers.Pop(); @@ -179,7 +208,7 @@ namespace Avalonia.Media /// A disposable used to undo the clip rectangle. public PushedState PushClip(Rect clip) { - _impl.PushClip(clip); + PlatformImpl.PushClip(clip); return new PushedState(this, PushedState.PushedStateType.Clip); } @@ -191,7 +220,7 @@ namespace Avalonia.Media public PushedState PushGeometryClip(Geometry clip) { Contract.Requires(clip != null); - _impl.PushGeometryClip(clip); + PlatformImpl.PushGeometryClip(clip.PlatformImpl); return new PushedState(this, PushedState.PushedStateType.GeometryClip); } @@ -201,9 +230,9 @@ namespace Avalonia.Media /// The opacity. /// A disposable used to undo the opacity. public PushedState PushOpacity(double opacity) - //TODO: Eliminate platform-specific push opacity call + //TODO: Eliminate platform-specific push opacity call { - _impl.PushOpacity(opacity); + PlatformImpl.PushOpacity(opacity); return new PushedState(this, PushedState.PushedStateType.Opacity); } @@ -217,7 +246,7 @@ namespace Avalonia.Media /// A disposable to undo the opacity mask. public PushedState PushOpacityMask(IBrush mask, Rect bounds) { - _impl.PushOpacityMask(mask, bounds); + PlatformImpl.PushOpacityMask(mask, bounds); return new PushedState(this, PushedState.PushedStateType.OpacityMask); } @@ -226,14 +255,14 @@ namespace Avalonia.Media /// /// The matrix /// A disposable used to undo the transformation. - public PushedState PushPostTransform(Matrix matrix) => PushSetTransform(CurrentTransform*matrix); + public PushedState PushPostTransform(Matrix matrix) => PushSetTransform(CurrentTransform * matrix); /// /// Pushes a matrix pre-transformation. /// /// The matrix /// A disposable used to undo the transformation. - public PushedState PushPreTransform(Matrix matrix) => PushSetTransform(matrix*CurrentTransform); + public PushedState PushPreTransform(Matrix matrix) => PushSetTransform(matrix * CurrentTransform); /// /// Sets the current matrix transformation. @@ -244,7 +273,7 @@ namespace Avalonia.Media { var oldMatrix = CurrentTransform; CurrentTransform = matrix; - + return new PushedState(this, PushedState.PushedStateType.Matrix, oldMatrix); } @@ -255,7 +284,7 @@ namespace Avalonia.Media public PushedState PushTransformContainer() { _transformContainers.Push(new TransformContainer(CurrentTransform, _currentContainerTransform)); - _currentContainerTransform = CurrentTransform*_currentContainerTransform; + _currentContainerTransform = CurrentTransform * _currentContainerTransform; _currentTransform = Matrix.Identity; return new PushedState(this, PushedState.PushedStateType.MatrixContainer); } @@ -271,7 +300,12 @@ namespace Avalonia.Media _states = null; TransformStackPool.Push(_transformContainers); _transformContainers = null; - _impl.Dispose(); + PlatformImpl.Dispose(); + } + + private static bool PenIsVisible(Pen pen) + { + return pen?.Brush != null && pen.Thickness > 0; } } -} +} \ No newline at end of file diff --git a/src/Avalonia.Visuals/Media/IDrawingContext.cs b/src/Avalonia.Visuals/Media/IDrawingContextImpl.cs similarity index 85% rename from src/Avalonia.Visuals/Media/IDrawingContext.cs rename to src/Avalonia.Visuals/Media/IDrawingContextImpl.cs index c63abc160f..c62bca3486 100644 --- a/src/Avalonia.Visuals/Media/IDrawingContext.cs +++ b/src/Avalonia.Visuals/Media/IDrawingContextImpl.cs @@ -2,7 +2,7 @@ // Licensed under the MIT license. See licence.md file in the project root for full license information. using System; -using Avalonia.Media.Imaging; +using Avalonia.Platform; namespace Avalonia.Media { @@ -16,6 +16,12 @@ namespace Avalonia.Media /// Matrix Transform { get; set; } + /// + /// Clears the render target to the specified color. + /// + /// The color. + void Clear(Color color); + /// /// Draws a bitmap image. /// @@ -23,7 +29,7 @@ namespace Avalonia.Media /// The opacity to draw with. /// The rect in the image to draw. /// The rect in the output to draw to. - void DrawImage(IBitmap source, double opacity, Rect sourceRect, Rect destRect); + void DrawImage(IBitmapImpl source, double opacity, Rect sourceRect, Rect destRect); /// /// Draws a line. @@ -39,7 +45,7 @@ namespace Avalonia.Media /// The fill brush. /// The stroke pen. /// The geometry. - void DrawGeometry(IBrush brush, Pen pen, Geometry geometry); + void DrawGeometry(IBrush brush, Pen pen, IGeometryImpl geometry); /// /// Draws the outline of a rectangle. @@ -55,7 +61,7 @@ namespace Avalonia.Media /// The foreground brush. /// The upper-left corner of the text. /// The text. - void DrawText(IBrush foreground, Point origin, FormattedText text); + void DrawText(IBrush foreground, Point origin, IFormattedTextImpl text); /// /// Draws a filled rectangle. @@ -89,8 +95,8 @@ namespace Avalonia.Media /// Pushes a clip geometry. /// /// The clip geometry. - void PushGeometryClip(Geometry clip); + void PushGeometryClip(IGeometryImpl clip); void PopGeometryClip(); } -} +} \ No newline at end of file diff --git a/src/Avalonia.Visuals/Platform/IFormattedTextImpl.cs b/src/Avalonia.Visuals/Platform/IFormattedTextImpl.cs index 14f9e987bd..e3a44c437e 100644 --- a/src/Avalonia.Visuals/Platform/IFormattedTextImpl.cs +++ b/src/Avalonia.Visuals/Platform/IFormattedTextImpl.cs @@ -17,6 +17,11 @@ namespace Avalonia.Platform /// Size Constraint { get; set; } + /// + /// Gets the text. + /// + string Text { get; } + /// /// Gets the lines in the text. /// diff --git a/src/Gtk/Avalonia.Cairo/Media/DrawingContext.cs b/src/Gtk/Avalonia.Cairo/Media/DrawingContext.cs index c9d07ad0cb..5dc5b1dab2 100644 --- a/src/Gtk/Avalonia.Cairo/Media/DrawingContext.cs +++ b/src/Gtk/Avalonia.Cairo/Media/DrawingContext.cs @@ -5,13 +5,12 @@ using System; using System.Collections.Generic; using System.Linq; using System.Reactive.Disposables; -using System.Runtime.InteropServices; using Avalonia.Cairo.Media.Imaging; using Avalonia.Media; +using Avalonia.Platform; namespace Avalonia.Cairo.Media { - using Avalonia.Media.Imaging; using Cairo = global::Cairo; /// @@ -60,6 +59,12 @@ namespace Avalonia.Cairo.Media } } + public void Clear(Color color) + { + _context.SetSourceRGBA(color.R, color.G, color.B, color.A); + _context.Paint(); + } + /// /// Ends a draw operation. /// @@ -75,9 +80,9 @@ namespace Avalonia.Cairo.Media /// The opacity to draw with. /// The rect in the image to draw. /// The rect in the output to draw to. - public void DrawImage(IBitmap bitmap, double opacity, Rect sourceRect, Rect destRect) + public void DrawImage(IBitmapImpl bitmap, double opacity, Rect sourceRect, Rect destRect) { - var impl = bitmap.PlatformImpl as BitmapImpl; + var impl = bitmap as BitmapImpl; var size = new Size(impl.PixelWidth, impl.PixelHeight); var scale = new Vector(destRect.Width / sourceRect.Width, destRect.Height / sourceRect.Height); @@ -137,9 +142,9 @@ namespace Avalonia.Cairo.Media /// The fill brush. /// The stroke pen. /// The geometry. - public void DrawGeometry(IBrush brush, Pen pen, Geometry geometry) + public void DrawGeometry(IBrush brush, Pen pen, IGeometryImpl geometry) { - var impl = geometry.PlatformImpl as StreamGeometryImpl; + var impl = geometry as StreamGeometryImpl; var oldMatrix = Transform; Transform = impl.Transform * Transform; @@ -192,9 +197,9 @@ namespace Avalonia.Cairo.Media /// The foreground brush. /// The upper-left corner of the text. /// The text. - public void DrawText(IBrush foreground, Point origin, FormattedText text) + public void DrawText(IBrush foreground, Point origin, IFormattedTextImpl text) { - var layout = ((FormattedTextImpl)text.PlatformImpl).Layout; + var layout = ((FormattedTextImpl)text).Layout; _context.MoveTo(origin.X, origin.Y); using (var b = SetBrush(foreground, new Size(0, 0))) @@ -350,10 +355,10 @@ namespace Avalonia.Cairo.Media return SetBrush(pen.Brush, destinationSize); } - public void PushGeometryClip(Geometry clip) + public void PushGeometryClip(IGeometryImpl clip) { _context.Save(); - _context.AppendPath(((StreamGeometryImpl)clip.PlatformImpl).Path); + _context.AppendPath(((StreamGeometryImpl)clip).Path); _context.Clip(); } diff --git a/src/Gtk/Avalonia.Cairo/Media/FormattedTextImpl.cs b/src/Gtk/Avalonia.Cairo/Media/FormattedTextImpl.cs index e9d092559d..6c023c212e 100644 --- a/src/Gtk/Avalonia.Cairo/Media/FormattedTextImpl.cs +++ b/src/Gtk/Avalonia.Cairo/Media/FormattedTextImpl.cs @@ -13,7 +13,6 @@ namespace Avalonia.Cairo.Media public class FormattedTextImpl : IFormattedTextImpl { private Size _size; - private readonly string _text; static double CorrectScale(double input) { @@ -32,7 +31,6 @@ namespace Avalonia.Cairo.Media Contract.Requires(context != null); Contract.Requires(text != null); Layout = new Pango.Layout(context); - _text = text; Layout.SetText(text); Layout.FontDescription = new Pango.FontDescription { @@ -46,6 +44,8 @@ namespace Avalonia.Cairo.Media Layout.Attributes = new Pango.AttrList(); } + public string Text => Layout.Text; + public Size Constraint { get @@ -99,7 +99,7 @@ namespace Avalonia.Cairo.Media int PangoIndexToTextIndex(int pangoIndex) { - return Encoding.UTF8.GetString(Encoding.UTF8.GetBytes(_text), 0, Math.Min(pangoIndex, _text.Length)).Length; + return Encoding.UTF8.GetString(Encoding.UTF8.GetBytes(Text), 0, Math.Min(pangoIndex, Text.Length)).Length; } public Rect HitTestTextPosition(int index) @@ -109,7 +109,7 @@ namespace Avalonia.Cairo.Media int TextIndexToPangoIndex(int textIndex) { - return Encoding.UTF8.GetByteCount(textIndex < _text.Length ? _text.Remove(textIndex) : _text); + return Encoding.UTF8.GetByteCount(textIndex < Text.Length ? Text.Remove(textIndex) : Text); } public IEnumerable HitTestTextRange(int index, int length) diff --git a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs index 10ce1d1c91..eade31523d 100644 --- a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs +++ b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs @@ -5,6 +5,7 @@ using SkiaSharp; using System; using System.Collections.Generic; using System.Linq; +using Avalonia.Platform; namespace Avalonia.Skia { @@ -26,9 +27,14 @@ namespace Avalonia.Skia Transform = Matrix.Identity; } - public void DrawImage(IBitmap source, double opacity, Rect sourceRect, Rect destRect) + public void Clear(Color color) { - var impl = (BitmapImpl)source.PlatformImpl; + Canvas.Clear(color.ToSKColor()); + } + + public void DrawImage(IBitmapImpl source, double opacity, Rect sourceRect, Rect destRect) + { + var impl = (BitmapImpl)source; var s = sourceRect.ToSKRect(); var d = destRect.ToSKRect(); using (var paint = new SKPaint() @@ -46,9 +52,9 @@ namespace Avalonia.Skia } } - public void DrawGeometry(IBrush brush, Pen pen, Geometry geometry) + public void DrawGeometry(IBrush brush, Pen pen, IGeometryImpl geometry) { - var impl = ((StreamGeometryImpl)geometry.PlatformImpl); + var impl = (StreamGeometryImpl)geometry; var size = geometry.Bounds.Size; using (var fill = brush != null ? CreatePaint(brush, size) : default(PaintWrapper)) @@ -284,11 +290,11 @@ namespace Avalonia.Skia } } - public void DrawText(IBrush foreground, Point origin, FormattedText text) + public void DrawText(IBrush foreground, Point origin, IFormattedTextImpl text) { using (var paint = CreatePaint(foreground, text.Measure())) { - var textImpl = text.PlatformImpl as FormattedTextImpl; + var textImpl = (FormattedTextImpl)text; textImpl.Draw(this, Canvas, origin.ToSKPoint(), paint); } } @@ -325,10 +331,10 @@ namespace Avalonia.Skia disposable?.Dispose(); } - public void PushGeometryClip(Geometry clip) + public void PushGeometryClip(IGeometryImpl clip) { Canvas.Save(); - Canvas.ClipPath(((StreamGeometryImpl)clip.PlatformImpl).EffectivePath); + Canvas.ClipPath(((StreamGeometryImpl)clip).EffectivePath); } public void PopGeometryClip() diff --git a/src/Skia/Avalonia.Skia/FormattedTextImpl.cs b/src/Skia/Avalonia.Skia/FormattedTextImpl.cs index 7e70f9354e..e427dc0f58 100644 --- a/src/Skia/Avalonia.Skia/FormattedTextImpl.cs +++ b/src/Skia/Avalonia.Skia/FormattedTextImpl.cs @@ -15,10 +15,10 @@ namespace Avalonia.Skia public FormattedTextImpl(string text, string fontFamilyName, double fontSize, FontStyle fontStyle, TextAlignment textAlignment, FontWeight fontWeight, TextWrapping wrapping) { - _text = text ?? string.Empty; + Text = text ?? string.Empty; // Replace 0 characters with zero-width spaces (200B) - _text = _text.Replace((char)0, (char)0x200B); + Text = Text.Replace((char)0, (char)0x200B); var typeface = TypefaceCache.GetTypeface(fontFamilyName, fontStyle, fontWeight); @@ -54,6 +54,8 @@ namespace Avalonia.Skia } } + public string Text { get; } + public void Dispose() { } @@ -98,7 +100,7 @@ namespace Avalonia.Skia { IsInside = false, TextPosition = line.Start + offset, - IsTrailing = _text.Length == (line.Start + offset + 1) + IsTrailing = Text.Length == (line.Start + offset + 1) }; } @@ -108,7 +110,7 @@ namespace Avalonia.Skia { IsInside = false, IsTrailing = end, - TextPosition = end ? _text.Length - 1 : 0 + TextPosition = end ? Text.Length - 1 : 0 }; } @@ -182,7 +184,7 @@ namespace Avalonia.Skia public override string ToString() { - return _text; + return Text; } internal void Draw(DrawingContextImpl context, @@ -231,7 +233,7 @@ namespace Avalonia.Skia if (!hasCusomFGBrushes) { - var subString = _text.Substring(line.Start, line.Length); + var subString = Text.Substring(line.Start, line.Length); canvas.DrawText(subString, x, origin.Y + line.Top + _lineOffset, paint); } else @@ -255,7 +257,7 @@ namespace Avalonia.Skia currentWrapper = foreground; } - subStr = _text.Substring(i, len); + subStr = Text.Substring(i, len); if (currFGPaint != currentWrapper.Paint) { @@ -284,7 +286,6 @@ namespace Avalonia.Skia private readonly List _lines = new List(); private readonly SKPaint _paint; private readonly List _rects = new List(); - private readonly string _text; private readonly TextWrapping _wrapping; private Size _constraint = new Size(double.PositiveInfinity, double.PositiveInfinity); private float _lineHeight = 0; @@ -434,7 +435,7 @@ namespace Avalonia.Skia for (int i = line.Start; i < line.Start + line.TextLength; i++) { - float w = _paint.MeasureText(_text[i].ToString()); + float w = _paint.MeasureText(Text[i].ToString()); _rects.Add(new Rect( prevRight, @@ -490,7 +491,7 @@ namespace Avalonia.Skia private List GetRects() { - if (_text.Length > _rects.Count) + if (Text.Length > _rects.Count) { BuildRects(); } @@ -500,7 +501,7 @@ namespace Avalonia.Skia private void Rebuild() { - var length = _text.Length; + var length = Text.Length; _lines.Clear(); _rects.Clear(); @@ -536,7 +537,7 @@ namespace Avalonia.Skia int measured; int trailingnumber = 0; - subString = _text.Substring(curOff); + subString = Text.Substring(curOff); float constraint = -1; @@ -547,12 +548,12 @@ namespace Avalonia.Skia constraint = MAX_LINE_WIDTH; } - measured = LineBreak(_text, curOff, length, _paint, constraint, out trailingnumber); + measured = LineBreak(Text, curOff, length, _paint, constraint, out trailingnumber); AvaloniaFormattedTextLine line = new AvaloniaFormattedTextLine(); line.TextLength = measured; - subString = _text.Substring(line.Start, line.TextLength); + subString = Text.Substring(line.Start, line.TextLength); lineWidth = _paint.MeasureText(subString); line.Start = curOff; line.Length = measured - trailingnumber; diff --git a/src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj b/src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj index ba117d72e9..8292ab46ed 100644 --- a/src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj +++ b/src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj @@ -65,7 +65,7 @@ - + diff --git a/src/Windows/Avalonia.Direct2D1/Media/AvaloniaTextRenderer.cs b/src/Windows/Avalonia.Direct2D1/Media/AvaloniaTextRenderer.cs index a1b9f85783..51b4eef62d 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/AvaloniaTextRenderer.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/AvaloniaTextRenderer.cs @@ -11,14 +11,14 @@ namespace Avalonia.Direct2D1.Media { internal class AvaloniaTextRenderer : TextRenderer { - private readonly DrawingContext _context; + private readonly DrawingContextImpl _context; private readonly SharpDX.Direct2D1.RenderTarget _renderTarget; private readonly Brush _foreground; public AvaloniaTextRenderer( - DrawingContext context, + DrawingContextImpl context, SharpDX.Direct2D1.RenderTarget target, Brush foreground) { diff --git a/src/Windows/Avalonia.Direct2D1/Media/DrawingContext.cs b/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs similarity index 93% rename from src/Windows/Avalonia.Direct2D1/Media/DrawingContext.cs rename to src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs index 51925d5341..2c5ad778c2 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/DrawingContext.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs @@ -5,6 +5,7 @@ using System; using System.Collections; using System.Collections.Generic; using Avalonia.Media; +using Avalonia.Platform; using SharpDX; using SharpDX.Direct2D1; using SharpDX.Mathematics.Interop; @@ -15,7 +16,7 @@ namespace Avalonia.Direct2D1.Media /// /// Draws using Direct2D1. /// - public class DrawingContext : IDrawingContextImpl, IDisposable + public class DrawingContextImpl : IDrawingContextImpl, IDisposable { /// /// The Direct2D1 render target. @@ -30,12 +31,12 @@ namespace Avalonia.Direct2D1.Media private SharpDX.DXGI.SwapChain1 _swapChain; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The render target to draw to. /// The DirectWrite factory. /// An optional swap chain associated with this drawing context. - public DrawingContext( + public DrawingContextImpl( SharpDX.Direct2D1.RenderTarget renderTarget, SharpDX.DirectWrite.Factory directWriteFactory, SharpDX.DXGI.SwapChain1 swapChain = null) @@ -55,6 +56,12 @@ namespace Avalonia.Direct2D1.Media set { _renderTarget.Transform = value.ToDirect2D(); } } + /// + public void Clear(Color color) + { + _renderTarget.Clear(color.ToDirect2D()); + } + /// /// Ends a draw operation. /// @@ -81,9 +88,9 @@ namespace Avalonia.Direct2D1.Media /// 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) + public void DrawImage(IBitmapImpl source, double opacity, Rect sourceRect, Rect destRect) { - var impl = (BitmapImpl)source.PlatformImpl; + var impl = (BitmapImpl)source; Bitmap d2d = impl.GetDirect2DBitmap(_renderTarget); _renderTarget.DrawBitmap( d2d, @@ -127,7 +134,7 @@ namespace Avalonia.Direct2D1.Media /// The fill brush. /// The stroke pen. /// The geometry. - public void DrawGeometry(IBrush brush, Pen pen, Avalonia.Media.Geometry geometry) + public void DrawGeometry(IBrush brush, Pen pen, IGeometryImpl geometry) { if (brush != null) { @@ -135,7 +142,7 @@ namespace Avalonia.Direct2D1.Media { if (d2dBrush.PlatformBrush != null) { - var impl = (GeometryImpl)geometry.PlatformImpl; + var impl = (GeometryImpl)geometry; _renderTarget.FillGeometry(impl.Geometry, d2dBrush.PlatformBrush); } } @@ -148,7 +155,7 @@ namespace Avalonia.Direct2D1.Media { if (d2dBrush.PlatformBrush != null) { - var impl = (GeometryImpl)geometry.PlatformImpl; + var impl = (GeometryImpl)geometry; _renderTarget.DrawGeometry(impl.Geometry, d2dBrush.PlatformBrush, (float)pen.Thickness, d2dStroke); } } @@ -194,11 +201,11 @@ namespace Avalonia.Direct2D1.Media /// The foreground brush. /// The upper-left corner of the text. /// The text. - public void DrawText(IBrush foreground, Point origin, FormattedText text) + public void DrawText(IBrush foreground, Point origin, IFormattedTextImpl text) { if (!string.IsNullOrEmpty(text.Text)) { - var impl = (FormattedTextImpl)text.PlatformImpl; + var impl = (FormattedTextImpl)text; using (var brush = CreateBrush(foreground, impl.Measure())) using (var renderer = new AvaloniaTextRenderer(this, _renderTarget, brush.PlatformBrush)) @@ -343,14 +350,14 @@ namespace Avalonia.Direct2D1.Media } } - public void PushGeometryClip(Avalonia.Media.Geometry clip) + public void PushGeometryClip(IGeometryImpl clip) { var parameters = new LayerParameters { ContentBounds = PrimitiveExtensions.RectangleInfinite, MaskTransform = PrimitiveExtensions.Matrix3x2Identity, Opacity = 1, - GeometricMask = ((GeometryImpl)clip.PlatformImpl).Geometry + GeometricMask = ((GeometryImpl)clip).Geometry }; var layer = _layerPool.Count != 0 ? _layerPool.Pop() : new Layer(_renderTarget); _renderTarget.PushLayer(ref parameters, layer); diff --git a/src/Windows/Avalonia.Direct2D1/Media/FormattedTextImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/FormattedTextImpl.cs index 45d06b5e27..ae226a5087 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/FormattedTextImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/FormattedTextImpl.cs @@ -30,6 +30,7 @@ namespace Avalonia.Direct2D1.Media (DWrite.FontStyle)fontStyle, (float)fontSize)) { + Text = text; format.WordWrapping = wrapping == TextWrapping.Wrap ? DWrite.WordWrapping.Wrap : DWrite.WordWrapping.NoWrap; @@ -58,6 +59,8 @@ namespace Avalonia.Direct2D1.Media } } + public string Text { get; } + public DWrite.TextLayout TextLayout { get; } public void Dispose() diff --git a/src/Windows/Avalonia.Direct2D1/RenderTarget.cs b/src/Windows/Avalonia.Direct2D1/RenderTarget.cs index 52146d77c1..e105f90442 100644 --- a/src/Windows/Avalonia.Direct2D1/RenderTarget.cs +++ b/src/Windows/Avalonia.Direct2D1/RenderTarget.cs @@ -51,7 +51,7 @@ namespace Avalonia.Direct2D1 /// An . public DrawingContext CreateDrawingContext() { - return new DrawingContext(new Media.DrawingContext(_renderTarget, DirectWriteFactory)); + return new DrawingContext(new Media.DrawingContextImpl(_renderTarget, DirectWriteFactory)); } public void Dispose() diff --git a/src/Windows/Avalonia.Direct2D1/SwapChainRenderTarget.cs b/src/Windows/Avalonia.Direct2D1/SwapChainRenderTarget.cs index 119715b5fc..afad78ecca 100644 --- a/src/Windows/Avalonia.Direct2D1/SwapChainRenderTarget.cs +++ b/src/Windows/Avalonia.Direct2D1/SwapChainRenderTarget.cs @@ -69,7 +69,7 @@ namespace Avalonia.Direct2D1 CreateSwapChain(); } - return new DrawingContext(new Media.DrawingContext(_deviceContext, DirectWriteFactory, _swapChain)); + return new DrawingContext(new Media.DrawingContextImpl(_deviceContext, DirectWriteFactory, _swapChain)); } public void Dispose()