Browse Source

Ported changes to DrawingContext from scenegraph

Ported changes to `DrawingContext` and `DrawingContextImpl` from the
`scenegraph` branch.
pull/912/head
Steven Kirk 9 years ago
parent
commit
4e7b743ecd
  1. 2
      src/Avalonia.Visuals/Avalonia.Visuals.csproj
  2. 100
      src/Avalonia.Visuals/Media/DrawingContext.cs
  3. 18
      src/Avalonia.Visuals/Media/IDrawingContextImpl.cs
  4. 5
      src/Avalonia.Visuals/Platform/IFormattedTextImpl.cs
  5. 25
      src/Gtk/Avalonia.Cairo/Media/DrawingContext.cs
  6. 8
      src/Gtk/Avalonia.Cairo/Media/FormattedTextImpl.cs
  7. 22
      src/Skia/Avalonia.Skia/DrawingContextImpl.cs
  8. 29
      src/Skia/Avalonia.Skia/FormattedTextImpl.cs
  9. 2
      src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj
  10. 4
      src/Windows/Avalonia.Direct2D1/Media/AvaloniaTextRenderer.cs
  11. 31
      src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs
  12. 3
      src/Windows/Avalonia.Direct2D1/Media/FormattedTextImpl.cs
  13. 2
      src/Windows/Avalonia.Direct2D1/RenderTarget.cs
  14. 2
      src/Windows/Avalonia.Direct2D1/SwapChainRenderTarget.cs

2
src/Avalonia.Visuals/Avalonia.Visuals.csproj

@ -107,7 +107,7 @@
<Compile Include="Media\FormattedTextLine.cs" />
<Compile Include="Media\FormattedText.cs" />
<Compile Include="Media\Geometry.cs" />
<Compile Include="Media\IDrawingContext.cs" />
<Compile Include="Media\IDrawingContextImpl.cs" />
<Compile Include="Platform\ExportRenderingSubsystemAttribute.cs" />
<Compile Include="Platform\ILockedFramebuffer.cs" />
<Compile Include="Platform\IModuleEnvironmentChecker.cs" />

100
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<Stack<PushedState>> StateStackPool = new Stack<Stack<PushedState>>();
static readonly Stack<Stack<TransformContainer>> TransformStackPool = new Stack<Stack<TransformContainer>>();
@ -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;
/// <summary>
/// Gets the current transform of the drawing context.
/// </summary>
@ -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;
/// <summary>
/// Draws a bitmap image.
@ -72,7 +68,11 @@ namespace Avalonia.Media
/// <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);
{
Contract.Requires<ArgumentNullException>(source != null);
PlatformImpl.DrawImage(source.PlatformImpl, opacity, sourceRect, destRect);
}
/// <summary>
/// Draws a line.
@ -80,7 +80,13 @@ namespace Avalonia.Media
/// <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);
public void DrawLine(Pen pen, Point p1, Point p2)
{
if (PenIsVisible(pen))
{
PlatformImpl.DrawLine(pen, p1, p2);
}
}
/// <summary>
/// Draws a geometry.
@ -88,7 +94,13 @@ namespace Avalonia.Media
/// <param name="brush">The fill brush.</param>
/// <param name="pen">The stroke pen.</param>
/// <param name="geometry">The geometry.</param>
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);
}
}
/// <summary>
/// Draws the outline of a rectangle.
@ -97,7 +109,12 @@ namespace Avalonia.Media
/// <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);
{
if (PenIsVisible(pen))
{
PlatformImpl.DrawRectangle(pen, rect, cornerRadius);
}
}
/// <summary>
/// Draws text.
@ -106,7 +123,14 @@ namespace Avalonia.Media
/// <param name="origin">The upper-left corner of the text.</param>
/// <param name="text">The text.</param>
public void DrawText(IBrush foreground, Point origin, FormattedText text)
=> _impl.DrawText(foreground, origin, text);
{
Contract.Requires<ArgumentNullException>(text != null);
if (foreground != null)
{
PlatformImpl.DrawText(foreground, origin, text.PlatformImpl);
}
}
/// <summary>
/// Draws a filled rectangle.
@ -115,7 +139,12 @@ namespace Avalonia.Media
/// <param name="rect">The rectangle bounds.</param>
/// <param name="cornerRadius">The corner radius.</param>
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
/// <returns>A disposable used to undo the clip rectangle.</returns>
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<ArgumentNullException>(clip != null);
_impl.PushGeometryClip(clip);
PlatformImpl.PushGeometryClip(clip.PlatformImpl);
return new PushedState(this, PushedState.PushedStateType.GeometryClip);
}
@ -201,9 +230,9 @@ namespace Avalonia.Media
/// <param name="opacity">The opacity.</param>
/// <returns>A disposable used to undo the opacity.</returns>
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
/// <returns>A disposable to undo the opacity mask.</returns>
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
/// </summary>
/// <param name="matrix">The matrix</param>
/// <returns>A disposable used to undo the transformation.</returns>
public PushedState PushPostTransform(Matrix matrix) => PushSetTransform(CurrentTransform*matrix);
public PushedState PushPostTransform(Matrix matrix) => PushSetTransform(CurrentTransform * matrix);
/// <summary>
/// Pushes a matrix pre-transformation.
/// </summary>
/// <param name="matrix">The matrix</param>
/// <returns>A disposable used to undo the transformation.</returns>
public PushedState PushPreTransform(Matrix matrix) => PushSetTransform(matrix*CurrentTransform);
public PushedState PushPreTransform(Matrix matrix) => PushSetTransform(matrix * CurrentTransform);
/// <summary>
/// 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;
}
}
}
}

18
src/Avalonia.Visuals/Media/IDrawingContext.cs → 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
/// </summary>
Matrix Transform { get; set; }
/// <summary>
/// Clears the render target to the specified color.
/// </summary>
/// <param name="color">The color.</param>
void Clear(Color color);
/// <summary>
/// Draws a bitmap image.
/// </summary>
@ -23,7 +29,7 @@ namespace Avalonia.Media
/// <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>
void DrawImage(IBitmap source, double opacity, Rect sourceRect, Rect destRect);
void DrawImage(IBitmapImpl source, double opacity, Rect sourceRect, Rect destRect);
/// <summary>
/// Draws a line.
@ -39,7 +45,7 @@ namespace Avalonia.Media
/// <param name="brush">The fill brush.</param>
/// <param name="pen">The stroke pen.</param>
/// <param name="geometry">The geometry.</param>
void DrawGeometry(IBrush brush, Pen pen, Geometry geometry);
void DrawGeometry(IBrush brush, Pen pen, IGeometryImpl geometry);
/// <summary>
/// Draws the outline of a rectangle.
@ -55,7 +61,7 @@ namespace Avalonia.Media
/// <param name="foreground">The foreground brush.</param>
/// <param name="origin">The upper-left corner of the text.</param>
/// <param name="text">The text.</param>
void DrawText(IBrush foreground, Point origin, FormattedText text);
void DrawText(IBrush foreground, Point origin, IFormattedTextImpl text);
/// <summary>
/// Draws a filled rectangle.
@ -89,8 +95,8 @@ namespace Avalonia.Media
/// Pushes a clip geometry.
/// </summary>
/// <param name="clip">The clip geometry.</param>
void PushGeometryClip(Geometry clip);
void PushGeometryClip(IGeometryImpl clip);
void PopGeometryClip();
}
}
}

5
src/Avalonia.Visuals/Platform/IFormattedTextImpl.cs

@ -17,6 +17,11 @@ namespace Avalonia.Platform
/// </summary>
Size Constraint { get; set; }
/// <summary>
/// Gets the text.
/// </summary>
string Text { get; }
/// <summary>
/// Gets the lines in the text.
/// </summary>

25
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;
/// <summary>
@ -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();
}
/// <summary>
/// Ends a draw operation.
/// </summary>
@ -75,9 +80,9 @@ namespace Avalonia.Cairo.Media
/// <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 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
/// <param name="brush">The fill brush.</param>
/// <param name="pen">The stroke pen.</param>
/// <param name="geometry">The geometry.</param>
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
/// <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(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();
}

8
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<ArgumentNullException>(context != null);
Contract.Requires<ArgumentNullException>(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<Rect> HitTestTextRange(int index, int length)

22
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()

29
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<FormattedTextLine> _lines = new List<FormattedTextLine>();
private readonly SKPaint _paint;
private readonly List<Rect> _rects = new List<Rect>();
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<Rect> 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;

2
src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj

@ -65,7 +65,7 @@
<Compile Include="HwndRenderTarget.cs" />
<Compile Include="Media\BrushImpl.cs" />
<Compile Include="Media\BrushWrapper.cs" />
<Compile Include="Media\DrawingContext.cs" />
<Compile Include="Media\DrawingContextImpl.cs" />
<Compile Include="Media\Imaging\BitmapImpl.cs" />
<Compile Include="Media\Imaging\D2DBitmapImpl.cs" />
<Compile Include="Media\Imaging\RenderTargetBitmapImpl.cs" />

4
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)
{

31
src/Windows/Avalonia.Direct2D1/Media/DrawingContext.cs → 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
/// <summary>
/// Draws using Direct2D1.
/// </summary>
public class DrawingContext : IDrawingContextImpl, IDisposable
public class DrawingContextImpl : IDrawingContextImpl, IDisposable
{
/// <summary>
/// The Direct2D1 render target.
@ -30,12 +31,12 @@ namespace Avalonia.Direct2D1.Media
private SharpDX.DXGI.SwapChain1 _swapChain;
/// <summary>
/// Initializes a new instance of the <see cref="DrawingContext"/> class.
/// Initializes a new instance of the <see cref="DrawingContextImpl"/> class.
/// </summary>
/// <param name="renderTarget">The render target to draw to.</param>
/// <param name="directWriteFactory">The DirectWrite factory.</param>
/// <param name="swapChain">An optional swap chain associated with this drawing context.</param>
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(); }
}
/// <inheritdoc/>
public void Clear(Color color)
{
_renderTarget.Clear(color.ToDirect2D());
}
/// <summary>
/// Ends a draw operation.
/// </summary>
@ -81,9 +88,9 @@ namespace Avalonia.Direct2D1.Media
/// <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)
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
/// <param name="brush">The fill brush.</param>
/// <param name="pen">The stroke pen.</param>
/// <param name="geometry">The geometry.</param>
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
/// <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(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);

3
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()

2
src/Windows/Avalonia.Direct2D1/RenderTarget.cs

@ -51,7 +51,7 @@ namespace Avalonia.Direct2D1
/// <returns>An <see cref="Avalonia.Media.DrawingContext"/>.</returns>
public DrawingContext CreateDrawingContext()
{
return new DrawingContext(new Media.DrawingContext(_renderTarget, DirectWriteFactory));
return new DrawingContext(new Media.DrawingContextImpl(_renderTarget, DirectWriteFactory));
}
public void Dispose()

2
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()

Loading…
Cancel
Save