diff --git a/src/Performance/FunctionPointers.cs b/src/Performance/FunctionPointers.cs index b2a3c60d..ce34a9bb 100644 --- a/src/Performance/FunctionPointers.cs +++ b/src/Performance/FunctionPointers.cs @@ -15,14 +15,14 @@ namespace Performance [MemoryDiagnoser] public unsafe class FunctionPointers { - private IUnknown* _punk; + private Unknown* _punk; private string _path; [GlobalSetup] public void GlobalSetup() { _path = Path.Join(Path.GetTempPath(), Path.GetRandomFileName()); - _punk = (IUnknown*)CreateStorage(_path, InterfaceIds.IID_IStorage); + _punk = (Unknown*)CreateStorage(_path, InterfaceIds.IID_IStorage); } [GlobalCleanup] diff --git a/src/Performance/Performance.csproj b/src/Performance/Performance.csproj index 638d88f0..62781c30 100644 --- a/src/Performance/Performance.csproj +++ b/src/Performance/Performance.csproj @@ -7,7 +7,7 @@ - + diff --git a/src/Samples/CoreWindows/Direct2dDemo/CombineGeometries.cs b/src/Samples/CoreWindows/Direct2dDemo/CombineGeometries.cs new file mode 100644 index 00000000..1e2b5de8 --- /dev/null +++ b/src/Samples/CoreWindows/Direct2dDemo/CombineGeometries.cs @@ -0,0 +1,94 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Drawing; +using System.Numerics; +using WInterop.Direct2d; +using WInterop.DirectX; +using WInterop.Windows; + +namespace Direct2dDemo +{ + // https://docs.microsoft.com/windows/win32/direct2d/how-to-combine-geometries + public class CombineGeometries : DirectXWindowClass + { + private readonly EllipseGeometry _circleGeometry1; + private readonly EllipseGeometry _circleGeometry2; + private readonly PathGeometry _geometryUnion; + private readonly PathGeometry _geometryIntersect; + private readonly PathGeometry _geometryXOR; + private readonly PathGeometry _geometryExclude; + private SolidColorBrush _brush; + private SolidColorBrush _strokeBrush; + private SolidColorBrush _fillBrush; + + public CombineGeometries() : base() + { + _circleGeometry1 = Direct2dFactory.CreateEllipseGeometry(new((75.0f, 75.0f), 50.0f, 50.0f)); + _circleGeometry2 = Direct2dFactory.CreateEllipseGeometry(new((125.0f, 75.0f), 50.0f, 50.0f)); + _geometryUnion = Direct2dFactory.CreatePathGeometry(); + using (var sink = _geometryUnion.Open()) + { + _circleGeometry1.CombineWithGeometry(_circleGeometry2, CombineMode.Union, sink); + } + + _geometryIntersect = Direct2dFactory.CreatePathGeometry(); + using (var sink = _geometryIntersect.Open()) + { + _circleGeometry1.CombineWithGeometry(_circleGeometry2, CombineMode.Intersect, sink); + } + + _geometryXOR = Direct2dFactory.CreatePathGeometry(); + using (var sink = _geometryXOR.Open()) + { + _circleGeometry1.CombineWithGeometry(_circleGeometry2, CombineMode.XOr, sink); + } + + _geometryExclude = Direct2dFactory.CreatePathGeometry(); + using (var sink = _geometryExclude.Open()) + { + _circleGeometry1.CombineWithGeometry(_circleGeometry2, CombineMode.Exclude, sink); + } + } + + protected override void CreateResources() + { + _brush = RenderTarget.CreateSolidColorBrush(Color.Black); + _strokeBrush = RenderTarget.CreateSolidColorBrush(Color.Blue); + _fillBrush = RenderTarget.CreateSolidColorBrush(new(Color.CornflowerBlue, 0.5f)); + } + + protected override void OnPaint(WindowHandle window) + { + RenderTarget.Transform = Matrix3x2.Identity; + RenderTarget.Clear(Color.White); + + RenderTarget.Transform = Matrix3x2.CreateTranslation(new(20, 100)); + RenderTarget.FillGeometry(_circleGeometry1, _fillBrush); + RenderTarget.DrawGeometry(_circleGeometry1, _strokeBrush); + RenderTarget.FillGeometry(_circleGeometry2, _fillBrush); + RenderTarget.DrawGeometry(_circleGeometry2, _strokeBrush); + RenderTarget.Transform = Matrix3x2.Identity; + + RenderTarget.Transform = Matrix3x2.CreateTranslation(new(300, 0)); + RenderTarget.FillGeometry(_geometryUnion, _fillBrush); + RenderTarget.DrawGeometry(_geometryUnion, _strokeBrush); + RenderTarget.Transform = Matrix3x2.Identity; + + RenderTarget.Transform = Matrix3x2.CreateTranslation(new(550, 0)); + RenderTarget.FillGeometry(_geometryIntersect, _fillBrush); + RenderTarget.DrawGeometry(_geometryIntersect, _strokeBrush); + RenderTarget.Transform = Matrix3x2.Identity; + + RenderTarget.Transform = Matrix3x2.CreateTranslation(new(300, 200)); + RenderTarget.FillGeometry(_geometryXOR, _fillBrush); + RenderTarget.DrawGeometry(_geometryXOR, _strokeBrush); + RenderTarget.Transform = Matrix3x2.Identity; + + RenderTarget.Transform = Matrix3x2.CreateTranslation(new(550, 200)); + RenderTarget.FillGeometry(_geometryExclude, _fillBrush); + RenderTarget.DrawGeometry(_geometryExclude, _strokeBrush); + RenderTarget.Transform = Matrix3x2.Identity; + } + } +} diff --git a/src/Samples/CoreWindows/Direct2dDemo/Direct2dDemo.cs b/src/Samples/CoreWindows/Direct2dDemo/Direct2dDemo.cs index 11bf326a..1bb470d2 100644 --- a/src/Samples/CoreWindows/Direct2dDemo/Direct2dDemo.cs +++ b/src/Samples/CoreWindows/Direct2dDemo/Direct2dDemo.cs @@ -2,17 +2,21 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.Drawing; +using System.Numerics; using WInterop.Direct2d; using WInterop.DirectX; using WInterop.Windows; namespace Direct2dDemo { - // https://docs.microsoft.com/en-us/windows/desktop/Direct2D/direct2d-quickstart + /// + /// Implementation of the + /// Simple Direct2D Application. + /// public class Direct2dDemo : DirectXWindowClass { - private ISolidColorBrush _lightSlateGrayBrush; - private ISolidColorBrush _cornflowerBlueBrush; + private SolidColorBrush _lightSlateGrayBrush; + private SolidColorBrush _cornflowerBlueBrush; protected override void CreateResources() { @@ -22,16 +26,14 @@ protected override void CreateResources() protected override void OnPaint(WindowHandle window) { - RenderTarget.SetTransform(); + RenderTarget.Transform = Matrix3x2.Identity; RenderTarget.Clear(Color.White); - Size size = RenderTarget.GetSize().ToSize(); - - _lightSlateGrayBrush.GetColor(out ColorF color); + Size size = RenderTarget.Size.ToSize(); for (int x = 0; x < size.Width; x += 10) { RenderTarget.DrawLine( - new Point(x, 0), new Point(x, size.Height), + (x, 0), (x, size.Height), _lightSlateGrayBrush, 0.5f); } diff --git a/src/Samples/CoreWindows/Direct2dDemo/DrawEllipse.cs b/src/Samples/CoreWindows/Direct2dDemo/DrawEllipse.cs index bb1e19a7..8cb2ae7b 100644 --- a/src/Samples/CoreWindows/Direct2dDemo/DrawEllipse.cs +++ b/src/Samples/CoreWindows/Direct2dDemo/DrawEllipse.cs @@ -8,16 +8,19 @@ namespace Direct2dDemo { - // https://docs.microsoft.com/en-us/windows/desktop/Direct2D/how-to-draw-an-ellipse + // https://docs.microsoft.com/windows/desktop/Direct2D/how-to-draw-an-ellipse public class DrawEllipse : DirectXWindowClass { - private ISolidColorBrush _blackBrush; - private ISolidColorBrush _silverBrush; - private readonly IStrokeStyle _dashDotDotStyle; + private SolidColorBrush _blackBrush; + private SolidColorBrush _silverBrush; + private readonly StrokeStyle _dashDotDotStyle; public DrawEllipse() : base() { - StrokeStyleProperties style = new StrokeStyleProperties(dashCap: CapStyle.Triangle, miterLimit: 10.0f, dashStyle: DashStyle.DashDotDot); + StrokeStyleProperties style = new( + dashCap: CapStyle.Triangle, + miterLimit: 10.0f, + dashStyle: DashStyle.DashDotDot); _dashDotDotStyle = Direct2dFactory.CreateStrokeStyle(style); } @@ -31,19 +34,26 @@ protected override void OnPaint(WindowHandle window) { RenderTarget.Clear(Color.White); - Ellipse ellipse = new Ellipse(new PointF(100.0f, 100.0f), 75.0f, 50.0f); + Ellipse ellipse = new((100.0f, 100.0f), 75.0f, 50.0f); RenderTarget.DrawEllipse(ellipse, _blackBrush, 10.0f); - Ellipse ellipse2 = new Ellipse(new PointF(300.0f, 100.0f), 75.0f, 50.0f); + Ellipse ellipse2 = new((300.0f, 100.0f), 75.0f, 50.0f); RenderTarget.DrawEllipse(ellipse2, _blackBrush, 10.0f, _dashDotDotStyle); - Ellipse ellipse3 = new Ellipse(new PointF(500.0f, 100.0f), 75.0f, 50.0f); + Ellipse ellipse3 = new((500.0f, 100.0f), 75.0f, 50.0f); RenderTarget.DrawEllipse(ellipse3, _blackBrush, 10.0f, _dashDotDotStyle); RenderTarget.FillEllipse(ellipse3, _silverBrush); - Ellipse ellipse4 = new Ellipse(new PointF(700.0f, 100.0f), 75.0f, 50.0f); + Ellipse ellipse4 = new((700.0f, 100.0f), 75.0f, 50.0f); RenderTarget.FillEllipse(ellipse4, _silverBrush); RenderTarget.DrawEllipse(ellipse4, _blackBrush, 10.0f, _dashDotDotStyle); } + + protected override void Dispose(bool disposing) + { + _blackBrush.Dispose(); + _silverBrush.Dispose(); + _dashDotDotStyle.Dispose(); + } } } diff --git a/src/Samples/CoreWindows/Direct2dDemo/PathGeometries.cs b/src/Samples/CoreWindows/Direct2dDemo/PathGeometries.cs index 1b329f1f..a1b6fe85 100644 --- a/src/Samples/CoreWindows/Direct2dDemo/PathGeometries.cs +++ b/src/Samples/CoreWindows/Direct2dDemo/PathGeometries.cs @@ -6,20 +6,19 @@ using System.Numerics; using WInterop.Direct2d; using WInterop.DirectX; -using WInterop.Errors; using WInterop.Windows; namespace Direct2dDemo { public class PathGeometries : DirectXWindowClass { - private readonly IPathGeometry _leftMountainGeometry; - private readonly IPathGeometry _rightMountainGeometry; - private readonly IPathGeometry _sunGeometry; - private readonly IPathGeometry _riverGeometry; - private ISolidColorBrush _sceneBrush; - private IBitmapBrush _gridPatternBrush; - private IRadialGradientBrush _radialGradientBrush; + private readonly PathGeometry _leftMountainGeometry; + private readonly PathGeometry _rightMountainGeometry; + private readonly PathGeometry _sunGeometry; + private readonly PathGeometry _riverGeometry; + private SolidColorBrush _sceneBrush; + private BitmapBrush _gridPatternBrush; + private RadialGradientBrush _radialGradientBrush; public PathGeometries() : base() { @@ -27,17 +26,17 @@ public PathGeometries() : base() _leftMountainGeometry = Direct2dFactory.CreatePathGeometry(); var sink = _leftMountainGeometry.Open(); sink.SetFillMode(FillMode.Winding); - sink.BeginFigure(new PointF(346, 255), FigureBegin.Filled); - Span lines = stackalloc PointF[] - { - new PointF(267, 177), - new PointF(236, 192), - new PointF(212, 160), - new PointF(156, 255), - new PointF(346, 255) - }; - - sink.AddLines(lines); + sink.BeginFigure((346, 255), FigureBegin.Filled); + + sink.AddLines( + stackalloc PointF[] + { + new(267, 177), + new(236, 192), + new(212, 160), + new(156, 255), + new(346, 255) + }); sink.EndFigure(FigureEnd.Closed); sink.Close(); @@ -45,19 +44,20 @@ public PathGeometries() : base() _rightMountainGeometry = Direct2dFactory.CreatePathGeometry(); sink = _rightMountainGeometry.Open(); sink.SetFillMode(FillMode.Winding); - sink.BeginFigure(new PointF(575, 263), FigureBegin.Filled); - lines = stackalloc PointF[] - { - new PointF(481, 146), - new PointF(449, 181), - new PointF(433, 159), - new PointF(401, 214), - new PointF(381, 199), - new PointF(323, 263), - new PointF(575, 263) - }; - - sink.AddLines(lines); + sink.BeginFigure((575, 263), FigureBegin.Filled); + + sink.AddLines( + stackalloc PointF[] + { + new(481, 146), + new(449, 181), + new(433, 159), + new(401, 214), + new(381, 199), + new(323, 263), + new(575, 263) + }); + sink.EndFigure(FigureEnd.Closed); sink.Close(); @@ -65,33 +65,33 @@ public PathGeometries() : base() _sunGeometry = Direct2dFactory.CreatePathGeometry(); sink = _sunGeometry.Open(); sink.SetFillMode(FillMode.Winding); - sink.BeginFigure(new PointF(270, 255), FigureBegin.Filled); - sink.AddArc(new ArcSegment(new PointF(440, 255), new SizeF(85, 85))); + sink.BeginFigure((270, 255), FigureBegin.Filled); + sink.AddArc(new((440, 255), (85, 85))); sink.EndFigure(FigureEnd.Closed); - sink.BeginFigure(new PointF(299, 182), FigureBegin.Hollow); - sink.AddBezier((299, 182), (294, 176), (285, 178)); - sink.AddBezier((276, 179), (272, 173), (272, 173)); + sink.BeginFigure((299, 182), FigureBegin.Hollow); + sink.AddBezier(new((299, 182), (294, 176), (285, 178))); + sink.AddBezier(new((276, 179), (272, 173), (272, 173))); sink.EndFigure(FigureEnd.Open); - sink.BeginFigure(new PointF(354, 156), FigureBegin.Hollow); - sink.AddBezier((354, 156), (358, 149), (354, 142)); - sink.AddBezier((349, 134), (354, 127), (354, 127)); + sink.BeginFigure((354, 156), FigureBegin.Hollow); + sink.AddBezier(new((354, 156), (358, 149), (354, 142))); + sink.AddBezier(new((349, 134), (354, 127), (354, 127))); sink.EndFigure(FigureEnd.Open); - sink.BeginFigure(new PointF(322, 164), FigureBegin.Hollow); - sink.AddBezier((322, 164), (322, 156), (314, 152)); - sink.AddBezier((306, 149), (305, 141), (305, 141)); + sink.BeginFigure((322, 164), FigureBegin.Hollow); + sink.AddBezier(new((322, 164), (322, 156), (314, 152))); + sink.AddBezier(new((306, 149), (305, 141), (305, 141))); sink.EndFigure(FigureEnd.Open); - sink.BeginFigure(new PointF(385, 164), FigureBegin.Hollow); - sink.AddBezier((385, 164), (392, 161), (394,152)); - sink.AddBezier((395, 144), (402, 141), (402, 142)); + sink.BeginFigure((385, 164), FigureBegin.Hollow); + sink.AddBezier(new((385, 164), (392, 161), (394, 152))); + sink.AddBezier(new((395, 144), (402, 141), (402, 142))); sink.EndFigure(FigureEnd.Open); - sink.BeginFigure(new PointF(408, 182), FigureBegin.Hollow); - sink.AddBezier((408, 182), (416, 184), (422, 178)); - sink.AddBezier((428, 171), (435, 173), (435, 173)); + sink.BeginFigure((408, 182), FigureBegin.Hollow); + sink.AddBezier(new((408, 182), (416, 184), (422, 178))); + sink.AddBezier(new((428, 171), (435, 173), (435, 173))); sink.EndFigure(FigureEnd.Open); sink.Close(); @@ -100,11 +100,11 @@ public PathGeometries() : base() _riverGeometry = Direct2dFactory.CreatePathGeometry(); sink = _riverGeometry.Open(); sink.SetFillMode(FillMode.Winding); - sink.BeginFigure(new PointF(183, 392), FigureBegin.Filled); - sink.AddBezier((238, 284), (472, 345), (356, 303)); - sink.AddBezier((237, 261), (333, 256), (333, 256)); - sink.AddBezier((335, 257), (241, 261), (411, 306)); - sink.AddBezier((574, 350), (288, 324), (296, 392)); + sink.BeginFigure((183, 392), FigureBegin.Filled); + sink.AddBezier(new((238, 284), (472, 345), (356, 303))); + sink.AddBezier(new((237, 261), (333, 256), (333, 256))); + sink.AddBezier(new((335, 257), (241, 261), (411, 306))); + sink.AddBezier(new((574, 350), (288, 324), (296, 392))); sink.EndFigure(FigureEnd.Open); sink.Close(); } @@ -114,54 +114,55 @@ protected override void CreateResources() _sceneBrush = RenderTarget.CreateSolidColorBrush(Color.Black); // Background grid brush - var bitmapTarget = RenderTarget.CreateCompatibleRenderTarget(new SizeF(10, 10)); - var gridBrush = bitmapTarget.CreateSolidColorBrush(new ColorF(.93f, .94f, .96f)); + var bitmapTarget = RenderTarget.CreateCompatibleRenderTarget((10, 10)); + var gridBrush = bitmapTarget.CreateSolidColorBrush(.93f, .94f, .96f); bitmapTarget.BeginDraw(); - bitmapTarget.FillRectangle(RectangleF.FromLTRB(0, 0, 10, 1), gridBrush); - bitmapTarget.FillRectangle(RectangleF.FromLTRB(0, 0, 1, 10), gridBrush); - bitmapTarget.EndDraw().ThrowIfFailed(); - IBitmap bitmap = bitmapTarget.GetBitmap(); - _gridPatternBrush = RenderTarget.CreateBitmapBrush(bitmap, new BitmapBrushProperties(ExtendMode.Wrap, ExtendMode.Wrap)); + bitmapTarget.FillRectangle((0, 0, 10, 1), gridBrush); + bitmapTarget.FillRectangle((0, 0, 1, 10), gridBrush); + bitmapTarget.EndDraw(); + Bitmap bitmap = bitmapTarget.Bitmap; + _gridPatternBrush = RenderTarget.CreateBitmapBrush(bitmap, new(ExtendMode.Wrap, ExtendMode.Wrap)); // Gradient brush - Span stops = stackalloc[] - { - new GradientStop(0.0f, Color.Gold), - new GradientStop(0.85f, new ColorF(Color.Orange, 0.8f)), - new GradientStop(1.0f, new ColorF(Color.OrangeRed, 0.7f)) - }; + using var gradientStops = RenderTarget.CreateGradientStopCollection( + stackalloc GradientStop[] + { + new(0.0f, Color.Gold), + new(0.85f, new(Color.Orange, 0.8f)), + new(1.0f, new(Color.OrangeRed, 0.7f)) + }); _radialGradientBrush = RenderTarget.CreateRadialGradientBrush( - new RadialGradientBrushProperties(new PointF(330, 330), new PointF(140, 140), 140, 140), - RenderTarget.CreateGradienStopCollection(stops)); + new((330, 330), (140, 140), 140, 140), + gradientStops); } protected override void OnPaint(WindowHandle window) { - SizeF targetSize = RenderTarget.GetSize(); + SizeF targetSize = RenderTarget.Size; - RenderTarget.SetTransform(); + RenderTarget.Transform = Matrix3x2.Identity; RenderTarget.Clear(Color.White); - RenderTarget.FillRectangle(RenderTarget.GetSize(), _gridPatternBrush); - RenderTarget.SetTransform(Matrix3x2.CreateScale(Math.Min(targetSize.Width / 840.0f, targetSize.Height / 700.0f) * 1.4f)); + RenderTarget.FillRectangle(new(RenderTarget.Size), _gridPatternBrush); + RenderTarget.Transform = Matrix3x2.CreateScale(Math.Min(targetSize.Width / 840.0f, targetSize.Height / 700.0f) * 1.4f); RenderTarget.FillGeometry(_sunGeometry, _radialGradientBrush); - _sceneBrush.SetColor(Color.Black); + _sceneBrush.Color = Color.Black; RenderTarget.DrawGeometry(_sunGeometry, _sceneBrush); - _sceneBrush.SetColor(Color.OliveDrab); + _sceneBrush.Color = Color.OliveDrab; RenderTarget.FillGeometry(_leftMountainGeometry, _sceneBrush); - _sceneBrush.SetColor(Color.Black); + _sceneBrush.Color = Color.Black; RenderTarget.DrawGeometry(_leftMountainGeometry, _sceneBrush); - _sceneBrush.SetColor(Color.LightSkyBlue); + _sceneBrush.Color = Color.LightSkyBlue; RenderTarget.FillGeometry(_riverGeometry, _sceneBrush); - _sceneBrush.SetColor(Color.Black); + _sceneBrush.Color = Color.Black; RenderTarget.DrawGeometry(_riverGeometry, _sceneBrush); - _sceneBrush.SetColor(Color.YellowGreen); + _sceneBrush.Color = Color.YellowGreen; RenderTarget.FillGeometry(_rightMountainGeometry, _sceneBrush); - _sceneBrush.SetColor(Color.Black); + _sceneBrush.Color = Color.Black; RenderTarget.DrawGeometry(_rightMountainGeometry, _sceneBrush); } } diff --git a/src/Samples/CoreWindows/Direct2dDemo/Program.cs b/src/Samples/CoreWindows/Direct2dDemo/Program.cs index 5e7c295b..5390cec2 100644 --- a/src/Samples/CoreWindows/Direct2dDemo/Program.cs +++ b/src/Samples/CoreWindows/Direct2dDemo/Program.cs @@ -11,6 +11,7 @@ internal static class Program [STAThread] private static void Main() { + Windows.CreateMainWindowAndRun(new CombineGeometries(), "Combine geometries"); Windows.CreateMainWindowAndRun(new Direct2dDemo(), "Direct2d Sample App"); Windows.CreateMainWindowAndRun(new DrawEllipse(), "Drawing ellipses"); Windows.CreateMainWindowAndRun(new PathGeometries(), "Path geometries"); diff --git a/src/Samples/CoreWindows/DirectWriteDemo/CustomText.cs b/src/Samples/CoreWindows/DirectWriteDemo/CustomText.cs index 52ea69b6..edd9c67c 100644 --- a/src/Samples/CoreWindows/DirectWriteDemo/CustomText.cs +++ b/src/Samples/CoreWindows/DirectWriteDemo/CustomText.cs @@ -11,8 +11,8 @@ namespace DirectWriteDemo // https://docs.microsoft.com/en-us/windows/desktop/DirectWrite/how-to-implement-a-custom-text-renderer public class CustomText : HelloWorld { - private IRadialGradientBrush _radialGradientBrush; - private CustomTextRenderer _textRenderer; + private RadialGradientBrush _radialGradientBrush; + private SampleTextRenderer _textRenderer; protected override void CreateResources() { @@ -28,15 +28,15 @@ protected override void CreateResources() _radialGradientBrush = RenderTarget.CreateRadialGradientBrush( new RadialGradientBrushProperties(new PointF(330, 330), new PointF(140, 140), 140, 140), - RenderTarget.CreateGradienStopCollection(stops)); + RenderTarget.CreateGradientStopCollection(stops)); - _textRenderer = new CustomTextRenderer(Direct2dFactory, RenderTarget, _blackBrush, _radialGradientBrush); + _textRenderer = new SampleTextRenderer(Direct2dFactory, RenderTarget, _blackBrush, _radialGradientBrush); } protected override void OnPaint(WindowHandle window) { RenderTarget.Clear(Color.AntiqueWhite); - _textLayout.Draw(IntPtr.Zero, _textRenderer, 0, 0); + _textLayout.Draw(IntPtr.Zero, _textRenderer, default); } } } diff --git a/src/Samples/CoreWindows/DirectWriteDemo/CustomTextRenderer.cs b/src/Samples/CoreWindows/DirectWriteDemo/CustomTextRenderer.cs deleted file mode 100644 index ba4dc7be..00000000 --- a/src/Samples/CoreWindows/DirectWriteDemo/CustomTextRenderer.cs +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright (c) Jeremy W. Kuhne. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Drawing; -using System.Numerics; -using System.Runtime.InteropServices; -using WInterop; -using WInterop.Direct2d; -using WInterop.DirectWrite; - -namespace DirectWriteDemo -{ - public class CustomTextRenderer : ITextRenderer - { - private readonly IRenderTarget _renderTarget; - private readonly IBrush _outlineBrush; - private readonly IBrush _fillBrush; - private readonly WInterop.Direct2d.IFactory _factory; - - public CustomTextRenderer( - WInterop.Direct2d.IFactory factory, - IRenderTarget renderTarget, - IBrush outlineBrush, - IBrush fillBrush) - { - _renderTarget = renderTarget; - _factory = factory; - _outlineBrush = outlineBrush; - _fillBrush = fillBrush; - } - - public IntBoolean IsPixelSnappingDisabled(IntPtr clientDrawingContext) => false; - - public Matrix3x2 GetCurrentTransform(IntPtr clientDrawingContext) - { - _renderTarget.GetTransform(out Matrix3x2 transform); - return transform; - } - - public float GetPixelsPerDip(IntPtr clientDrawingContext) - { - _renderTarget.GetDpi(out float x, out _); - return x / 96; - } - - public unsafe void DrawGlyphRun( - IntPtr clientDrawingContext, - float baselineOriginX, - float baselineOriginY, - MeasuringMode measuringMode, - in GlyphRun glyphRun, - in GlyphRunDescription glyphRunDescription, - [MarshalAs(UnmanagedType.IUnknown)] object clientDrawingEffect) - { - IPathGeometry geometry = _factory.CreatePathGeometry(); - IGeometrySink sink = geometry.Open(); - glyphRun.FontFace.GetGlyphRunOutline( - glyphRun.FontEmSize, - glyphRun.GlyphIndices, - glyphRun.GlyphAdvances, - glyphRun.GlyphOffsets, - glyphRun.GlyphCount, - glyphRun.IsSideways, - glyphRun.BidiLevel % 2 > 0, - sink); - sink.Close(); - - Matrix3x2 matrix = new Matrix3x2(1, 0, 0, 1, baselineOriginX, baselineOriginY); - ITransformedGeometry transformedGeometry = _factory.CreateTransformedGeometry(geometry, ref matrix); - - _renderTarget.DrawGeometry(transformedGeometry, _outlineBrush); - _renderTarget.FillGeometry(transformedGeometry, _fillBrush); - } - - public void DrawUnderline( - IntPtr clientDrawingContext, - float baselineOriginX, - float baselineOriginY, - in Underline underline, - [MarshalAs(UnmanagedType.IUnknown)] object clientDrawingEffect) - { - IRectangleGeometry geometry = _factory.CreateRectangleGeometry(RectangleF.FromLTRB( - 0, underline.Offset, underline.Width, underline.Offset + underline.Thickness)); - - Matrix3x2 matrix = new Matrix3x2(1, 0, 0, 1, baselineOriginX, baselineOriginY); - ITransformedGeometry transformedGeometry = _factory.CreateTransformedGeometry(geometry, ref matrix); - - _renderTarget.DrawGeometry(transformedGeometry, _outlineBrush); - _renderTarget.FillGeometry(transformedGeometry, _fillBrush); - } - - public void DrawStrikethrough( - IntPtr clientDrawingContext, - float baselineOriginX, - float baselineOriginY, - in Strikethrough strikethrough, - [MarshalAs(UnmanagedType.IUnknown)] object clientDrawingEffect) - { - IRectangleGeometry geometry = _factory.CreateRectangleGeometry(RectangleF.FromLTRB( - 0, strikethrough.Offset, strikethrough.Width, strikethrough.Offset + strikethrough.Thickness)); - - Matrix3x2 matrix = new Matrix3x2(1, 0, 0, 1, baselineOriginX, baselineOriginY); - ITransformedGeometry transformedGeometry = _factory.CreateTransformedGeometry(geometry, ref matrix); - - _renderTarget.DrawGeometry(transformedGeometry, _outlineBrush); - _renderTarget.FillGeometry(transformedGeometry, _fillBrush); - } - - public void DrawInlineObject( - IntPtr clientDrawingContext, - float originX, - float originY, - IInlineObject inlineObject, - IntBoolean isSideways, - IntBoolean isRightToLeft, - [MarshalAs(UnmanagedType.IUnknown)] object clientDrawingEffect) - { - throw new NotImplementedException(); - } - } -} diff --git a/src/Samples/CoreWindows/DirectWriteDemo/HelloWorld.cs b/src/Samples/CoreWindows/DirectWriteDemo/HelloWorld.cs index 3dff7ec9..739e8f59 100644 --- a/src/Samples/CoreWindows/DirectWriteDemo/HelloWorld.cs +++ b/src/Samples/CoreWindows/DirectWriteDemo/HelloWorld.cs @@ -12,24 +12,24 @@ namespace DirectWriteDemo // https://docs.microsoft.com/en-us/windows/desktop/DirectWrite/getting-started-with-directwrite public class HelloWorld : DirectXWindowClass { - protected ITextFormat _textFormat; - protected ITextLayout _textLayout; - protected ITypography _typography; + protected TextFormat _textFormat; + protected TextLayout _textLayout; + protected Typography _typography; - protected ISolidColorBrush _blackBrush; + protected SolidColorBrush _blackBrush; public HelloWorld() : base() { _textFormat = DirectWriteFactory.CreateTextFormat("Gabriola", fontSize: 64); - _textFormat.SetTextAlignment(TextAlignment.Center); - _textFormat.SetParagraphAlignment(ParagraphAlignment.Center); + _textFormat.TextAlignment = TextAlignment.Center; + _textFormat.ParagraphAlignment = ParagraphAlignment.Center; } protected override void CreateResources() { string text = "Hello World From ... DirectWrite!"; _blackBrush = RenderTarget.CreateSolidColorBrush(Color.Black); - _textLayout = DirectWriteFactory.CreateTextLayout(text, _textFormat, RenderTarget.GetSize()); + _textLayout = DirectWriteFactory.CreateTextLayout(text, _textFormat, RenderTarget.Size); // (21, 12) is the range around "DirectWrite!" _textLayout.SetFontSize(100, (21, 12)); diff --git a/src/Samples/CoreWindows/DirectWriteDemo/SampleTextRenderer.cs b/src/Samples/CoreWindows/DirectWriteDemo/SampleTextRenderer.cs new file mode 100644 index 00000000..c479bbb9 --- /dev/null +++ b/src/Samples/CoreWindows/DirectWriteDemo/SampleTextRenderer.cs @@ -0,0 +1,107 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Drawing; +using System.Numerics; +using WInterop.Direct2d; +using WInterop.DirectWrite; + +namespace DirectWriteDemo +{ + public class SampleTextRenderer : ManagedTextRenderer + { + private readonly IRenderTarget _renderTarget; + private readonly Brush _outlineBrush; + private readonly Brush _fillBrush; + private readonly Factory _factory; + + public SampleTextRenderer( + Factory factory, + IRenderTarget renderTarget, + Brush outlineBrush, + Brush fillBrush) + { + _renderTarget = renderTarget; + _factory = factory; + _outlineBrush = outlineBrush; + _fillBrush = fillBrush; + } + + public override Matrix3x2 GetCurrentTransform(IntPtr clientDrawingContext) + => _renderTarget.Transform; + + public override float GetPixelsPerDip(IntPtr clientDrawingContext) + => _renderTarget.Dpi.X / 96; + + public override void DrawGlyphRun( + IntPtr clientDrawingContext, + PointF baselineOrigin, + MeasuringMode measuringMode, + GlyphRun glyphRun, + GlyphRunDescription glyphRunDescription, + IntPtr clientDrawingEffect) + { + using PathGeometry geometry = _factory.CreatePathGeometry(); + using GeometrySink sink = geometry.Open(); + glyphRun.FontFace.GetGlyphRunOutline( + glyphRun.FontEmSize, + glyphRun.GlyphIndices, + glyphRun.GlyphAdvances, + glyphRun.GlyphOffsets, + glyphRun.IsSideways, + glyphRun.BidiLevel % 2 > 0, + sink); + sink.Close(); + + Matrix3x2 matrix = new(1, 0, 0, 1, baselineOrigin.X, baselineOrigin.Y); + using TransformedGeometry transformedGeometry = _factory.CreateTransformedGeometry(geometry, matrix); + + _renderTarget.DrawGeometry(transformedGeometry, _outlineBrush); + _renderTarget.FillGeometry(transformedGeometry, _fillBrush); + } + + public override void DrawUnderline( + IntPtr clientDrawingContext, + PointF baselineOrigin, + Underline underline, + IntPtr clientDrawingEffect) + { + using RectangleGeometry geometry = _factory.CreateRectangleGeometry(RectangleF.FromLTRB( + 0, underline.Offset, underline.Width, underline.Offset + underline.Thickness)); + + Matrix3x2 matrix = new(1, 0, 0, 1, baselineOrigin.X, baselineOrigin.Y); + TransformedGeometry transformedGeometry = _factory.CreateTransformedGeometry(geometry, matrix); + + _renderTarget.DrawGeometry(transformedGeometry, _outlineBrush); + _renderTarget.FillGeometry(transformedGeometry, _fillBrush); + } + + public override void DrawStrikethrough( + IntPtr clientDrawingContext, + PointF baselineOrigin, + Strikethrough strikethrough, + IntPtr clientDrawingEffect) + { + using RectangleGeometry geometry = _factory.CreateRectangleGeometry(RectangleF.FromLTRB( + 0, strikethrough.Offset, strikethrough.Width, strikethrough.Offset + strikethrough.Thickness)); + + Matrix3x2 matrix = new(1, 0, 0, 1, baselineOrigin.X, baselineOrigin.Y); + TransformedGeometry transformedGeometry = _factory.CreateTransformedGeometry(geometry, matrix); + + _renderTarget.DrawGeometry(transformedGeometry, _outlineBrush); + _renderTarget.FillGeometry(transformedGeometry, _fillBrush); + } + + public override void DrawInlineObject( + IntPtr clientDrawingContext, + PointF origin, + InlineObject inlineObject, + bool isSideways, + bool isRightToLeft, + IntPtr clientDrawingEffect) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Tests/WInterop.Tests/Direct2d/Factory.cs b/src/Tests/WInterop.Tests/Direct2d/Factory.cs deleted file mode 100644 index 1d644b37..00000000 --- a/src/Tests/WInterop.Tests/Direct2d/Factory.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) Jeremy W. Kuhne. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Drawing; -using WInterop.Direct2d; -using WInterop.Direct2d.Native; -using WInterop.Errors; -using Xunit; - -namespace Direct2dTests -{ - public class Factory - { - [Fact] - public void Initialize() - { - HResult result = Imports.D2D1CreateFactory( - FactoryType.SingleThreaded, new Guid(InterfaceIds.IID_ID2D1Factory), DebugLevel.None, out IFactory factory); - - Ellipse ellipse = new Ellipse(new PointF(1.0f, 2.0f), 3.0f, 4.0f); - var ellipseGeometry = factory.CreateEllipseGeometry(in ellipse); - ellipseGeometry.GetEllipse(out Ellipse newEllipse); - } - - [Fact] - public void GetDpi() - { - IFactory factory = Direct2d.CreateFactory(); - - factory.GetDesktopDpi(out float x, out float y); - } - } -} diff --git a/src/Tests/WInterop.Tests/Direct2d/FactoryTests.cs b/src/Tests/WInterop.Tests/Direct2d/FactoryTests.cs new file mode 100644 index 00000000..fb880c2a --- /dev/null +++ b/src/Tests/WInterop.Tests/Direct2d/FactoryTests.cs @@ -0,0 +1,30 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using FluentAssertions; +using System.Drawing; +using WInterop.Direct2d; +using Xunit; + +namespace Direct2dTests +{ + public class FactoryTests + { + [Fact] + public void Initialize() + { + using Factory factory = Direct2d.CreateFactory(); + + Ellipse ellipse = new(new PointF(1.0f, 2.0f), 3.0f, 4.0f); + using EllipseGeometry ellipseGeometry = factory.CreateEllipseGeometry(ellipse); + ellipseGeometry.GetEllipse().Should().Be(ellipse); + } + + [Fact] + public void GetDpi() + { + using Factory factory = Direct2d.CreateFactory(); + SizeF dpi = factory.GetDesktopDpi(); + } + } +} diff --git a/src/Tests/WInterop.Tests/Direct2d/RenderTarget.cs b/src/Tests/WInterop.Tests/Direct2d/RenderTarget.cs index 3eae6f2f..73bbcc20 100644 --- a/src/Tests/WInterop.Tests/Direct2d/RenderTarget.cs +++ b/src/Tests/WInterop.Tests/Direct2d/RenderTarget.cs @@ -12,205 +12,205 @@ namespace Direct2dTests { - public class RenderTarget : IClassFixture - { - private readonly RenderTargetFixture _fixture; - public RenderTarget(RenderTargetFixture fixture) - { - _fixture = fixture; - } - - public class RenderTargetFixture : IDisposable - { - private readonly IFactory _factory; - // private DeviceContext _dc; - private readonly WindowHandle _window; - private readonly WindowClass _windowClass; - - public RenderTargetFixture() - { - _factory = Direct2d.CreateFactory(FactoryType.SingleThreaded, DebugLevel.None); - - // Create a memory only copy of the primary monitor DC - // _dc = Gdi.CreateCompatibleDeviceContext(Gdi.GetDeviceContext()); - - _windowClass = new WindowClass(backgroundBrush: BrushHandle.NoBrush); - _windowClass.Register(); - _window = _windowClass.CreateWindow(Windows.DefaultBounds, "RenderTargetTest"); - RenderTarget = _factory.CreateWindowRenderTarget(default, - new WindowRenderTargetProperties(_window, _window.GetClientRectangle().Size)); - } - - public void Dispose() - { - // Nothing - } - - public IRenderTarget RenderTarget { get; private set; } - } - - [Fact] - public void GetFactory() - { - _fixture.RenderTarget.GetFactory(out IFactory factory); - factory.Should().NotBeNull(); - } - - [Fact] - public void CreateBitmap() - { - IBitmap bitmap = _fixture.RenderTarget.CreateBitmap(new Size(100, 100), - new BitmapProperties(new PixelFormat(WInterop.Dxgi.Format.DXGI_FORMAT_R32G32B32A32_FLOAT, AlphaMode.Ignore), 72, 72)); - - bitmap.Should().NotBeNull(); - } - - [Fact] - public unsafe void CreateBitmapBrush() - { - IBitmap bitmap = _fixture.RenderTarget.CreateBitmap(new Size(10, 10), - new BitmapProperties(new PixelFormat(WInterop.Dxgi.Format.DXGI_FORMAT_R32G32B32A32_FLOAT, AlphaMode.Ignore), 72, 72)); - - IBitmapBrush brush = _fixture.RenderTarget.CreateBitmapBrush(bitmap, null, null); - brush.Should().NotBeNull(); - } - - [Fact] - public unsafe void CreateSolidColorBrush() - { - ISolidColorBrush brush = _fixture.RenderTarget.CreateSolidColorBrush(Color.Bisque); - brush.Should().NotBeNull(); - brush.GetColor(out ColorF color); - ((Color)color).ToArgb().Should().Be(Color.Bisque.ToArgb()); - } - - [Fact] - public unsafe void DrawLine() - { - ISolidColorBrush brush = _fixture.RenderTarget.CreateSolidColorBrush(Color.Maroon); - _fixture.RenderTarget.BeginDraw(); - _fixture.RenderTarget.DrawLine(default, new Point(10, 10), brush); - _fixture.RenderTarget.EndDraw(out _, out _); - } - - [Fact] - public unsafe void DrawRectangle() - { - ISolidColorBrush brush = _fixture.RenderTarget.CreateSolidColorBrush(Color.Gold); - _fixture.RenderTarget.BeginDraw(); - _fixture.RenderTarget.DrawRectangle(new Rectangle(0, 0, 10, 10), brush); - _fixture.RenderTarget.EndDraw(out _, out _); - } - - [Fact] - public unsafe void FillRectangle() - { - ISolidColorBrush brush = _fixture.RenderTarget.CreateSolidColorBrush(Color.Blue); - _fixture.RenderTarget.BeginDraw(); - _fixture.RenderTarget.FillRectangle(new Rectangle(0, 0, 10, 10), brush); - _fixture.RenderTarget.EndDraw(out _, out _); - } - - [Fact] - public unsafe void DrawRoundedRectangle() - { - ISolidColorBrush brush = _fixture.RenderTarget.CreateSolidColorBrush(Color.White); - _fixture.RenderTarget.BeginDraw(); - _fixture.RenderTarget.DrawRoundedRectangle(new RoundedRectangle(new Rectangle(0, 0, 10, 10), 3, 3), brush); - _fixture.RenderTarget.EndDraw(out _, out _); - } - - [Fact] - public unsafe void FillRoundedRectangle() - { - ISolidColorBrush brush = _fixture.RenderTarget.CreateSolidColorBrush(Color.BurlyWood); - _fixture.RenderTarget.BeginDraw(); - _fixture.RenderTarget.FillRoundedRectangle(new RoundedRectangle(new Rectangle(0, 0, 10, 10), 3, 3), brush); - _fixture.RenderTarget.EndDraw(out _, out _); - } - - [Fact] - public unsafe void DrawEllipse() - { - ISolidColorBrush brush = _fixture.RenderTarget.CreateSolidColorBrush(Color.Chocolate); - _fixture.RenderTarget.BeginDraw(); - _fixture.RenderTarget.DrawEllipse(new Ellipse(new Point(5,5), 6, 7), brush); - _fixture.RenderTarget.EndDraw(out _, out _); - } - - [Fact] - public unsafe void FillEllipse() - { - ISolidColorBrush brush = _fixture.RenderTarget.CreateSolidColorBrush(Color.Honeydew); - _fixture.RenderTarget.BeginDraw(); - _fixture.RenderTarget.FillEllipse(new Ellipse(new Point(5, 5), 6, 7), brush); - _fixture.RenderTarget.EndDraw(out _, out _); - } - - [Fact] - public unsafe void Tags() - { - _fixture.RenderTarget.SetTags(2001, 2010); - _fixture.RenderTarget.GetTags(out ulong tag1, out ulong tag2); - tag1.Should().Be(2001); - tag2.Should().Be(2010); - _fixture.RenderTarget.BeginDraw(); - _fixture.RenderTarget.EndDraw(out tag2, out tag1); - - // These are 0 if there are no errors, a value will tell you the tag state when - // a drawing operation failed. - tag2.Should().Be(0); - tag1.Should().Be(0); - } - - [Fact] - public unsafe void Dpi() - { - _fixture.RenderTarget.SetDpi(72.0f, 72.0f); - _fixture.RenderTarget.GetDpi(out float dpiX, out float dpiY); - dpiX.Should().Be(72.0f); - dpiY.Should().Be(72.0f); - } - - [Fact] - public void GetSize() - { - _fixture.RenderTarget.GetSize(out SizeF size); - size.Width.Should().BeGreaterThan(0); - } - - [Fact] - public void GetPixelSize() - { - _fixture.RenderTarget.GetPixelSize(out SizeU size); - size.Width.Should().BeGreaterThan(0); - } - - [Fact] - public void GetPixelFormat() - { - _fixture.RenderTarget.GetPixelFormat(out PixelFormat pixelFormat); - // BGRA - pixelFormat.Format.Should().Be(WInterop.Dxgi.Format.DXGI_FORMAT_B8G8R8A8_UNORM); - } - - [Fact] - public void AntialiasModes() - { - AntialiasMode existing = _fixture.RenderTarget.GetAntialiasMode(); - _fixture.RenderTarget.SetAntialiasMode(AntialiasMode.Aliased); - _fixture.RenderTarget.GetAntialiasMode().Should().Be(AntialiasMode.Aliased); - _fixture.RenderTarget.SetAntialiasMode(existing); - } - - [Fact] - public void Transforms() - { - _fixture.RenderTarget.GetTransform(out Matrix3x2 transform); - _fixture.RenderTarget.SetTransform(); - _fixture.RenderTarget.GetTransform(out Matrix3x2 newTransform); - newTransform.IsIdentity.Should().BeTrue(); - _fixture.RenderTarget.SetTransform(ref transform); - } - } + //public class RenderTarget : IClassFixture + //{ + // private readonly RenderTargetFixture _fixture; + // public RenderTarget(RenderTargetFixture fixture) + // { + // _fixture = fixture; + // } + + // public class RenderTargetFixture : IDisposable + // { + // private readonly IFactory _factory; + // // private DeviceContext _dc; + // private readonly WindowHandle _window; + // private readonly WindowClass _windowClass; + + // public RenderTargetFixture() + // { + // _factory = Direct2d.CreateFactory(FactoryType.SingleThreaded, DebugLevel.None); + + // // Create a memory only copy of the primary monitor DC + // // _dc = Gdi.CreateCompatibleDeviceContext(Gdi.GetDeviceContext()); + + // _windowClass = new WindowClass(backgroundBrush: BrushHandle.NoBrush); + // _windowClass.Register(); + // _window = _windowClass.CreateWindow(Windows.DefaultBounds, "RenderTargetTest"); + // RenderTarget = _factory.CreateWindowRenderTarget(default, + // new WindowRenderTargetProperties(_window, _window.GetClientRectangle().Size)); + // } + + // public void Dispose() + // { + // // Nothing + // } + + // public IRenderTarget RenderTarget { get; private set; } + // } + + // [Fact] + // public void GetFactory() + // { + // _fixture.RenderTarget.GetFactory(out IFactory factory); + // factory.Should().NotBeNull(); + // } + + // [Fact] + // public void CreateBitmap() + // { + // IBitmap bitmap = _fixture.RenderTarget.CreateBitmap(new Size(100, 100), + // new BitmapProperties(new PixelFormat(WInterop.Dxgi.Format.DXGI_FORMAT_R32G32B32A32_FLOAT, AlphaMode.Ignore), 72, 72)); + + // bitmap.Should().NotBeNull(); + // } + + // [Fact] + // public unsafe void CreateBitmapBrush() + // { + // IBitmap bitmap = _fixture.RenderTarget.CreateBitmap(new Size(10, 10), + // new BitmapProperties(new PixelFormat(WInterop.Dxgi.Format.DXGI_FORMAT_R32G32B32A32_FLOAT, AlphaMode.Ignore), 72, 72)); + + // IBitmapBrush brush = _fixture.RenderTarget.CreateBitmapBrush(bitmap, null, null); + // brush.Should().NotBeNull(); + // } + + // [Fact] + // public unsafe void CreateSolidColorBrush() + // { + // ISolidColorBrush brush = _fixture.RenderTarget.CreateSolidColorBrush(Color.Bisque); + // brush.Should().NotBeNull(); + // brush.GetColor(out ColorF color); + // ((Color)color).ToArgb().Should().Be(Color.Bisque.ToArgb()); + // } + + // [Fact] + // public unsafe void DrawLine() + // { + // ISolidColorBrush brush = _fixture.RenderTarget.CreateSolidColorBrush(Color.Maroon); + // _fixture.RenderTarget.BeginDraw(); + // _fixture.RenderTarget.DrawLine(default, new Point(10, 10), brush); + // _fixture.RenderTarget.EndDraw(out _, out _); + // } + + // [Fact] + // public unsafe void DrawRectangle() + // { + // ISolidColorBrush brush = _fixture.RenderTarget.CreateSolidColorBrush(Color.Gold); + // _fixture.RenderTarget.BeginDraw(); + // _fixture.RenderTarget.DrawRectangle(new Rectangle(0, 0, 10, 10), brush); + // _fixture.RenderTarget.EndDraw(out _, out _); + // } + + // [Fact] + // public unsafe void FillRectangle() + // { + // ISolidColorBrush brush = _fixture.RenderTarget.CreateSolidColorBrush(Color.Blue); + // _fixture.RenderTarget.BeginDraw(); + // _fixture.RenderTarget.FillRectangle(new Rectangle(0, 0, 10, 10), brush); + // _fixture.RenderTarget.EndDraw(out _, out _); + // } + + // [Fact] + // public unsafe void DrawRoundedRectangle() + // { + // ISolidColorBrush brush = _fixture.RenderTarget.CreateSolidColorBrush(Color.White); + // _fixture.RenderTarget.BeginDraw(); + // _fixture.RenderTarget.DrawRoundedRectangle(new RoundedRectangle(new Rectangle(0, 0, 10, 10), 3, 3), brush); + // _fixture.RenderTarget.EndDraw(out _, out _); + // } + + // [Fact] + // public unsafe void FillRoundedRectangle() + // { + // ISolidColorBrush brush = _fixture.RenderTarget.CreateSolidColorBrush(Color.BurlyWood); + // _fixture.RenderTarget.BeginDraw(); + // _fixture.RenderTarget.FillRoundedRectangle(new RoundedRectangle(new Rectangle(0, 0, 10, 10), 3, 3), brush); + // _fixture.RenderTarget.EndDraw(out _, out _); + // } + + // [Fact] + // public unsafe void DrawEllipse() + // { + // ISolidColorBrush brush = _fixture.RenderTarget.CreateSolidColorBrush(Color.Chocolate); + // _fixture.RenderTarget.BeginDraw(); + // _fixture.RenderTarget.DrawEllipse(new Ellipse(new Point(5,5), 6, 7), brush); + // _fixture.RenderTarget.EndDraw(out _, out _); + // } + + // [Fact] + // public unsafe void FillEllipse() + // { + // ISolidColorBrush brush = _fixture.RenderTarget.CreateSolidColorBrush(Color.Honeydew); + // _fixture.RenderTarget.BeginDraw(); + // _fixture.RenderTarget.FillEllipse(new Ellipse(new Point(5, 5), 6, 7), brush); + // _fixture.RenderTarget.EndDraw(out _, out _); + // } + + // [Fact] + // public unsafe void Tags() + // { + // _fixture.RenderTarget.SetTags(2001, 2010); + // _fixture.RenderTarget.GetTags(out ulong tag1, out ulong tag2); + // tag1.Should().Be(2001); + // tag2.Should().Be(2010); + // _fixture.RenderTarget.BeginDraw(); + // _fixture.RenderTarget.EndDraw(out tag2, out tag1); + + // // These are 0 if there are no errors, a value will tell you the tag state when + // // a drawing operation failed. + // tag2.Should().Be(0); + // tag1.Should().Be(0); + // } + + // [Fact] + // public unsafe void Dpi() + // { + // _fixture.RenderTarget.SetDpi(72.0f, 72.0f); + // _fixture.RenderTarget.GetDpi(out float dpiX, out float dpiY); + // dpiX.Should().Be(72.0f); + // dpiY.Should().Be(72.0f); + // } + + // [Fact] + // public void GetSize() + // { + // _fixture.RenderTarget.GetSize(out SizeF size); + // size.Width.Should().BeGreaterThan(0); + // } + + // [Fact] + // public void GetPixelSize() + // { + // _fixture.RenderTarget.GetPixelSize(out SizeU size); + // size.Width.Should().BeGreaterThan(0); + // } + + // [Fact] + // public void GetPixelFormat() + // { + // _fixture.RenderTarget.GetPixelFormat(out PixelFormat pixelFormat); + // // BGRA + // pixelFormat.Format.Should().Be(WInterop.Dxgi.Format.DXGI_FORMAT_B8G8R8A8_UNORM); + // } + + // [Fact] + // public void AntialiasModes() + // { + // AntialiasMode existing = _fixture.RenderTarget.GetAntialiasMode(); + // _fixture.RenderTarget.SetAntialiasMode(AntialiasMode.Aliased); + // _fixture.RenderTarget.GetAntialiasMode().Should().Be(AntialiasMode.Aliased); + // _fixture.RenderTarget.SetAntialiasMode(existing); + // } + + // [Fact] + // public void Transforms() + // { + // _fixture.RenderTarget.GetTransform(out Matrix3x2 transform); + // _fixture.RenderTarget.SetTransform(); + // _fixture.RenderTarget.GetTransform(out Matrix3x2 newTransform); + // newTransform.IsIdentity.Should().BeTrue(); + // _fixture.RenderTarget.SetTransform(ref transform); + // } + //} } diff --git a/src/WInterop.Desktop/Com/Native/IDataObject.cs b/src/WInterop.Desktop/Com/Native/IDataObject.cs index 8b59b997..526ed3e8 100644 --- a/src/WInterop.Desktop/Com/Native/IDataObject.cs +++ b/src/WInterop.Desktop/Com/Native/IDataObject.cs @@ -96,15 +96,15 @@ private static unsafe HResult QueryInterface(void* @this, Guid* iid, void* ppObj return HResult.E_NOINTERFACE; } - Lifetime.AddRef(@this); + Lifetime.AddRef(@this); return HResult.S_OK; } [UnmanagedCallersOnly] - private static unsafe uint AddRef(void* @this) => Lifetime.AddRef(@this); + private static unsafe uint AddRef(void* @this) => Lifetime.AddRef(@this); [UnmanagedCallersOnly] - private static unsafe uint Release(void* @this) => Lifetime.Release(@this); + private static unsafe uint Release(void* @this) => Lifetime.Release(@this); [UnmanagedCallersOnly] #pragma warning disable IDE0060 // Remove unused parameter diff --git a/src/WInterop.Desktop/Com/Native/IDropSource.CCW.cs b/src/WInterop.Desktop/Com/Native/IDropSource.CCW.cs index ebc561f6..9d4479cf 100644 --- a/src/WInterop.Desktop/Com/Native/IDropSource.CCW.cs +++ b/src/WInterop.Desktop/Com/Native/IDropSource.CCW.cs @@ -29,7 +29,7 @@ public static class CCW } public static unsafe IntPtr CreateInstance(Managed.IDropSource @object) - => (IntPtr)Lifetime.Allocate(@object, CCWVTable); + => (IntPtr)Lifetime.Allocate(@object, CCWVTable); [UnmanagedCallersOnly] private static unsafe HResult QueryInterface(void* @this, Guid* iid, void* ppObject) @@ -44,20 +44,20 @@ private static unsafe HResult QueryInterface(void* @this, Guid* iid, void* ppObj return HResult.E_NOINTERFACE; } - Lifetime.AddRef(@this); + Lifetime.AddRef(@this); return HResult.S_OK; } [UnmanagedCallersOnly] - private static unsafe uint AddRef(void* @this) => Lifetime.AddRef(@this); + private static unsafe uint AddRef(void* @this) => Lifetime.AddRef(@this); [UnmanagedCallersOnly] - private static unsafe uint Release(void* @this) => Lifetime.Release(@this); + private static unsafe uint Release(void* @this) => Lifetime.Release(@this); [UnmanagedCallersOnly] private static unsafe HResult QueryContinueDrag(void* @this, int fEscapePressed, KeyState grfKeyState) { - var lifetime = (Lifetime*)@this; + var lifetime = (Lifetime*)@this; var dropSource = GCHandle.FromIntPtr((IntPtr)lifetime->Handle).Target as Managed.IDropSource; return dropSource?.QueryContinueDrag(fEscapePressed.FromBOOL(), grfKeyState) ?? HResult.E_FAIL; } @@ -65,7 +65,7 @@ private static unsafe HResult QueryContinueDrag(void* @this, int fEscapePressed, [UnmanagedCallersOnly] private static unsafe HResult GiveFeedback(void* @this, DropEffect dwEffect) { - var lifetime = (Lifetime*)@this; + var lifetime = (Lifetime*)@this; var dropSource = GCHandle.FromIntPtr((IntPtr)lifetime->Handle).Target as Managed.IDropSource; return dropSource?.GiveFeedback(dwEffect) ?? HResult.E_FAIL; } diff --git a/src/WInterop.Desktop/Com/Native/IUnknown.CCW.cs b/src/WInterop.Desktop/Com/Native/IUnknown.CCW.cs index 1022624a..169710c4 100644 --- a/src/WInterop.Desktop/Com/Native/IUnknown.CCW.cs +++ b/src/WInterop.Desktop/Com/Native/IUnknown.CCW.cs @@ -27,7 +27,7 @@ public static class CCW } public static unsafe IntPtr CreateInstance(object @object) - => (IntPtr)Lifetime.Allocate(@object, CCWVTable); + => (IntPtr)Lifetime.Allocate(@object, CCWVTable); [UnmanagedCallersOnly] private static unsafe HResult QueryInterface(void* @this, Guid* iid, void* ppObject) @@ -42,15 +42,15 @@ private static unsafe HResult QueryInterface(void* @this, Guid* iid, void* ppObj return HResult.E_NOINTERFACE; } - Lifetime.AddRef(@this); + Lifetime.AddRef(@this); return HResult.S_OK; } [UnmanagedCallersOnly] - private static unsafe uint AddRef(void* @this) => Lifetime.AddRef(@this); + private static unsafe uint AddRef(void* @this) => Lifetime.AddRef(@this); [UnmanagedCallersOnly] - private static unsafe uint Release(void* @this) => Lifetime.Release(@this); + private static unsafe uint Release(void* @this) => Lifetime.Release(@this); } } } \ No newline at end of file diff --git a/src/WInterop.Desktop/Com/Native/Lifetime.cs b/src/WInterop.Desktop/Com/Native/Lifetime.cs index 7fa67efd..ef6b0861 100644 --- a/src/WInterop.Desktop/Com/Native/Lifetime.cs +++ b/src/WInterop.Desktop/Com/Native/Lifetime.cs @@ -9,18 +9,18 @@ namespace WInterop.Com.Native { - public unsafe struct Lifetime where TVTable : unmanaged + public unsafe struct Lifetime where TVTable : unmanaged { public TVTable* VTable; public void* Handle; public uint RefCount; public static unsafe uint AddRef(void* @this) - => Interlocked.Increment(ref ((Lifetime*)@this)->RefCount); + => Interlocked.Increment(ref ((Lifetime*)@this)->RefCount); public static unsafe uint Release(void* @this) { - var lifetime = (Lifetime*)@this; + var lifetime = (Lifetime*)@this; Debug.Assert(lifetime->RefCount > 0); uint count = Interlocked.Decrement(ref lifetime->RefCount); if (count == 0) @@ -32,9 +32,23 @@ public static unsafe uint Release(void* @this) return count; } - public static unsafe Lifetime* Allocate(object @object, TVTable* vtable) + /// + /// Allocate a lifetime wrapper for the given with the given + /// . + /// + /// + /// + /// This creates a to root the until ref + /// counting has gone to zero. + /// + /// + /// The should be fixed, typically as a static. Com calls always + /// include the "this" pointer as the first argument. + /// + /// + public static unsafe Lifetime* Allocate(TObject @object, TVTable* vtable) { - var wrapper = (Lifetime*)CoTaskAllocate((nuint)sizeof(Lifetime)); + var wrapper = (Lifetime*)CoTaskAllocate((nuint)sizeof(Lifetime)); // Create the wrapper instance. wrapper->VTable = vtable; @@ -43,5 +57,11 @@ public static unsafe uint Release(void* @this) return wrapper; } + + public static TObject? GetObject(void* @this) + { + var lifetime = (Lifetime*)@this; + return (TObject?)GCHandle.FromIntPtr((IntPtr)lifetime->Handle).Target; + } } } \ No newline at end of file diff --git a/src/WInterop.Desktop/Windows/Classes/WindowClass.cs b/src/WInterop.Desktop/Windows/Classes/WindowClass.cs index 81542218..26bce03d 100644 --- a/src/WInterop.Desktop/Windows/Classes/WindowClass.cs +++ b/src/WInterop.Desktop/Windows/Classes/WindowClass.cs @@ -11,13 +11,14 @@ namespace WInterop.Windows { - public class WindowClass + public class WindowClass : IDisposable { // Stash the delegate to keep it from being collected private readonly WindowProcedure _windowProcedure; private WNDCLASSEX _wndClass; private readonly string _className; private readonly string _menuName; + private bool _disposedValue; public Atom Atom { get; private set; } public WindowHandle MainWindow { get; private set; } @@ -190,5 +191,28 @@ protected virtual LResult WindowProcedure(WindowHandle window, MessageType messa return Windows.DefaultWindowProcedure(window, message, wParam, lParam); } + + protected virtual void Dispose(bool disposing) + { + } + + ~WindowClass() + { + if (!_disposedValue) + { + _disposedValue = true; + Dispose(disposing: false); + } + } + + public void Dispose() + { + GC.SuppressFinalize(this); + if (!_disposedValue) + { + _disposedValue = true; + Dispose(disposing: true); + } + } } } \ No newline at end of file diff --git a/src/WInterop.DirectX/Direct2d/AlphaMode.cs b/src/WInterop.DirectX/Direct2d/AlphaMode.cs index 112c6d3c..49695d8a 100644 --- a/src/WInterop.DirectX/Direct2d/AlphaMode.cs +++ b/src/WInterop.DirectX/Direct2d/AlphaMode.cs @@ -14,21 +14,21 @@ public enum AlphaMode : uint /// or imply this information in which case alpha must be specified. /// [D2D1_ALPHA_MODE_UNKNOWN] /// - Unknown = 0, + Unknown = D2D1_ALPHA_MODE.D2D1_ALPHA_MODE_UNKNOWN, /// /// Treat the alpha as premultipled. [D2D1_ALPHA_MODE_PREMULTIPLIED] /// - Premultiplied = 1, + Premultiplied = D2D1_ALPHA_MODE.D2D1_ALPHA_MODE_PREMULTIPLIED, /// /// Opacity is in the 'A' component only. [D2D1_ALPHA_MODE_STRAIGHT] /// - Straight = 2, + Straight = D2D1_ALPHA_MODE.D2D1_ALPHA_MODE_STRAIGHT, /// /// Ignore any alpha channel information. [D2D1_ALPHA_MODE_IGNORE] /// - Ignore = 3, + Ignore = D2D1_ALPHA_MODE.D2D1_ALPHA_MODE_IGNORE, } } diff --git a/src/WInterop.DirectX/Direct2d/AntialiasMode.cs b/src/WInterop.DirectX/Direct2d/AntialiasMode.cs index c1a64721..fd8b0432 100644 --- a/src/WInterop.DirectX/Direct2d/AntialiasMode.cs +++ b/src/WInterop.DirectX/Direct2d/AntialiasMode.cs @@ -11,11 +11,11 @@ public enum AntialiasMode : uint /// /// The edges of each primitive are antialiased sequentially. [D2D1_ANTIALIAS_MODE_PER_PRIMITIVE] /// - PerPrimitive = 0, + PerPrimitive = D2D1_ANTIALIAS_MODE.D2D1_ANTIALIAS_MODE_PER_PRIMITIVE, /// /// Each pixel is rendered if its pixel center is contained by the geometry. [D2D1_ANTIALIAS_MODE_ALIASED] /// - Aliased = 1 + Aliased = D2D1_ANTIALIAS_MODE.D2D1_ANTIALIAS_MODE_ALIASED } } diff --git a/src/WInterop.DirectX/Direct2d/ArcSegment.cs b/src/WInterop.DirectX/Direct2d/ArcSegment.cs index 3ca3c52e..e867ea86 100644 --- a/src/WInterop.DirectX/Direct2d/ArcSegment.cs +++ b/src/WInterop.DirectX/Direct2d/ArcSegment.cs @@ -10,11 +10,11 @@ namespace WInterop.Direct2d /// public readonly struct ArcSegment { - public readonly PointF Point; - public readonly SizeF Size; - public readonly float RotationAngle; - public readonly SweepDirection SweepDirection; - public readonly ArcSize ArcSize; + public PointF Point { get; } + public SizeF Size { get; } + public float RotationAngle { get; } + public SweepDirection SweepDirection { get; } + public ArcSize ArcSize { get; } public ArcSegment( PointF point, @@ -29,5 +29,19 @@ public ArcSegment( SweepDirection = sweepDirection; ArcSize = arcSize; } + + public ArcSegment( + (float X, float Y) point, + (float X, float Y) size, + float rotationAngle = 0.0f, + SweepDirection sweepDirection = SweepDirection.Clockwise, + ArcSize arcSize = ArcSize.Small) + { + Point = new(point.X, point.Y); + Size = new(size.X, size.Y); + RotationAngle = rotationAngle; + SweepDirection = sweepDirection; + ArcSize = arcSize; + } } } diff --git a/src/WInterop.DirectX/Direct2d/ArcSize.cs b/src/WInterop.DirectX/Direct2d/ArcSize.cs index 6727dfb3..b8348c6f 100644 --- a/src/WInterop.DirectX/Direct2d/ArcSize.cs +++ b/src/WInterop.DirectX/Direct2d/ArcSize.cs @@ -12,11 +12,11 @@ public enum ArcSize : uint /// /// [D2D1_ARC_SIZE_SMALL] /// - Small = 0, + Small = D2D1_ARC_SIZE.D2D1_ARC_SIZE_SMALL, /// /// [D2D1_ARC_SIZE_LARGE] /// - Large = 1, + Large = D2D1_ARC_SIZE.D2D1_ARC_SIZE_LARGE, } } diff --git a/src/WInterop.DirectX/Direct2d/BezierSegment.cs b/src/WInterop.DirectX/Direct2d/BezierSegment.cs index d88f9ffc..1b47ed1b 100644 --- a/src/WInterop.DirectX/Direct2d/BezierSegment.cs +++ b/src/WInterop.DirectX/Direct2d/BezierSegment.cs @@ -10,9 +10,9 @@ namespace WInterop.Direct2d /// public readonly struct BezierSegment { - public readonly PointF Point1; - public readonly PointF Point2; - public readonly PointF Point3; + public PointF Point1 { get; } + public PointF Point2 { get; } + public PointF Point3 { get; } public BezierSegment(PointF point1, PointF point2, PointF point3) { @@ -23,9 +23,9 @@ public BezierSegment(PointF point1, PointF point2, PointF point3) public BezierSegment((float X, float Y) point1, (float X, float Y) point2, (float X, float Y) point3) { - Point1 = new PointF(point1.X, point1.Y); - Point2 = new PointF(point2.X, point2.Y); - Point3 = new PointF(point3.X, point3.Y); + Point1 = new(point1.X, point1.Y); + Point2 = new(point2.X, point2.Y); + Point3 = new(point3.X, point3.Y); } } } diff --git a/src/WInterop.DirectX/Direct2d/Bitmap.cs b/src/WInterop.DirectX/Direct2d/Bitmap.cs new file mode 100644 index 00000000..9344045d --- /dev/null +++ b/src/WInterop.DirectX/Direct2d/Bitmap.cs @@ -0,0 +1,110 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Drawing; +using System.Runtime.InteropServices; + +namespace WInterop.Direct2d +{ + /// + /// Root bitmap resource, linearly scaled on a draw call. [ID2D1Bitmap] + /// + [StructLayout(LayoutKind.Sequential)] + [Guid(InterfaceIds.IID_ID2D1Bitmap)] + public readonly unsafe struct Bitmap : Bitmap.Interface, IDisposable + { + internal readonly ID2D1Bitmap* _handle; + + internal Bitmap(ID2D1Bitmap* handle) => _handle = handle; + + public unsafe Factory GetFactory() => Resource.From(this).GetFactory(); + + public SizeF Size => _handle->GetSize().ToSizeF(); + + public SizeU PixelSize => new(_handle->GetPixelSize()); + + public PixelFormat PixelFormat => new(_handle->GetPixelFormat()); + + public PointF Dpi + { + get + { + float x; + float y; + _handle->GetDpi(&x, &y); + return new(x, y); + } + } + + public void CopyFromBitmap(PointU destinationPoint, Bitmap bitmap, Rectangle sourceRectangle) + { + var rect = sourceRectangle.ToD2D(); + _handle->CopyFromBitmap( + (D2D_POINT_2U*)&destinationPoint, + bitmap._handle, + &rect).ThrowIfFailed(); + } + + public void CopyFromRenderTarget(PointU destinationPoint, IRenderTarget renderTarget, Rectangle sourceRectangle) + { + var rect = sourceRectangle.ToD2D(); + _handle->CopyFromRenderTarget( + (D2D_POINT_2U*)&destinationPoint, + ((IResource)renderTarget).Handle, + &rect).ThrowIfFailed(); + } + + public void CopyFromMemory(Rectangle destinationRectangle, void* sourceData, uint pitch) + { + var rect = destinationRectangle.ToD2D(); + _handle->CopyFromMemory( + &rect, + sourceData, + pitch).ThrowIfFailed(); + } + + public void Dispose() => _handle->Release(); + + + public static implicit operator Image(Bitmap bitmap) => new((ID2D1Image*)bitmap._handle); + + internal interface Interface : Resource.Interface + { + /// + /// Returns the size of the bitmap in resolution independent units. + /// + SizeF Size { get; } + + /// + /// Returns the size of the bitmap in resolution dependent units, (pixels). + /// + SizeU PixelSize { get; } + + /// + /// Retrieve the format of the bitmap. + /// + PixelFormat PixelFormat { get; } + + /// + /// Return the DPI of the bitmap. + /// + PointF Dpi { get; } + + void CopyFromBitmap( + PointU destinationPoint, + Bitmap bitmap, + Rectangle sourceRectangle); + + void CopyFromRenderTarget( + PointU destinationPoint, + IRenderTarget renderTarget, + Rectangle sourceRectangle); + + void CopyFromMemory( + Rectangle destinationRectangle, + void* sourceData, + uint pitch); + } + } +} diff --git a/src/WInterop.DirectX/Direct2d/BitmapBrush.cs b/src/WInterop.DirectX/Direct2d/BitmapBrush.cs new file mode 100644 index 00000000..ea0cbbbc --- /dev/null +++ b/src/WInterop.DirectX/Direct2d/BitmapBrush.cs @@ -0,0 +1,90 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Numerics; +using System.Runtime.InteropServices; + +namespace WInterop.Direct2d +{ + /// + /// A bitmap brush allows a bitmap to be used to fill a geometry. [ID2D1BitmapBrush] + /// + [Guid(InterfaceIds.IID_ID2D1BitmapBrush)] + public readonly unsafe struct BitmapBrush : BitmapBrush.Interface + { + private readonly ID2D1BitmapBrush* _handle; + + internal BitmapBrush(ID2D1BitmapBrush* handle) => _handle = handle; + + public unsafe Factory GetFactory() => Resource.From(this).GetFactory(); + + public float Opacity + { + get => Brush.From(this).Opacity; + set => Brush.From(this).Opacity = value; + } + + public Matrix3x2 Transform + { + get => Brush.From(this).Transform; + set => Brush.From(this).Transform = value; + } + + public ExtendMode ExtendModeX + { + get => (ExtendMode)_handle->GetExtendModeX(); + set => _handle->SetExtendModeX((D2D1_EXTEND_MODE)value); + } + + public ExtendMode ExtendModeY + { + get => (ExtendMode)_handle->GetExtendModeY(); + set => _handle->SetExtendModeY((D2D1_EXTEND_MODE)value); + } + + public Bitmap Bitmap + { + get + { + ID2D1Bitmap* bitmap; + _handle->GetBitmap(&bitmap); + return new(bitmap); + } + set => _handle->SetBitmap(value._handle); + } + + public BitmapInterpolationMode InterpolationMode + { + get => (BitmapInterpolationMode)_handle->GetInterpolationMode(); + set => _handle->SetInterpolationMode((D2D1_BITMAP_INTERPOLATION_MODE)value); + } + + public void Dispose() => _handle->Release(); + + public static implicit operator Brush(BitmapBrush brush) => new((ID2D1Brush*)brush._handle); + + internal interface Interface : Brush.Interface + { + /// + /// How the bitmap is to be treated outside of its natural extent on the X axis. + /// + ExtendMode ExtendModeX { get; set; } + + /// + /// How the bitmap is to be treated outside of its natural extent on the Y axis. + /// + ExtendMode ExtendModeY { get; set; } + + /// + /// Sets the bitmap associated as the source of this brush. + /// + Bitmap Bitmap { get; set; } + + /// + /// The interpolation mode used when this brush is used. + /// + BitmapInterpolationMode InterpolationMode { get; set; } + } + } +} diff --git a/src/WInterop.DirectX/Direct2d/BitmapBrushProperties.cs b/src/WInterop.DirectX/Direct2d/BitmapBrushProperties.cs index d24ff008..fc1645c3 100644 --- a/src/WInterop.DirectX/Direct2d/BitmapBrushProperties.cs +++ b/src/WInterop.DirectX/Direct2d/BitmapBrushProperties.cs @@ -1,17 +1,19 @@ // Copyright (c) Jeremy W. Kuhne. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using System.Runtime.CompilerServices; + namespace WInterop.Direct2d { /// - /// Describes the extend modes and the interpolation mode of an . + /// Describes the extend modes and the interpolation mode of an . /// [D2D1_BITMAP_BRUSH_PROPERTIES] /// - public readonly struct BitmapBrushProperties + public struct BitmapBrushProperties { - public readonly ExtendMode ExtendModeX; - public readonly ExtendMode ExtendModeY; - public readonly BitmapInterpolationMode InterpolationMode; + public ExtendMode ExtendModeX; + public ExtendMode ExtendModeY; + public BitmapInterpolationMode InterpolationMode; public BitmapBrushProperties( ExtendMode extendModeX = ExtendMode.Clamp, @@ -22,5 +24,11 @@ public BitmapBrushProperties( ExtendModeY = extendModeY; InterpolationMode = interpolationMode; } + + public static implicit operator BitmapBrushProperties(in D2D1_BITMAP_BRUSH_PROPERTIES properties) + => Unsafe.As(ref Unsafe.AsRef(properties)); + + public static implicit operator D2D1_BITMAP_BRUSH_PROPERTIES(in BitmapBrushProperties properties) + => Unsafe.As(ref Unsafe.AsRef(properties)); } } diff --git a/src/WInterop.DirectX/Direct2d/BitmapRenderTarget.cs b/src/WInterop.DirectX/Direct2d/BitmapRenderTarget.cs new file mode 100644 index 00000000..5151085b --- /dev/null +++ b/src/WInterop.DirectX/Direct2d/BitmapRenderTarget.cs @@ -0,0 +1,28 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace WInterop.Direct2d +{ + /// + /// Renders to an intermediate texture created by the CreateCompatibleRenderTarget method. + /// [ID2D1BitmapRenderTarget] + /// + internal unsafe class BitmapRenderTarget : RenderTarget, IBitmapRenderTarget + { + private readonly ID2D1BitmapRenderTarget* _handle; + + internal BitmapRenderTarget(ID2D1BitmapRenderTarget* handle) + : base ((ID2D1RenderTarget*)handle) + => _handle = handle; + + public Bitmap Bitmap + { + get + { + ID2D1Bitmap* bitmap; + _handle->GetBitmap(&bitmap).ThrowIfFailed(); + return new(bitmap); + } + } + } +} diff --git a/src/WInterop.DirectX/Direct2d/Brush.cs b/src/WInterop.DirectX/Direct2d/Brush.cs new file mode 100644 index 00000000..dd023149 --- /dev/null +++ b/src/WInterop.DirectX/Direct2d/Brush.cs @@ -0,0 +1,61 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace WInterop.Direct2d +{ + /// + /// The root brush interface. All brushes can be used to fill or pen a geometry. + /// [ID2D1Brush] + /// + [StructLayout(LayoutKind.Sequential)] + [Guid(InterfaceIds.IID_ID2D1Brush)] + public readonly unsafe struct Brush : Brush.Interface, IDisposable + { + internal readonly ID2D1Brush* Handle { get; } + + internal Brush(ID2D1Brush* handle) => Handle = handle; + + public unsafe Factory GetFactory() => Resource.From(this).GetFactory(); + + public float Opacity + { + get => Handle->GetOpacity(); + set => Handle->SetOpacity(value); + } + + public Matrix3x2 Transform + { + get + { + Matrix3x2 matrix; + Handle->GetTransform((D2D_MATRIX_3X2_F*)&matrix); + return matrix; + } + set => Handle->SetTransform((D2D_MATRIX_3X2_F*)&value); + } + + internal static ref Brush From(in TFrom from) + where TFrom : unmanaged, Interface + => ref Unsafe.AsRef(Unsafe.AsPointer(ref Unsafe.AsRef(from))); + + public void Dispose() => Handle->Release(); + + internal interface Interface : Resource.Interface + { + /// + /// Sets the opacity for when the brush is drawn over the entire fill of the brush. + /// + float Opacity { get; set; } + + /// + /// Sets the transform that applies to everything drawn by the brush. + /// + Matrix3x2 Transform { get; set; } + } + } +} diff --git a/src/WInterop.DirectX/Direct2d/BrushProperties.cs b/src/WInterop.DirectX/Direct2d/BrushProperties.cs index 4b3efa0b..123fbd7e 100644 --- a/src/WInterop.DirectX/Direct2d/BrushProperties.cs +++ b/src/WInterop.DirectX/Direct2d/BrushProperties.cs @@ -2,21 +2,30 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.Numerics; +using System.Runtime.CompilerServices; namespace WInterop.Direct2d { /// /// Describes the opacity and transformation of a brush. [D2D1_BRUSH_PROPERTIES] /// - public readonly struct BrushProperties + public struct BrushProperties { public readonly float Opacity; public readonly Matrix3x2 Transform; - public BrushProperties(float opacity) + public static BrushProperties Default { get; } = new(1.0f, Matrix3x2.Identity); + + public BrushProperties(float opacity, Matrix3x2 transform) { Opacity = opacity; - Transform = Matrix3x2.Identity; + Transform = transform; } + + public static implicit operator BrushProperties(in D2D1_BRUSH_PROPERTIES properties) + => Unsafe.As(ref Unsafe.AsRef(properties)); + + public static implicit operator D2D1_BRUSH_PROPERTIES(in BrushProperties properties) + => Unsafe.As(ref Unsafe.AsRef(properties)); } } diff --git a/src/WInterop.DirectX/Direct2d/CapStyle.cs b/src/WInterop.DirectX/Direct2d/CapStyle.cs index 32e2bce4..8d88164f 100644 --- a/src/WInterop.DirectX/Direct2d/CapStyle.cs +++ b/src/WInterop.DirectX/Direct2d/CapStyle.cs @@ -12,21 +12,21 @@ public enum CapStyle : uint /// /// Flat line cap. [D2D1_CAP_STYLE_FLAT] /// - Flat = 0, + Flat = D2D1_CAP_STYLE.D2D1_CAP_STYLE_FLAT, /// /// Square line cap. [D2D1_CAP_STYLE_SQUARE] /// - Square = 1, + Square = D2D1_CAP_STYLE.D2D1_CAP_STYLE_SQUARE, /// /// Round line cap. [D2D1_CAP_STYLE_ROUND] /// - Round = 2, + Round = D2D1_CAP_STYLE.D2D1_CAP_STYLE_ROUND, /// /// Triangle line cap. [D2D1_CAP_STYLE_TRIANGLE] /// - Triangle = 3 + Triangle = D2D1_CAP_STYLE.D2D1_CAP_STYLE_TRIANGLE } } diff --git a/src/WInterop.DirectX/Direct2d/ColorF.cs b/src/WInterop.DirectX/Direct2d/ColorF.cs index 5bed64b5..c211067a 100644 --- a/src/WInterop.DirectX/Direct2d/ColorF.cs +++ b/src/WInterop.DirectX/Direct2d/ColorF.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.Drawing; +using System.Runtime.CompilerServices; namespace WInterop.Direct2d { @@ -31,10 +32,16 @@ public ColorF(Color color, float a = 1.0f) A = a; } + public static implicit operator ColorF(in DXGI_RGBA color) + => Unsafe.As(ref Unsafe.AsRef(color)); + + public static implicit operator DXGI_RGBA(in ColorF color) + => Unsafe.As(ref Unsafe.AsRef(color)); + public static implicit operator Color(ColorF color) => Color.FromArgb((int)(color.A * 255), (int)(color.R * 255), (int)(color.G * 255), (int)(color.B * 255)); public static implicit operator ColorF(Color color) - => new ColorF(color, color.A / 255.0f); + => new(color, color.A / 255.0f); } } diff --git a/src/WInterop.DirectX/Direct2d/DashStyle.cs b/src/WInterop.DirectX/Direct2d/DashStyle.cs index dfacb9de..9c27f003 100644 --- a/src/WInterop.DirectX/Direct2d/DashStyle.cs +++ b/src/WInterop.DirectX/Direct2d/DashStyle.cs @@ -12,31 +12,31 @@ public enum DashStyle : uint /// /// [D2D1_DASH_STYLE_SOLID] /// - Solid = 0, + Solid = D2D1_DASH_STYLE.D2D1_DASH_STYLE_SOLID, /// /// [D2D1_DASH_STYLE_DASH] /// - Dash = 1, + Dash = D2D1_DASH_STYLE.D2D1_DASH_STYLE_DASH, /// /// [D2D1_DASH_STYLE_DOT] /// - Dot = 2, + Dot = D2D1_DASH_STYLE.D2D1_DASH_STYLE_DOT, /// /// [D2D1_DASH_STYLE_DASH_DOT] /// - DashDot = 3, + DashDot = D2D1_DASH_STYLE.D2D1_DASH_STYLE_DASH_DOT, /// /// [D2D1_DASH_STYLE_DASH_DOT_DOT] /// - DashDotDot = 4, + DashDotDot = D2D1_DASH_STYLE.D2D1_DASH_STYLE_DASH_DOT_DOT, /// /// [D2D1_DASH_STYLE_CUSTOM] /// - Custom = 5 + Custom = D2D1_DASH_STYLE.D2D1_DASH_STYLE_CUSTOM } } diff --git a/src/WInterop.DirectX/Direct2d/DebugLevel.cs b/src/WInterop.DirectX/Direct2d/DebugLevel.cs index 1440df7b..cc9c040d 100644 --- a/src/WInterop.DirectX/Direct2d/DebugLevel.cs +++ b/src/WInterop.DirectX/Direct2d/DebugLevel.cs @@ -12,21 +12,21 @@ public enum DebugLevel : uint /// /// [D2D1_DEBUG_LEVEL_NONE] /// - None, + None = D2D1_DEBUG_LEVEL.D2D1_DEBUG_LEVEL_NONE, /// /// [D2D1_DEBUG_LEVEL_ERROR] /// - Error, + Error = D2D1_DEBUG_LEVEL.D2D1_DEBUG_LEVEL_ERROR, /// /// [D2D1_DEBUG_LEVEL_WARNING] /// - Warning, + Warning = D2D1_DEBUG_LEVEL.D2D1_DEBUG_LEVEL_WARNING, /// /// [D2D1_DEBUG_LEVEL_INFORMATION] /// - Information + Information = D2D1_DEBUG_LEVEL.D2D1_DEBUG_LEVEL_INFORMATION } } diff --git a/src/WInterop.DirectX/Direct2d/Direct2d.cs b/src/WInterop.DirectX/Direct2d/Direct2d.cs index ae4f33a9..8a330407 100644 --- a/src/WInterop.DirectX/Direct2d/Direct2d.cs +++ b/src/WInterop.DirectX/Direct2d/Direct2d.cs @@ -1,23 +1,24 @@ // Copyright (c) Jeremy W. Kuhne. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System; using WInterop.Errors; -using WInterop.Direct2d.Native; namespace WInterop.Direct2d { public static class Direct2d { - public static IFactory CreateFactory( + public unsafe static Factory CreateFactory( FactoryType factoryType = FactoryType.SingleThreaded, DebugLevel debugLevel = DebugLevel.None) { - Imports.D2D1CreateFactory( - factoryType, new Guid(InterfaceIds.IID_ID2D1Factory), debugLevel, out IFactory factory) - .ThrowIfFailed(); + ID2D1Factory* factory; + HResult result = TerraFX.Interop.DirectX.DirectX.D2D1CreateFactory( + (D2D1_FACTORY_TYPE)factoryType, + (D2D1_FACTORY_OPTIONS*)&debugLevel, + (void**)&factory).ToHResult(); - return factory; + result.ThrowIfFailed(); + return new(factory); } } } diff --git a/src/WInterop.DirectX/Direct2d/Ellipse.cs b/src/WInterop.DirectX/Direct2d/Ellipse.cs index b31a4eda..5153f663 100644 --- a/src/WInterop.DirectX/Direct2d/Ellipse.cs +++ b/src/WInterop.DirectX/Direct2d/Ellipse.cs @@ -12,9 +12,9 @@ namespace WInterop.Direct2d /// public readonly struct Ellipse { - public readonly PointF Point; - public readonly float RadiusX; - public readonly float RadiusY; + public PointF Point { get; } + public float RadiusX { get; } + public float RadiusY { get; } public Ellipse(PointF point, float radiusX, float radiusY) { @@ -22,5 +22,12 @@ public Ellipse(PointF point, float radiusX, float radiusY) RadiusX = radiusX; RadiusY = radiusY; } + + public unsafe Ellipse((float X, float Y) point, float radiusX, float radiusY) + { + Point = *(PointF*)&point; + RadiusX = radiusX; + RadiusY = radiusY; + } } } diff --git a/src/WInterop.DirectX/Direct2d/EllipseGeometry.cs b/src/WInterop.DirectX/Direct2d/EllipseGeometry.cs new file mode 100644 index 00000000..07c72296 --- /dev/null +++ b/src/WInterop.DirectX/Direct2d/EllipseGeometry.cs @@ -0,0 +1,49 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Drawing; +using System.Runtime.InteropServices; +using System.Numerics; +using System.Runtime.CompilerServices; + +namespace WInterop.Direct2d +{ + /// + /// [ID2D1EllipseGeometry] + /// + [StructLayout(LayoutKind.Sequential)] + [Guid(InterfaceIds.IID_ID2D1ElipseGeometry)] + public readonly unsafe struct EllipseGeometry : EllipseGeometry.Interface, IDisposable + { + internal readonly ID2D1EllipseGeometry* _handle; + + internal EllipseGeometry(ID2D1EllipseGeometry* handle) => _handle = handle; + + public RectangleF GetBounds() => Geometry.From(this).GetBounds(); + + public RectangleF GetBounds(Matrix3x2 worldTransform) + => Geometry.From(this).GetBounds(worldTransform); + + public void CombineWithGeometry(Geometry inputGeometry, CombineMode combineMode, SimplifiedGeometrySink geometrySink) + => Geometry.From(this).CombineWithGeometry(inputGeometry, combineMode, geometrySink); + + public Ellipse GetEllipse() + { + Ellipse ellipse; + _handle->GetEllipse((D2D1_ELLIPSE*)&ellipse); + return ellipse; + } + + public Factory GetFactory() => Resource.From(this).GetFactory(); + + public void Dispose() => _handle->Release(); + + public static implicit operator Geometry(EllipseGeometry geometry) => new((ID2D1Geometry*)geometry._handle); + + internal unsafe interface Interface : Geometry.Interface + { + Ellipse GetEllipse(); + } + } +} diff --git a/src/WInterop.DirectX/Direct2d/ExtendMode.cs b/src/WInterop.DirectX/Direct2d/ExtendMode.cs index afe5cd13..a7878df7 100644 --- a/src/WInterop.DirectX/Direct2d/ExtendMode.cs +++ b/src/WInterop.DirectX/Direct2d/ExtendMode.cs @@ -12,18 +12,18 @@ public enum ExtendMode : uint /// Extend the edges of the source out by clamping sample points outside the source /// to the edges. [D2D1_EXTEND_MODE_CLAMP] /// - Clamp = 0, + Clamp = D2D1_EXTEND_MODE.D2D1_EXTEND_MODE_CLAMP, /// /// The base tile is drawn untransformed and the remainder are filled by repeating /// the base tile. [D2D1_EXTEND_MODE_WRAP] /// - Wrap = 1, + Wrap = D2D1_EXTEND_MODE.D2D1_EXTEND_MODE_WRAP, /// /// The same as wrap, but alternate tiles are flipped The base tile is drawn /// untransformed. [D2D1_EXTEND_MODE_MIRROR] /// - Mirror = 2 + Mirror = D2D1_EXTEND_MODE.D2D1_EXTEND_MODE_MIRROR } } diff --git a/src/WInterop.DirectX/Direct2d/Factory.cs b/src/WInterop.DirectX/Direct2d/Factory.cs new file mode 100644 index 00000000..5d8e284f --- /dev/null +++ b/src/WInterop.DirectX/Direct2d/Factory.cs @@ -0,0 +1,164 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Drawing; +using System.Numerics; + +namespace WInterop.Direct2d +{ + /// + /// [ID2D1Factory] + /// + /// + /// https://docs.microsoft.com/windows/win32/api/d2d1/nn-d2d1-id2d1factory + /// + public readonly unsafe struct Factory : Factory.Interface, IDisposable + { + private readonly ID2D1Factory* _handle; + + internal Factory(ID2D1Factory* factory) => _handle = factory; + + public EllipseGeometry CreateEllipseGeometry(Ellipse ellipse) + { + ID2D1EllipseGeometry* geometry; + _handle->CreateEllipseGeometry((D2D1_ELLIPSE*)&ellipse, &geometry).ThrowIfFailed(); + return new(geometry); + } + + public GeometryGroup CreateGeometryGroup(FillMode fillMode, ReadOnlySpan geometries) + { + fixed (Geometry* g = geometries) + { + ID2D1GeometryGroup* group; + _handle->CreateGeometryGroup( + (D2D1_FILL_MODE)fillMode, + (ID2D1Geometry**)&g, + (uint)geometries.Length, + &group).ThrowIfFailed(); + + return new(group); + } + } + + public PathGeometry CreatePathGeometry() + { + ID2D1PathGeometry* geometry; + _handle->CreatePathGeometry(&geometry).ThrowIfFailed(); + return new(geometry); + } + + public RectangleGeometry CreateRectangleGeometry(RectangleF rectangle) + { + ID2D1RectangleGeometry* geometry; + var rect = rectangle.ToD2D(); + _handle->CreateRectangleGeometry(&rect, &geometry).ThrowIfFailed(); + return new(geometry); + } + + public RoundedRectangleGeometry CreateRoundedRectangleGeometry(RoundedRectangle roundedRectangle) + { + ID2D1RoundedRectangleGeometry* geometry; + _handle->CreateRoundedRectangleGeometry((D2D1_ROUNDED_RECT*)&roundedRectangle, &geometry).ThrowIfFailed(); + return new(geometry); + } + + public StrokeStyle CreateStrokeStyle(StrokeStyleProperties strokeStyleProperties, ReadOnlySpan dashes = default) + { + ID2D1StrokeStyle* style; + fixed(float* d = dashes) + { + _handle->CreateStrokeStyle( + (D2D1_STROKE_STYLE_PROPERTIES*)&strokeStyleProperties, + d, + (uint)dashes.Length, + &style).ThrowIfFailed(); + + return new(style); + } + } + + public TransformedGeometry CreateTransformedGeometry(Geometry sourceGeometry, Matrix3x2 transform) + { + ID2D1TransformedGeometry* geometry; + _handle->CreateTransformedGeometry( + sourceGeometry._handle, + (D2D_MATRIX_3X2_F*)&transform, + &geometry).ThrowIfFailed(); + + return new(geometry); + } + + public IWindowRenderTarget CreateWindowRenderTarget( + RenderTargetProperties renderTargetProperties, + WindowRenderTargetProperties hwndRenderTargetProperties) + { + ID2D1HwndRenderTarget* target; + _handle->CreateHwndRenderTarget( + (D2D1_RENDER_TARGET_PROPERTIES*)&renderTargetProperties, + (D2D1_HWND_RENDER_TARGET_PROPERTIES*)&hwndRenderTargetProperties, + &target).ThrowIfFailed(); + + return new WindowRenderTarget(target); + } + + public void Dispose() => _handle->Release(); + + public SizeF GetDesktopDpi() + { + float x; + float y; + _handle->GetDesktopDpi(&x, &y); + return new(x, y); + } + + public void ReloadSystemMetrics() => _handle->ReloadSystemMetrics().ThrowIfFailed(); + + internal unsafe interface Interface + { + RectangleGeometry CreateRectangleGeometry(RectangleF rectangle); + + RoundedRectangleGeometry CreateRoundedRectangleGeometry(RoundedRectangle roundedRectangle); + + EllipseGeometry CreateEllipseGeometry(Ellipse ellipse); + + GeometryGroup CreateGeometryGroup( + FillMode fillMode, + ReadOnlySpan geometries); + + TransformedGeometry CreateTransformedGeometry( + Geometry sourceGeometry, + Matrix3x2 transform); + + /// + /// Returns an initially empty path geometry interface. A geometry sink is created + /// off the interface to populate it. + /// + PathGeometry CreatePathGeometry(); + + /// + /// Allows a non-default stroke style to be specified for a given geometry at draw time. + /// + StrokeStyle CreateStrokeStyle( + StrokeStyleProperties strokeStyleProperties, + ReadOnlySpan dashes = default); + + /// + /// Creates a render target that appears on the display. [CreateHwndRenderTarget] + /// + IWindowRenderTarget CreateWindowRenderTarget( + RenderTargetProperties renderTargetProperties, + WindowRenderTargetProperties hwndRenderTargetProperties); + + /// + /// Gets the current desktop DPI. + /// + SizeF GetDesktopDpi(); + + /// + /// Forces the factory to refresh any system defaults that it might have changed since factory creation. + /// + void ReloadSystemMetrics(); + } + } +} diff --git a/src/WInterop.DirectX/Direct2d/FactoryType.cs b/src/WInterop.DirectX/Direct2d/FactoryType.cs index 8a3cbfca..c2276e2d 100644 --- a/src/WInterop.DirectX/Direct2d/FactoryType.cs +++ b/src/WInterop.DirectX/Direct2d/FactoryType.cs @@ -14,11 +14,11 @@ public enum FactoryType : uint /// /// [D2D1_FACTORY_TYPE_SINGLE_THREADED] /// - SingleThreaded, + SingleThreaded = D2D1_FACTORY_TYPE.D2D1_FACTORY_TYPE_SINGLE_THREADED, /// /// [D2D1_FACTORY_TYPE_MULTI_THREADED] /// - MultiThreaded + MultiThreaded = D2D1_FACTORY_TYPE.D2D1_FACTORY_TYPE_MULTI_THREADED } } diff --git a/src/WInterop.DirectX/Direct2d/FigureBegin.cs b/src/WInterop.DirectX/Direct2d/FigureBegin.cs index 9d37d69f..e2247b55 100644 --- a/src/WInterop.DirectX/Direct2d/FigureBegin.cs +++ b/src/WInterop.DirectX/Direct2d/FigureBegin.cs @@ -11,11 +11,11 @@ public enum FigureBegin : uint /// /// [D2D1_FIGURE_BEGIN_FILLED] /// - Filled = 0, + Filled = D2D1_FIGURE_BEGIN.D2D1_FIGURE_BEGIN_FILLED, /// /// [D2D1_FIGURE_BEGIN_HOLLOW] /// - Hollow = 1 + Hollow = D2D1_FIGURE_BEGIN.D2D1_FIGURE_BEGIN_HOLLOW } } diff --git a/src/WInterop.DirectX/Direct2d/FigureEnd.cs b/src/WInterop.DirectX/Direct2d/FigureEnd.cs index e2237856..61e02fa8 100644 --- a/src/WInterop.DirectX/Direct2d/FigureEnd.cs +++ b/src/WInterop.DirectX/Direct2d/FigureEnd.cs @@ -11,11 +11,11 @@ public enum FigureEnd : uint /// /// [D2D1_FIGURE_END_OPEN] /// - Open = 0, + Open = D2D1_FIGURE_END.D2D1_FIGURE_END_OPEN, /// /// [D2D1_FIGURE_END_CLOSED] /// - Closed = 1 + Closed = D2D1_FIGURE_END.D2D1_FIGURE_END_CLOSED } } diff --git a/src/WInterop.DirectX/Direct2d/FillMode.cs b/src/WInterop.DirectX/Direct2d/FillMode.cs index f163f0a0..32e76393 100644 --- a/src/WInterop.DirectX/Direct2d/FillMode.cs +++ b/src/WInterop.DirectX/Direct2d/FillMode.cs @@ -12,11 +12,11 @@ public enum FillMode : uint /// /// [D2D1_FILL_MODE_ALTERNATE] /// - Alternate = 0, + Alternate = D2D1_FILL_MODE.D2D1_FILL_MODE_ALTERNATE, /// /// [D2D1_FILL_MODE_WINDING] /// - Winding = 1 + Winding = D2D1_FILL_MODE.D2D1_FILL_MODE_WINDING } } diff --git a/src/WInterop.DirectX/Direct2d/Gamma.cs b/src/WInterop.DirectX/Direct2d/Gamma.cs index 71697beb..fe625993 100644 --- a/src/WInterop.DirectX/Direct2d/Gamma.cs +++ b/src/WInterop.DirectX/Direct2d/Gamma.cs @@ -11,11 +11,11 @@ public enum Gamma : uint /// /// Colors are manipulated in 2.2 gamma color space. [D2D1_GAMMA_2_2] /// - ColorSpace_2_2 = 0, + ColorSpace_2_2 = D2D1_GAMMA.D2D1_GAMMA_2_2, /// /// Colors are manipulated in 1.0 gamma color space. [D2D1_GAMMA_1_0] /// - ColorSpace_1_0 = 1, + ColorSpace_1_0 = D2D1_GAMMA.D2D1_GAMMA_1_0, } } diff --git a/src/WInterop.DirectX/Direct2d/Geometry.cs b/src/WInterop.DirectX/Direct2d/Geometry.cs new file mode 100644 index 00000000..2b5293b2 --- /dev/null +++ b/src/WInterop.DirectX/Direct2d/Geometry.cs @@ -0,0 +1,182 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Drawing; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace WInterop.Direct2d +{ + [Guid(InterfaceIds.IID_ID2D1Geometry)] + [StructLayout(LayoutKind.Sequential)] + public readonly unsafe struct Geometry : Geometry.Interface, IDisposable + { + internal readonly ID2D1Geometry* _handle; + + internal Geometry(ID2D1Geometry* handle) => _handle = handle; + + public Factory GetFactory() => Resource.From(this).GetFactory(); + + public RectangleF GetBounds() + { + D2D_RECT_F rect; + _handle->GetBounds(null, &rect).ThrowIfFailed(); + return rect.ToRectangleF(); + } + + public RectangleF GetBounds(Matrix3x2 worldTransform) + { + D2D_RECT_F rect; + _handle->GetBounds((D2D_MATRIX_3X2_F*)&worldTransform, &rect).ThrowIfFailed(); + return rect.ToRectangleF(); + } + + public unsafe void CombineWithGeometry( + Geometry inputGeometry, + CombineMode combineMode, + SimplifiedGeometrySink geometrySink) + { + _handle->CombineWithGeometry( + inputGeometry._handle, + (D2D1_COMBINE_MODE)combineMode, + null, + geometrySink.Handle); + } + + internal static ref Geometry From(in TFrom from) + where TFrom : unmanaged, Interface + => ref Unsafe.AsRef(Unsafe.AsPointer(ref Unsafe.AsRef(from))); + + public void Dispose() => _handle->Release(); + + /// + /// [ID2D1Geometry] + /// + internal unsafe interface Interface : Resource.Interface + { + /// + /// Retrieve the bounds of the geometry. + /// + RectangleF GetBounds(); + + /// + /// Retrieve the bounds of the geometry with the applied . + /// + RectangleF GetBounds(Matrix3x2 worldTransform); + + /* + /// + /// Get the bounds of the corresponding geometry after it has been widened or have + /// an optional pen style applied. + /// + RectangleF GetWidenedBounds( + float strokeWidth, + StrokeStyle* strokeStyle, + Matrix3x2* worldTransform, + float flatteningTolerance); + + /// + /// Checks to see whether the corresponding penned and widened geometry contains the + /// given point. + /// + bool StrokeContainsPoint( + PointF point, + float strokeWidth, + StrokeStyle* strokeStyle, + Matrix3x2* worldTransform, + float flatteningTolerance); + + /// + /// Test whether the given fill of this geometry would contain this point. + /// + IntBoolean FillContainsPoint( + PointF point, + Matrix3x2* worldTransform, + float flatteningTolerance); + + /// + /// Compare how one geometry intersects or contains another geometry. + /// + GeometryRelation CompareWithGeometry( + Geometry* inputGeometry, + Matrix3x2* inputGeometryTransform, + float flatteningTolerance); + + /// + /// Converts a geometry to a simplified geometry that has arcs and quadratic beziers + /// removed. + /// + void Simplify( + GeometrySimplificationOption simplificationOption, + Matrix3x2* worldTransform, + float flatteningTolerance, + ISimplifiedGeometrySink geometrySink); + + /// + /// Tessellates a geometry into triangles. + /// + void Tessellate( + Matrix3x2* worldTransform, + float flatteningTolerance, + ITesselationSink tessellationSink); + */ + + /// + /// Performs a combine operation between the two geometries to produce a resulting geometry. + /// + void CombineWithGeometry( + Geometry inputGeometry, + CombineMode combineMode, + //Matrix3x2? inputGeometryTransform, + //float? flatteningTolerance, + SimplifiedGeometrySink geometrySink); + + /* + /// + /// Computes the outline of the geometry. The result is written back into a + /// simplified geometry sink. + /// + void Outline( + Matrix3x2* worldTransform, + float flatteningTolerance, + ISimplifiedGeometrySink geometrySink); + + /// + /// Computes the area of the geometry. + /// + float ComputeArea( + Matrix3x2* worldTransform, + float flatteningTolerance); + + /// + /// Computes the length of the geometry. + /// + float ComputeLength( + Matrix3x2* worldTransform, + float flatteningTolerance); + + /// + /// Computes the point and tangent a given distance along the path. + /// + void ComputePointAtLength( + float length, + Matrix3x2* worldTransform, + float flatteningTolerance, + PointF* point, + PointF* unitTangentVector); + + /// + /// Get the geometry and widen it as well as apply an optional pen style. + /// + void Widen( + float strokeWidth, + IStrokeStyle strokeStyle, + Matrix3x2* worldTransform, + float flatteningTolerance, + ISimplifiedGeometrySink geometrySink); + */ + } + } +} diff --git a/src/WInterop.DirectX/Direct2d/GeometryGroup.cs b/src/WInterop.DirectX/Direct2d/GeometryGroup.cs new file mode 100644 index 00000000..82eea4b8 --- /dev/null +++ b/src/WInterop.DirectX/Direct2d/GeometryGroup.cs @@ -0,0 +1,58 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Drawing; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace WInterop.Direct2d +{ + /// + /// [ID2D1GeometryGroup] + /// + [StructLayout(LayoutKind.Sequential)] + [Guid(InterfaceIds.IID_ID2D1GeometryGroup)] + public readonly unsafe struct GeometryGroup : GeometryGroup.Interface, IDisposable + { + internal readonly ID2D1GeometryGroup* _handle; + + internal GeometryGroup(ID2D1GeometryGroup* handle) => _handle = handle; + + public RectangleF GetBounds() => Geometry.From(this).GetBounds(); + + public RectangleF GetBounds(Matrix3x2 worldTransform) + => Geometry.From(this).GetBounds(worldTransform); + + public void CombineWithGeometry(Geometry inputGeometry, CombineMode combineMode, SimplifiedGeometrySink geometrySink) + => Geometry.From(this).CombineWithGeometry(inputGeometry, combineMode, geometrySink); + + public Factory GetFactory() => Geometry.From(this).GetFactory(); + + public FillMode GetFillMode() => (FillMode)_handle->GetFillMode(); + + public void GetSourceGeometries(Span geometries) + { + fixed(void* g = geometries) + { + _handle->GetSourceGeometries((ID2D1Geometry**)&g, (uint)geometries.Length); + } + } + + public uint GetSourceGeometryCount() => _handle->GetSourceGeometryCount(); + + public void Dispose() => _handle->Release(); + + public static implicit operator Geometry(GeometryGroup geometry) => new((ID2D1Geometry*)geometry._handle); + + internal unsafe interface Interface : Geometry.Interface + { + FillMode GetFillMode(); + + uint GetSourceGeometryCount(); + + unsafe void GetSourceGeometries(Span geometries); + } + } +} diff --git a/src/WInterop.DirectX/Direct2d/GeometryRelation.cs b/src/WInterop.DirectX/Direct2d/GeometryRelation.cs index 136a4298..dbe2bf87 100644 --- a/src/WInterop.DirectX/Direct2d/GeometryRelation.cs +++ b/src/WInterop.DirectX/Direct2d/GeometryRelation.cs @@ -4,8 +4,7 @@ namespace WInterop.Direct2d { /// - /// Describes how one geometry object is spatially related to another geometry - /// object. + /// Describes how one geometry object is spatially related to another geometry object. /// public enum GeometryRelation : uint { diff --git a/src/WInterop.DirectX/Direct2d/GeometrySink.cs b/src/WInterop.DirectX/Direct2d/GeometrySink.cs new file mode 100644 index 00000000..04d1d782 --- /dev/null +++ b/src/WInterop.DirectX/Direct2d/GeometrySink.cs @@ -0,0 +1,93 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Drawing; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace WInterop.Direct2d +{ + /// + /// Describes a geometric path that can contain lines, arcs, cubic Bezier curves, + /// and quadratic Bezier curves. [ID2D1GeometrySink] + /// + [StructLayout(LayoutKind.Sequential)] + [Guid(InterfaceIds.IID_ID2D1GeometrySink)] + public readonly unsafe struct GeometrySink : GeometrySink.Interface, IDisposable + { + internal ID2D1GeometrySink* Handle { get; } + + public void AddArc(ArcSegment arc) => Handle->AddArc((D2D1_ARC_SEGMENT*)&arc); + + public void AddBezier(BezierSegment bezier) => Handle->AddBezier((D2D1_BEZIER_SEGMENT*)&bezier); + + public void AddBeziers(ReadOnlySpan beziers) + { + fixed(BezierSegment* b = beziers) + { + Handle->AddBeziers((D2D1_BEZIER_SEGMENT*)b, (uint)beziers.Length); + } + } + + public void AddLine(PointF point) => Handle->AddLine(point.ToD2D()); + + public void AddLine((float X, float Y) point) => Handle->AddLine(new(point.X, point.Y)); + + public void AddLines(ReadOnlySpan points) + => SimplifiedGeometrySink.From(this).AddLines(points); + + public void AddQuadraticBezier(QuadraticBezierSegment bezier) + => Handle->AddQuadraticBezier((D2D1_QUADRATIC_BEZIER_SEGMENT*)&bezier); + + public void AddQuadraticBeziers(ReadOnlySpan beziers) + { + fixed(QuadraticBezierSegment* b = beziers) + { + Handle->AddQuadraticBeziers((D2D1_QUADRATIC_BEZIER_SEGMENT*)b, (uint)beziers.Length); + } + } + public void BeginFigure(PointF startPoint, FigureBegin figureBegin) + => SimplifiedGeometrySink.From(this).BeginFigure(startPoint, figureBegin); + + public void BeginFigure((float X, float Y) startPoint, FigureBegin figureBegin) + => SimplifiedGeometrySink.From(this).BeginFigure(startPoint, figureBegin); + + public void Close() => SimplifiedGeometrySink.From(this).Close(); + + public void EndFigure(FigureEnd figureEnd) + => SimplifiedGeometrySink.From(this).EndFigure(figureEnd); + + public void SetFillMode(FillMode fillMode) + => SimplifiedGeometrySink.From(this).SetFillMode(fillMode); + + public void SetSegmentFlags(PathSegment vertexFlags) + => SimplifiedGeometrySink.From(this).SetSegmentFlags(vertexFlags); + + public static implicit operator SimplifiedGeometrySink(GeometrySink sink) + => new((ID2D1SimplifiedGeometrySink*)sink.Handle); + + internal static ref GeometrySink From(in TFrom from) + where TFrom : unmanaged, Interface + => ref Unsafe.AsRef(Unsafe.AsPointer(ref Unsafe.AsRef(from))); + + public void Dispose() + { + Handle->Close(); + Handle->Release(); + } + + internal interface Interface : SimplifiedGeometrySink.Interface + { + void AddLine(PointF point); + + void AddBezier(BezierSegment bezier); + + void AddQuadraticBezier(QuadraticBezierSegment bezier); + + void AddQuadraticBeziers(ReadOnlySpan beziers); + + void AddArc(ArcSegment arc); + } + } +} diff --git a/src/WInterop.DirectX/Direct2d/GradientStopCollection.cs b/src/WInterop.DirectX/Direct2d/GradientStopCollection.cs new file mode 100644 index 00000000..8e3c91c6 --- /dev/null +++ b/src/WInterop.DirectX/Direct2d/GradientStopCollection.cs @@ -0,0 +1,61 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace WInterop.Direct2d +{ + /// + /// Represents an collection of gradient stops that can then be the source resource + /// for either a linear or radial gradient brush. [ID2D1GradientStopCollection] + /// + [StructLayout(LayoutKind.Sequential)] + [Guid(InterfaceIds.IID_ID2D1GradientStopCollection)] + public readonly unsafe struct GradientStopCollection : GradientStopCollection.Interface, IDisposable + { + internal readonly ID2D1GradientStopCollection* _handle; + + internal GradientStopCollection(ID2D1GradientStopCollection* collection) => _handle = collection; + + public Factory GetFactory() => Resource.From(this).GetFactory(); + + public Gamma GetColorInterpolationGamma() => (Gamma)_handle->GetColorInterpolationGamma(); + + public ExtendMode GetExtendMode() => (ExtendMode)_handle->GetExtendMode(); + + public uint GetGradientStopCount() => _handle->GetGradientStopCount(); + + public void GetGradientStops(Span gradientStops) + { + fixed(GradientStop* g = gradientStops) + { + _handle->GetGradientStops((D2D1_GRADIENT_STOP*)g, (uint)gradientStops.Length); + } + } + + public void Dispose() => _handle->Release(); + + internal interface Interface : Resource.Interface + { + /// + /// Returns the number of stops in the gradient. + /// + uint GetGradientStopCount(); + + /// + /// Copies the gradient stops from the collection into the caller's interface. The + /// returned colors have straight alpha. + /// + unsafe void GetGradientStops(Span gradientStops); + + /// + /// Returns whether the interpolation occurs with 1.0 or 2.2 gamma. + /// + Gamma GetColorInterpolationGamma(); + + ExtendMode GetExtendMode(); + } + } +} diff --git a/src/WInterop.DirectX/Direct2d/IBitmap.cs b/src/WInterop.DirectX/Direct2d/IBitmap.cs deleted file mode 100644 index 2ca4a478..00000000 --- a/src/WInterop.DirectX/Direct2d/IBitmap.cs +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) Jeremy W. Kuhne. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Drawing; -using System.Runtime.InteropServices; - -namespace WInterop.Direct2d -{ - /// - /// Root bitmap resource, linearly scaled on a draw call. [ID2D1Bitmap] - /// - [ComImport, - Guid(InterfaceIds.IID_ID2D1Bitmap), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IBitmap : IImage - { - #region ID2D1Resource - [PreserveSig] - new void GetFactory( - out IFactory factory); - #endregion - - /// - /// Returns the size of the bitmap in resolution independent units. - /// - [PreserveSig] - SizeF GetSize(); - - /// - /// Returns the size of the bitmap in resolution dependent units, (pixels). - /// - [PreserveSig] - SizeU GetPixelSize(); - - /// - /// Retrieve the format of the bitmap. - /// - [PreserveSig] - PixelFormat GetPixelFormat(); - - /// - /// Return the DPI of the bitmap. - /// - [PreserveSig] - void GetDpi( - out float dpiX, - out float dpiY); - - unsafe void CopyFromBitmap( - PointU* destPoint, - IBitmap bitmap, - LtrbRectangleU* srcRect); - - unsafe void CopyFromRenderTarget( - PointU* destPoint, - IRenderTarget renderTarget, - LtrbRectangleU* srcRect); - - unsafe void CopyFromMemory( - LtrbRectangleU* dstRect, - void* srcData, - uint pitch); - } -} diff --git a/src/WInterop.DirectX/Direct2d/IBitmapBrush.cs b/src/WInterop.DirectX/Direct2d/IBitmapBrush.cs deleted file mode 100644 index da0a3365..00000000 --- a/src/WInterop.DirectX/Direct2d/IBitmapBrush.cs +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (c) Jeremy W. Kuhne. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Numerics; -using System.Runtime.InteropServices; - -namespace WInterop.Direct2d -{ - /// - /// A bitmap brush allows a bitmap to be used to fill a geometry. [ID2D1BitmapBrush] - /// - [ComImport, - Guid(InterfaceIds.IID_ID2D1BitmapBrush), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IBitmapBrush : IBrush - { - #region ID2D1Resource - [PreserveSig] - new void GetFactory( - out IFactory factory); - #endregion - - #region ID2D1Brush - /// - /// Sets the opacity for when the brush is drawn over the entire fill of the brush. - /// - [PreserveSig] - new void SetOpacity( - float opacity); - - /// - /// Sets the transform that applies to everything drawn by the brush. - /// - [PreserveSig] - new void SetTransform( - ref Matrix3x2 transform); - - [PreserveSig] - new float GetOpacity(); - - [PreserveSig] - new void GetTransform( - out Matrix3x2 transform); - #endregion - - /// - /// Sets how the bitmap is to be treated outside of its natural extent on the X - /// axis. - /// - [PreserveSig] - void SetExtendModeX( - ExtendMode extendModeX); - - /// - /// Sets how the bitmap is to be treated outside of its natural extent on the X - /// axis. - /// - [PreserveSig] - void SetExtendModeY( - ExtendMode extendModeY); - - /// - /// Sets the interpolation mode used when this brush is used. - /// - [PreserveSig] - void SetInterpolationMode( - BitmapInterpolationMode interpolationMode); - - /// - /// Sets the bitmap associated as the source of this brush. - /// - [PreserveSig] - void SetBitmap( - IBitmap bitmap); - - [PreserveSig] - ExtendMode GetExtendModeX(); - - [PreserveSig] - ExtendMode GetExtendModeY(); - - [PreserveSig] - BitmapInterpolationMode GetInterpolationMode(); - - [PreserveSig] - void GetBitmap( - out IBitmap bitmap); - } -} diff --git a/src/WInterop.DirectX/Direct2d/IBitmapRenderTarget.cs b/src/WInterop.DirectX/Direct2d/IBitmapRenderTarget.cs index c08eb37f..685ae5b2 100644 --- a/src/WInterop.DirectX/Direct2d/IBitmapRenderTarget.cs +++ b/src/WInterop.DirectX/Direct2d/IBitmapRenderTarget.cs @@ -1,450 +1,10 @@ // Copyright (c) Jeremy W. Kuhne. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System; -using System.Drawing; -using System.Numerics; -using System.Runtime.InteropServices; -using WInterop.DirectWrite; - namespace WInterop.Direct2d { - /// - /// Renders to an intermediate texture created by the CreateCompatibleRenderTarget method. - /// [ID2D1BitmapRenderTarget] - /// - [ComImport, - Guid(InterfaceIds.IID_ID2D1BitmapRenderTarget), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public interface IBitmapRenderTarget : IRenderTarget { - #region ID2D1Resource - [PreserveSig] - new void GetFactory( - out IFactory factory); - #endregion - - #region ID2D1RenderTarget - /// - /// Create a D2D bitmap by copying from memory, or create uninitialized. - /// - new unsafe IBitmap CreateBitmap( - SizeU size, - void* srcData, - uint pitch, - in BitmapProperties bitmapProperties); - - /// - /// Create a D2D bitmap by copying a WIC bitmap. - /// - new unsafe IBitmap CreateBitmapFromWicBitmap( - object wicBitmapSource, // IWICBitmapSource - BitmapProperties* bitmapProperties); - - /// - /// Create a D2D bitmap by sharing bits from another resource. The bitmap must be - /// compatible with the render target for the call to succeed. For example, an - /// IWICBitmap can be shared with a software target, or a DXGI surface can be shared - /// with a DXGI render target. - /// - new unsafe IBitmap CreateSharedBitmap( - in Guid riid, - void* data, - BitmapProperties* bitmapProperties); - - /// - /// Creates a bitmap brush. The bitmap is scaled, rotated, skewed or tiled to fill - /// or pen a geometry. - /// - new unsafe IBitmapBrush CreateBitmapBrush( - IBitmap bitmap, - BitmapBrushProperties* bitmapBrushProperties, - BrushProperties* brushProperties); - - new unsafe ISolidColorBrush CreateSolidColorBrush( - in ColorF color, - BrushProperties* brushProperties); - - /// - /// A gradient stop collection represents a set of stops in an ideal unit length. - /// This is the source resource for a linear gradient and radial gradient brush. - /// - /// Specifies which space the color - /// interpolation occurs in. - /// Specifies how the gradient will be extended outside of - /// the unit length. - new unsafe IGradientStopCollection CreateGradientStopCollection( - GradientStop* gradientStops, - uint gradientStopsCount, - Gamma colorInterpolationGamma, - ExtendMode extendMode); - - new void CreateLinearGradientBrushSTUB(); - //STDMETHOD(CreateLinearGradientBrush)( - // _In_ CONST D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES *linearGradientBrushProperties, - // _In_opt_ CONST D2D1_BRUSH_PROPERTIES* brushProperties, - // _In_ ID2D1GradientStopCollection* gradientStopCollection, - // _COM_Outptr_ ID2D1LinearGradientBrush** linearGradientBrush - // ) PURE; - - new unsafe IRadialGradientBrush CreateRadialGradientBrush( - in RadialGradientBrushProperties radialGradientBrushProperties, - BrushProperties* brushProperties, - IGradientStopCollection gradientStopCollection); - - /// - /// Creates a bitmap render target whose bitmap can be used as a source for - /// rendering in the API. - /// - /// The requested size of the target in DIPs. If the pixel - /// size is not specified, the DPI is inherited from the parent target. However, the - /// render target will never contain a fractional number of pixels. - /// The requested size of the render target in - /// pixels. If the DIP size is also specified, the DPI is calculated from these two - /// values. If the desired size is not specified, the DPI is inherited from the - /// parent render target. If neither value is specified, the compatible render - /// target will be the same size and have the same DPI as the parent target. - /// The desired pixel format. The format must be - /// compatible with the parent render target type. If the format is not specified, - /// it will be inherited from the parent render target. - /// Allows the caller to retrieve a GDI compatible render - /// target. - /// The returned bitmap render target. - new unsafe IBitmapRenderTarget CreateCompatibleRenderTarget( - SizeF* desiredSize, - SizeU* desiredPixelSize, - PixelFormat* desiredFormat, - CompatibleRenderTargetOptions options); - - /// - /// Creates a layer resource that can be used on any target and which will resize - /// under the covers if necessary. - /// - /// The resolution independent minimum size hint for the layer - /// resource. Specify this to prevent unwanted reallocation of the layer backing - /// store. The size is in DIPs, but, it is unaffected by the current world - /// transform. If the size is unspecified, the returned resource is a placeholder - /// and the backing store will be allocated to be the minimum size that can hold the - /// content when the layer is pushed. - new void CreateLayerStub(); - //STDMETHOD(CreateLayer)( - // _In_opt_ CONST D2D1_SIZE_F *size, - // _COM_Outptr_ ID2D1Layer **layer - // ) PURE; - - /// - /// Create a D2D mesh. - /// - new void CreateMeshSTUB(); - //STDMETHOD(CreateMesh)( - // _COM_Outptr_ ID2D1Mesh ** mesh - // ) PURE; - - [PreserveSig] - new void DrawLine( - PointF point0, - PointF point1, - IBrush brush, - float strokeWidth = 1.0f, - IStrokeStyle strokeStyle = null); - - [PreserveSig] - new void DrawRectangle( - in LtrbRectangleF rect, - IBrush brush, - float strokeWidth = 1.0f, - IStrokeStyle strokeStyle = null); - - [PreserveSig] - new void FillRectangle( - in LtrbRectangleF rect, - IBrush brush); - - [PreserveSig] - new void DrawRoundedRectangle( - in RoundedRectangle roundedRect, - IBrush brush, - float strokeWidth = 1.0f, - IStrokeStyle strokeStyle = null); - - [PreserveSig] - new void FillRoundedRectangle( - in RoundedRectangle roundedRect, - IBrush brush); - - [PreserveSig] - new void DrawEllipse( - in Ellipse ellipse, - IBrush brush, - float strokeWidth = 1.0f, - IStrokeStyle strokeStyle = null); - - [PreserveSig] - new void FillEllipse( - in Ellipse ellipse, - IBrush brush); - - [PreserveSig] - new void DrawGeometry( - IGeometry geometry, - IBrush brush, - float strokeWidth = 1.0f, - IStrokeStyle strokeStyle = null); - - /// An optionally specified opacity brush. Only the alpha - /// channel of the corresponding brush will be sampled and will be applied to the - /// entire fill of the geometry. If this brush is specified, the fill brush must be - /// a bitmap brush with an extend mode of D2D1_EXTEND_MODE_CLAMP. - [PreserveSig] - new void FillGeometry( - IGeometry geometry, - IBrush brush, - IBrush opacityBrush = null); - - /// - /// Fill a mesh. Since meshes can only render aliased content, the render target - /// antialiasing mode must be set to aliased. - /// - new void FillMeshSTUB(); - //STDMETHOD_(void, FillMesh)( - // _In_ ID2D1Mesh * mesh, - // _In_ ID2D1Brush* brush - // ) PURE; - - /// - /// Fill using the alpha channel of the supplied opacity mask bitmap. The brush - /// opacity will be modulated by the mask. The render target antialiasing mode must - /// be set to aliased. - /// - new void FillOpacityMaskSTUB(); - //STDMETHOD_(void, FillOpacityMask)( - // _In_ ID2D1Bitmap * opacityMask, - // _In_ ID2D1Brush* brush, - // D2D1_OPACITY_MASK_CONTENT content, - // _In_opt_ CONST D2D1_RECT_F* destinationRectangle = NULL, - // _In_opt_ CONST D2D1_RECT_F *sourceRectangle = NULL - // ) PURE; - - [PreserveSig] - new unsafe void DrawBitmap( - IBitmap bitmap, - LtrbRectangleF* destinationRectangle = null, - float opacity = 1.0f, - BitmapInterpolationMode interpolationMode = BitmapInterpolationMode.Linear, - LtrbRectangleF* sourceRectangle = null); - - /// - /// Draws the text within the given layout rectangle and by default also performs - /// baseline snapping. - /// - [PreserveSig] - new unsafe void DrawText( - char* @string, - uint stringLength, - ITextFormat textFormat, - in LtrbRectangleF layoutRect, - IBrush defaultFillBrush, - DrawTextOptions options = DrawTextOptions.None, - MeasuringMode measuringMode = MeasuringMode.Natural); - - /// - /// Draw a text layout object. If the layout is not subsequently changed, this can - /// be more efficient than DrawText when drawing the same layout repeatedly. - /// - /// - /// The specified text options. If is used, the text - /// is clipped to the layout bounds. These bounds are derived from the origin and the - /// layout bounds of the corresponding object. - /// - [PreserveSig] - new void DrawTextLayout( - PointF origin, - ITextLayout textLayout, - IBrush defaultFillBrush, - DrawTextOptions options = DrawTextOptions.None); - - [PreserveSig] - new void DrawGlyphRun( - PointF baselineOrigin, - in GlyphRun glyphRun, - IBrush foregroundBrush, - MeasuringMode measuringMode = MeasuringMode.Natural); - - [PreserveSig] - new void SetTransform( - ref Matrix3x2 transform); - - [PreserveSig] - new void GetTransform( - out Matrix3x2 transform); - - [PreserveSig] - new void SetAntialiasMode( - AntialiasMode antialiasMode); - - [PreserveSig] - new AntialiasMode GetAntialiasMode(); - - [PreserveSig] - new void SetTextAntialiasMode( - TextAntialiasMode textAntialiasMode); - - [PreserveSig] - new TextAntialiasMode GetTextAntialiasMode(); - - [PreserveSig] - new void SetTextRenderingParams( - DirectWrite.IRenderingParams textRenderingParams = null); - - /// - /// Retrieve the text render parameters. NOTE: If NULL is specified to - /// SetTextRenderingParameters, NULL will be returned. - /// - [PreserveSig] - new void GetTextRenderingParams( - out DirectWrite.IRenderingParams textRenderingParams); - - /// - /// Set a tag to correspond to the succeeding primitives. If an error occurs - /// rendering a primitive, the tags can be returned from the Flush or EndDraw call. - /// - [PreserveSig] - new void SetTags( - ulong tag1, - ulong tag2); - - /// - /// Retrieves the currently set tags. This does not retrieve the tags corresponding - /// to any primitive that is in error. - /// - [PreserveSig] - new void GetTags( - out ulong tag1, - out ulong tag2); - - /// - /// Start a layer of drawing calls. The way in which the layer must be resolved is - /// specified first as well as the logical resource that stores the layer - /// parameters. The supplied layer resource might grow if the specified content - /// cannot fit inside it. The layer will grow monotonically on each axis. If a NULL - /// ID2D1Layer is provided, then a layer resource will be allocated automatically. - /// - new void PushLayerSTUB(); - //STDMETHOD_(void, PushLayer)( - // _In_ CONST D2D1_LAYER_PARAMETERS *layerParameters, - //_In_opt_ ID2D1Layer *layer - //) PURE; - - /// - /// Ends a layer that was defined with particular layer resources. - /// - [PreserveSig] - new void PopLayer(); - - new void Flush( - out ulong tag1, - out ulong tag2); - - /// - /// Gets the current drawing state and saves it into the supplied - /// IDrawingStatckBlock. - /// - [PreserveSig] - new void SaveDrawingState( - IDrawingStateBlock drawingStateBlock); - - /// - /// Copies the state stored in the block interface. - /// - [PreserveSig] - new void RestoreDrawingState( - IDrawingStateBlock drawingStateBlock); - - /// - /// Pushes a clip. The clip can be antialiased. The clip must be axis aligned. If - /// the current world transform is not axis preserving, then the bounding box of the - /// transformed clip rect will be used. The clip will remain in effect until a - /// PopAxisAligned clip call is made. - /// - [PreserveSig] - new void PushAxisAlignedClip( - in LtrbRectangleF clipRect, - AntialiasMode antialiasMode); - - [PreserveSig] - new void PopAxisAlignedClip(); - - [PreserveSig] - new unsafe void Clear( - ColorF* clearColor = null); - - /// - /// Start drawing on this render target. Draw calls can only be issued between a - /// BeginDraw and EndDraw call. - /// - [PreserveSig] - new void BeginDraw(); - - /// - /// Ends drawing on the render target, error results can be retrieved at this time, - /// or when calling flush. - /// - new void EndDraw( - out ulong tag1, - out ulong tag2); - - [PreserveSig] - new void GetPixelFormat(out PixelFormat pixelFormat); - - /// - /// Sets the DPI on the render target. This results in the render target being - /// interpreted to a different scale. Neither DPI can be negative. If zero is - /// specified for both, the system DPI is chosen. If one is zero and the other - /// unspecified, the DPI is not changed. - /// - [PreserveSig] - new void SetDpi( - float dpiX, - float dpiY); - - /// - /// Return the current DPI from the target. - /// - [PreserveSig] - new void GetDpi( - out float dpiX, - out float dpiY); - - /// - /// Returns the size of the render target in DIPs. - /// - [PreserveSig] - new void GetSize(out SizeF size); - - /// - /// Returns the size of the render target in pixels. - /// - [PreserveSig] - new SizeU GetPixelSize(out SizeU pixelSize); - - /// - /// Returns the maximum bitmap and render target size that is guaranteed to be - /// supported by the render target. - /// - [PreserveSig] - new uint GetMaximumBitmapSize(); - - /// - /// Returns true if the given properties are supported by this render target. The - /// DPI is ignored. NOTE: If the render target type is software, then neither - /// D2D1_FEATURE_LEVEL_9 nor D2D1_FEATURE_LEVEL_10 will be considered to be - /// supported. - /// - [PreserveSig] - new IntBoolean IsSupported( - in RenderTargetProperties renderTargetProperties); - #endregion - - IBitmap GetBitmap(); + Bitmap Bitmap { get; } } } diff --git a/src/WInterop.DirectX/Direct2d/IBrush.cs b/src/WInterop.DirectX/Direct2d/IBrush.cs deleted file mode 100644 index 7c93ccb4..00000000 --- a/src/WInterop.DirectX/Direct2d/IBrush.cs +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) Jeremy W. Kuhne. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Numerics; -using System.Runtime.InteropServices; - -namespace WInterop.Direct2d -{ - /// - /// The root brush interface. All brushes can be used to fill or pen a geometry. - /// [ID2D1Brush] - /// - [ComImport, - Guid(InterfaceIds.IID_ID2D1Brush), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IBrush : IResource - { - #region ID2D1Resource - [PreserveSig] - new void GetFactory( - out IFactory factory); - #endregion - - /// - /// Sets the opacity for when the brush is drawn over the entire fill of the brush. - /// - [PreserveSig] - void SetOpacity( - float opacity); - - /// - /// Sets the transform that applies to everything drawn by the brush. - /// - [PreserveSig] - void SetTransform( - ref Matrix3x2 transform); - - [PreserveSig] - float GetOpacity(); - - [PreserveSig] - void GetTransform( - out Matrix3x2 transform); - } -} diff --git a/src/WInterop.DirectX/Direct2d/IDeviceContextRenderTarget.cs b/src/WInterop.DirectX/Direct2d/IDeviceContextRenderTarget.cs index c7cec489..2297fc3e 100644 --- a/src/WInterop.DirectX/Direct2d/IDeviceContextRenderTarget.cs +++ b/src/WInterop.DirectX/Direct2d/IDeviceContextRenderTarget.cs @@ -1,443 +1,17 @@ // Copyright (c) Jeremy W. Kuhne. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System; using System.Drawing; -using System.Numerics; -using System.Runtime.InteropServices; -using WInterop.DirectWrite; using WInterop.Gdi; using WInterop.Gdi.Native; namespace WInterop.Direct2d { - // ID2D1DCRenderTarget - [ComImport, - Guid(InterfaceIds.IID_ID2D1DCRenderTarget), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public interface IDeviceContextRenderTarget : IRenderTarget { - #region ID2D1Resource - [PreserveSig] - new void GetFactory( - out IFactory factory); - #endregion - - #region ID2D1RenderTarget - /// - /// Create a D2D bitmap by copying from memory, or create uninitialized. - /// - new unsafe IBitmap CreateBitmap( - SizeU size, - void* srcData, - uint pitch, - in BitmapProperties bitmapProperties); - - /// - /// Create a D2D bitmap by copying a WIC bitmap. - /// - new unsafe IBitmap CreateBitmapFromWicBitmap( - object wicBitmapSource, // IWICBitmapSource - BitmapProperties* bitmapProperties); - - /// - /// Create a D2D bitmap by sharing bits from another resource. The bitmap must be compatible with the render - /// target for the call to succeed. For example, an IWICBitmap can be shared with a software target, or a - /// DXGI surface can be shared with a DXGI render target. - /// - new unsafe IBitmap CreateSharedBitmap( - in Guid riid, - void* data, - BitmapProperties* bitmapProperties); - - /// - /// Creates a bitmap brush. The bitmap is scaled, rotated, skewed or tiled to fill or pen a geometry. - /// - new unsafe IBitmapBrush CreateBitmapBrush( - IBitmap bitmap, - BitmapBrushProperties* bitmapBrushProperties, - BrushProperties* brushProperties); - - new unsafe ISolidColorBrush CreateSolidColorBrush( - in ColorF color, - BrushProperties* brushProperties); - - /// - /// A gradient stop collection represents a set of stops in an ideal unit length. This is the source resource - /// for a linear gradient and radial gradient brush. - /// - /// Specifies which space the color interpolation occurs in. - /// Specifies how the gradient will be extended outside of the unit length. - new unsafe IGradientStopCollection CreateGradientStopCollection( - GradientStop* gradientStops, - uint gradientStopsCount, - Gamma colorInterpolationGamma, - ExtendMode extendMode); - - new void CreateLinearGradientBrushSTUB(); - //STDMETHOD(CreateLinearGradientBrush)( - // _In_ CONST D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES *linearGradientBrushProperties, - // _In_opt_ CONST D2D1_BRUSH_PROPERTIES* brushProperties, - // _In_ ID2D1GradientStopCollection* gradientStopCollection, - // _COM_Outptr_ ID2D1LinearGradientBrush** linearGradientBrush - // ) PURE; - - new unsafe IRadialGradientBrush CreateRadialGradientBrush( - in RadialGradientBrushProperties radialGradientBrushProperties, - BrushProperties* brushProperties, - IGradientStopCollection gradientStopCollection); - - /// - /// Creates a bitmap render target whose bitmap can be used as a source for rendering in the API. - /// - /// - /// The requested size of the target in DIPs. If the pixel size is not specified, the DPI is inherited from - /// the parent target. However, the render target will never contain a fractional number of pixels. - /// - /// - /// The requested size of the render target in pixels. If the DIP size is also specified, the DPI is - /// calculated from these two values. If the desired size is not specified, the DPI is inherited from the - /// parent render target. If neither value is specified, the compatible render target will be the same size - /// and have the same DPI as the parent target. - /// - /// - /// The desired pixel format. The format must be compatible with the parent render target type. If the format - /// is not specified, it will be inherited from the parent render target. - /// - /// Allows the caller to retrieve a GDI compatible render target. - /// The returned bitmap render target. - new unsafe IBitmapRenderTarget CreateCompatibleRenderTarget( - SizeF* desiredSize, - SizeU* desiredPixelSize, - PixelFormat* desiredFormat, - CompatibleRenderTargetOptions options); - - /// - /// Creates a layer resource that can be used on any target and which will resize under the covers if necessary. - /// - /// - /// The resolution independent minimum size hint for the layer resource. Specify this to prevent unwanted - /// reallocation of the layer backing store. The size is in DIPs, but, it is unaffected by the current world - /// transform. If the size is unspecified, the returned resource is a placeholder and the backing store will - /// be allocated to be the minimum size that can hold the content when the layer is pushed. - /// - new void CreateLayerStub(); - //STDMETHOD(CreateLayer)( - // _In_opt_ CONST D2D1_SIZE_F *size, - // _COM_Outptr_ ID2D1Layer **layer - // ) PURE; - - /// - /// Create a D2D mesh. - /// - new void CreateMeshSTUB(); - //STDMETHOD(CreateMesh)( - // _COM_Outptr_ ID2D1Mesh ** mesh - // ) PURE; - - [PreserveSig] - new void DrawLine( - PointF point0, - PointF point1, - IBrush brush, - float strokeWidth = 1.0f, - IStrokeStyle strokeStyle = null); - - [PreserveSig] - new void DrawRectangle( - in LtrbRectangleF rect, - IBrush brush, - float strokeWidth = 1.0f, - IStrokeStyle strokeStyle = null); - - [PreserveSig] - new void FillRectangle( - in LtrbRectangleF rect, - IBrush brush); - - [PreserveSig] - new void DrawRoundedRectangle( - in RoundedRectangle roundedRect, - IBrush brush, - float strokeWidth = 1.0f, - IStrokeStyle strokeStyle = null); - - [PreserveSig] - new void FillRoundedRectangle( - in RoundedRectangle roundedRect, - IBrush brush); - - [PreserveSig] - new void DrawEllipse( - in Ellipse ellipse, - IBrush brush, - float strokeWidth = 1.0f, - IStrokeStyle strokeStyle = null); - - [PreserveSig] - new void FillEllipse( - in Ellipse ellipse, - IBrush brush); - - [PreserveSig] - new void DrawGeometry( - IGeometry geometry, - IBrush brush, - float strokeWidth = 1.0f, - IStrokeStyle strokeStyle = null); - - /// - /// An optionally specified opacity brush. Only the alpha channel of the corresponding brush will be sampled - /// and will be applied to the entire fill of the geometry. If this brush is specified, the fill brush must be - /// a bitmap brush with an extend mode of D2D1_EXTEND_MODE_CLAMP. - /// - [PreserveSig] - new void FillGeometry( - IGeometry geometry, - IBrush brush, - IBrush opacityBrush = null); - - /// - /// Fill a mesh. Since meshes can only render aliased content, the render target antialiasing mode must be - /// set to aliased. - /// - new void FillMeshSTUB(); - //STDMETHOD_(void, FillMesh)( - // _In_ ID2D1Mesh * mesh, - // _In_ ID2D1Brush* brush - // ) PURE; - - /// - /// Fill using the alpha channel of the supplied opacity mask bitmap. The brush opacity will be modulated by - /// the mask. The render target antialiasing mode must be set to aliased. - /// - new void FillOpacityMaskSTUB(); - //STDMETHOD_(void, FillOpacityMask)( - // _In_ ID2D1Bitmap * opacityMask, - // _In_ ID2D1Brush* brush, - // D2D1_OPACITY_MASK_CONTENT content, - // _In_opt_ CONST D2D1_RECT_F* destinationRectangle = NULL, - // _In_opt_ CONST D2D1_RECT_F *sourceRectangle = NULL - // ) PURE; - - [PreserveSig] - new unsafe void DrawBitmap( - IBitmap bitmap, - LtrbRectangleF* destinationRectangle = null, - float opacity = 1.0f, - BitmapInterpolationMode interpolationMode = BitmapInterpolationMode.Linear, - LtrbRectangleF* sourceRectangle = null); - - /// - /// Draws the text within the given layout rectangle and by default also performs baseline snapping. - /// - /// - /// Draws the text within the given layout rectangle and by default also performs baseline snapping. - /// - [PreserveSig] - new unsafe void DrawText( - char* @string, - uint stringLength, - ITextFormat textFormat, - in LtrbRectangleF layoutRect, - IBrush defaultFillBrush, - DrawTextOptions options = DrawTextOptions.None, - MeasuringMode measuringMode = MeasuringMode.Natural); - - /// - /// Draw a text layout object. If the layout is not subsequently changed, this can be more efficient than - /// DrawText when drawing the same layout repeatedly. - /// - /// - /// The specified text options. If is used, the text is clipped to the - /// layout bounds. These bounds are derived from the origin and the layout bounds of the corresponding - /// object. - /// - [PreserveSig] - new void DrawTextLayout( - PointF origin, - ITextLayout textLayout, - IBrush defaultFillBrush, - DrawTextOptions options = DrawTextOptions.None); - - [PreserveSig] - new void DrawGlyphRun( - PointF baselineOrigin, - in GlyphRun glyphRun, - IBrush foregroundBrush, - MeasuringMode measuringMode = MeasuringMode.Natural); - - [PreserveSig] - new void SetTransform( - ref Matrix3x2 transform); - - [PreserveSig] - new void GetTransform( - out Matrix3x2 transform); - - [PreserveSig] - new void SetAntialiasMode( - AntialiasMode antialiasMode); - - [PreserveSig] - new AntialiasMode GetAntialiasMode(); - - [PreserveSig] - new void SetTextAntialiasMode( - TextAntialiasMode textAntialiasMode); - - [PreserveSig] - new TextAntialiasMode GetTextAntialiasMode(); - - [PreserveSig] - new void SetTextRenderingParams( - DirectWrite.IRenderingParams textRenderingParams = null); - - /// - /// Retrieve the text render parameters. NOTE: If NULL is specified to SetTextRenderingParameters, NULL - /// will be returned. - /// - [PreserveSig] - new void GetTextRenderingParams( - out DirectWrite.IRenderingParams textRenderingParams); - - /// - /// Set a tag to correspond to the succeeding primitives. If an error occurs rendering a primitive, the tags - /// can be returned from the Flush or EndDraw call. - /// - [PreserveSig] - new void SetTags( - ulong tag1, - ulong tag2); - - /// - /// Retrieves the currently set tags. This does not retrieve the tags corresponding to any primitive that - /// is in error. - /// - [PreserveSig] - new void GetTags( - out ulong tag1, - out ulong tag2); - - /// - /// Start a layer of drawing calls. The way in which the layer must be resolved is specified first as well as - /// the logical resource that stores the layer parameters. The supplied layer resource might grow if the - /// specified content cannot fit inside it. The layer will grow monotonically on each axis. If a NULL - /// ID2D1Layer is provided, then a layer resource will be allocated automatically. - /// - new void PushLayerSTUB(); - //STDMETHOD_(void, PushLayer)( - // _In_ CONST D2D1_LAYER_PARAMETERS *layerParameters, - //_In_opt_ ID2D1Layer *layer - //) PURE; - - /// - /// Ends a layer that was defined with particular layer resources. - /// - [PreserveSig] - new void PopLayer(); - - new void Flush( - out ulong tag1, - out ulong tag2); - - /// - /// Gets the current drawing state and saves it into the supplied IDrawingStatckBlock. - /// - [PreserveSig] - new void SaveDrawingState( - IDrawingStateBlock drawingStateBlock); - - /// - /// Copies the state stored in the block interface. - /// - [PreserveSig] - new void RestoreDrawingState( - IDrawingStateBlock drawingStateBlock); - - /// - /// Pushes a clip. The clip can be antialiased. The clip must be axis aligned. If the current world transform - /// is not axis preserving, then the bounding box of the transformed clip rect will be used. The clip will - /// remain in effect until a PopAxisAligned clip call is made. - /// - [PreserveSig] - new void PushAxisAlignedClip( - in LtrbRectangleF clipRect, - AntialiasMode antialiasMode); - - [PreserveSig] - new void PopAxisAlignedClip(); - - [PreserveSig] - new unsafe void Clear( - ColorF* clearColor = null); - - /// - /// Start drawing on this render target. Draw calls can only be issued between a BeginDraw and EndDraw call. - /// - [PreserveSig] - new void BeginDraw(); - - /// - /// Ends drawing on the render target, error results can be retrieved at this time, or when calling flush. - /// - new void EndDraw( - out ulong tag1, - out ulong tag2); - - [PreserveSig] - new void GetPixelFormat(out PixelFormat pixelFormat); - - /// - /// Sets the DPI on the render target. This results in the render target being interpreted to a different - /// scale. Neither DPI can be negative. If zero is specified for both, the system DPI is chosen. If one is - /// zero and the other unspecified, the DPI is not changed. - /// - [PreserveSig] - new void SetDpi( - float dpiX, - float dpiY); - - /// - /// Return the current DPI from the target. - /// - [PreserveSig] - new void GetDpi( - out float dpiX, - out float dpiY); - - /// - /// Returns the size of the render target in DIPs. - /// - [PreserveSig] - new void GetSize(out SizeF size); - - /// - /// Returns the size of the render target in pixels. - /// - [PreserveSig] - new SizeU GetPixelSize(out SizeU pixelSize); - - /// - /// Returns the maximum bitmap and render target size that is guaranteed to be supported by the render target. - /// - [PreserveSig] - new uint GetMaximumBitmapSize(); - - /// - /// Returns true if the given properties are supported by this render target. The DPI is ignored. NOTE: If - /// the render target type is software, then neither D2D1_FEATURE_LEVEL_9 nor D2D1_FEATURE_LEVEL_10 will be - /// considered to be supported. - /// - [PreserveSig] - new IntBoolean IsSupported( - in RenderTargetProperties renderTargetProperties); - #endregion - - [PreserveSig] void BindDC( - HDC hDC, - in Rect pSubRect); + HDC deviceContext, + Rect subRectangle); } public static class DeviceContextRenderTargetExtensions diff --git a/src/WInterop.DirectX/Direct2d/IDrawingStateBlock.cs b/src/WInterop.DirectX/Direct2d/IDrawingStateBlock.cs index 680697e1..d71f0e9f 100644 --- a/src/WInterop.DirectX/Direct2d/IDrawingStateBlock.cs +++ b/src/WInterop.DirectX/Direct2d/IDrawingStateBlock.cs @@ -11,45 +11,50 @@ namespace WInterop.Direct2d /// Represents the drawing state of a render target: the antialiasing mode, /// transform, tags, and text-rendering options. [ID2D1DrawingStateBlock] /// - [ComImport, - Guid(InterfaceIds.IID_ID2D1DrawingStateBlock), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IDrawingStateBlock : IResource + [Guid(InterfaceIds.IID_ID2D1DrawingStateBlock)] + public readonly unsafe struct DrawingStateBlock : DrawingStateBlock.Interface, IDisposable { - #region ID2D1Resource - [PreserveSig] - new void GetFactory( - out IFactory factory); - #endregion - - /// - /// Retrieves the state currently contained within this state block resource. - /// - [PreserveSig] - void GetDescription( - out DrawingStateDescription stateDescription); - - /// - /// Sets the state description of this state block resource. - /// - [PreserveSig] - void SetDescription( - in DrawingStateDescription stateDescription); - - /// - /// Sets the text rendering parameters of this state block resource. - /// - [PreserveSig] - void SetTextRenderingParams( - IRenderingParams textRenderingParams); - - /// - /// Retrieves the text rendering parameters contained within this state block - /// resource. If a NULL text rendering parameter was specified, NULL will be - /// returned. - /// - [PreserveSig] - void GetTextRenderingParams( - out IRenderingParams textRenderingParams); + private readonly ID2D1DrawingStateBlock* _handle; + + internal DrawingStateBlock(ID2D1DrawingStateBlock* handle) => _handle = handle; + + public DrawingStateDescription Description + { + get + { + DrawingStateDescription description; + _handle->GetDescription((D2D1_DRAWING_STATE_DESCRIPTION*)&description); + return description; + } + set => _handle->SetDescription((D2D1_DRAWING_STATE_DESCRIPTION*)&value); + } + + public RenderingParams TextRenderingParams + { + get + { + IDWriteRenderingParams* rendering; + _handle->GetTextRenderingParams(&rendering); + return new(rendering); + } + set => _handle->SetTextRenderingParams(value.Handle); + } + + public void Dispose() => _handle->Release(); + + public Factory GetFactory() => Resource.From(this).GetFactory(); + + internal interface Interface : Resource.Interface + { + /// + /// Gets/sets the state description of this state block resource. + /// + DrawingStateDescription Description { get; set; } + + /// + /// Gets/Sets the text rendering parameters of this state block resource. + /// + RenderingParams TextRenderingParams { get; set; } + } } } diff --git a/src/WInterop.DirectX/Direct2d/IEllipseGeometry.cs b/src/WInterop.DirectX/Direct2d/IEllipseGeometry.cs deleted file mode 100644 index b74b7c2b..00000000 --- a/src/WInterop.DirectX/Direct2d/IEllipseGeometry.cs +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright (c) Jeremy W. Kuhne. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Drawing; -using System.Runtime.InteropServices; -using System.Numerics; - -namespace WInterop.Direct2d -{ - /// - /// [ID2D1EllipseGeometry] - /// - [ComImport, - Guid(InterfaceIds.IID_ID2D1ElipseGeometry), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public unsafe interface IEllipseGeometry : IGeometry - { - #region ID2D1Resource - [PreserveSig] - new void GetFactory( - out IFactory factory); - #endregion - - #region ID2D1Geometry - /// - /// Retrieve the bounds of the geometry, with an optional applied transform. - /// - new LtrbRectangleF GetBounds( - Matrix3x2* worldTransform); - - /// - /// Get the bounds of the corresponding geometry after it has been widened or have - /// an optional pen style applied. - /// - new LtrbRectangleF GetWidenedBounds( - float strokeWidth, - IStrokeStyle strokeStyle, - Matrix3x2* worldTransform, - float flatteningTolerance); - - /// - /// Checks to see whether the corresponding penned and widened geometry contains the - /// given point. - /// - new IntBoolean StrokeContainsPoint( - PointF point, - float strokeWidth, - IStrokeStyle strokeStyle, - Matrix3x2* worldTransform, - float flatteningTolerance); - - /// - /// Test whether the given fill of this geometry would contain this point. - /// - new IntBoolean FillContainsPoint( - PointF point, - Matrix3x2* worldTransform, - float flatteningTolerance); - - /// - /// Compare how one geometry intersects or contains another geometry. - /// - new GeometryRelation CompareWithGeometry( - IGeometry inputGeometry, - Matrix3x2* inputGeometryTransform, - float flatteningTolerance); - - /// - /// Converts a geometry to a simplified geometry that has arcs and quadratic beziers - /// removed. - /// - new void Simplify( - GeometrySimplificationOption simplificationOption, - Matrix3x2* worldTransform, - float flatteningTolerance, - ISimplifiedGeometrySink geometrySink); - - /// - /// Tessellates a geometry into triangles. - /// - new void Tessellate( - Matrix3x2* worldTransform, - float flatteningTolerance, - ITesselationSink tessellationSink); - - /// - /// Performs a combine operation between the two geometries to produce a resulting - /// geometry. - /// - new void CombineWithGeometry( - IGeometry inputGeometry, - CombineMode combineMode, - Matrix3x2* inputGeometryTransform, - float flatteningTolerance, - ISimplifiedGeometrySink geometrySink); - - /// - /// Computes the outline of the geometry. The result is written back into a - /// simplified geometry sink. - /// - new void Outline( - Matrix3x2* worldTransform, - float flatteningTolerance, - ISimplifiedGeometrySink geometrySink); - - /// - /// Computes the area of the geometry. - /// - new float ComputeArea( - Matrix3x2* worldTransform, - float flatteningTolerance); - - /// - /// Computes the length of the geometry. - /// - new float ComputeLength( - Matrix3x2* worldTransform, - float flatteningTolerance); - - /// - /// Computes the point and tangent a given distance along the path. - /// - new void ComputePointAtLength( - float length, - Matrix3x2* worldTransform, - float flatteningTolerance, - PointF* point, - PointF* unitTangentVector); - - /// - /// Get the geometry and widen it as well as apply an optional pen style. - /// - new void Widen( - float strokeWidth, - IStrokeStyle strokeStyle, - Matrix3x2* worldTransform, - float flatteningTolerance, - ISimplifiedGeometrySink geometrySink); - #endregion - - [PreserveSig] - void GetEllipse(out Ellipse ellipse); - } -} diff --git a/src/WInterop.DirectX/Direct2d/IFactory.cs b/src/WInterop.DirectX/Direct2d/IFactory.cs deleted file mode 100644 index 8b0981ed..00000000 --- a/src/WInterop.DirectX/Direct2d/IFactory.cs +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright (c) Jeremy W. Kuhne. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Numerics; -using System.Runtime.InteropServices; -using WInterop.DirectWrite; - -namespace WInterop.Direct2d -{ - /// - /// [ID2D1Factory] - /// - /// - /// - /// - [ComImport, - Guid(InterfaceIds.IID_ID2D1Factory), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IFactory - { - /// - /// Cause the factory to refresh any system metrics that it might have been snapped - /// on factory creation. - /// - void ReloadSystemMetrics(); - - /// - /// Retrieves the current desktop DPI. To refresh this, call ReloadSystemMetrics. - /// Note: this method is deprecated. Use DisplayProperties::LogicalDpi for Windows - /// Store Apps and GetDpiForWindow for Win32 Apps. - /// - [PreserveSig] - void GetDesktopDpi( - out float dpiX, - out float dpiY); - - IRectangleGeometry CreateRectangleGeometry( - in LtrbRectangleF rectangle); - - IRoundedRectangleGeometry CreateRoundedRectangleGeometry( - in RoundedRectangle roundedRectangle); - - IEllipseGeometry CreateEllipseGeometry( - in Ellipse ellipse); - - /// - /// Create a geometry which holds other geometries. - /// - IGeometryGroup CreateGeometryGroup( - FillMode fillMode, - IGeometry[] geometries, - uint geometriesCount); - - ITransformedGeometry CreateTransformedGeometry( - IGeometry sourceGeometry, - ref Matrix3x2 transform); - - /// - /// Returns an initially empty path geometry interface. A geometry sink is created - /// off the interface to populate it. - /// - IPathGeometry CreatePathGeometry(); - - /// - /// Allows a non-default stroke style to be specified for a given geometry at draw - /// time. - /// - unsafe IStrokeStyle CreateStrokeStyle( - in StrokeStyleProperties strokeStyleProperties, - float* dashes, - uint dashesCount); - - /// - /// Creates a new drawing state block, this can be used in subsequent - /// SaveDrawingState and RestoreDrawingState operations on the render target. - /// - IDrawingStateBlock CreateDrawingStateBlock( - in DrawingStateDescription drawingStateDescription, - IRenderingParams textRenderingParams); - - /// - /// Creates a render target which is a source of bitmaps. - /// - void CreateWicBitmapRenderTargetSTUB(); - //STDMETHOD(CreateWicBitmapRenderTarget)( - // _In_ IWICBitmap * target, - // _In_ CONST D2D1_RENDER_TARGET_PROPERTIES *renderTargetProperties, - //_COM_Outptr_ ID2D1RenderTarget **renderTarget - //) PURE; - - /// - /// Creates a render target that appears on the display. [CreateHwndRenderTarget] - /// - IWindowRenderTarget CreateWindowRenderTarget( - in RenderTargetProperties renderTargetProperties, - in WindowRenderTargetProperties hwndRenderTargetProperties); - - /// - /// Creates a render target that draws to a DXGI Surface. The device that owns the - /// surface is used for rendering. - /// - void CreateDxgiSurfaceRenderTargetSTUB(); - //STDMETHOD(CreateDxgiSurfaceRenderTarget)( - // _In_ IDXGISurface * dxgiSurface, - // _In_ CONST D2D1_RENDER_TARGET_PROPERTIES *renderTargetProperties, - // _COM_Outptr_ ID2D1RenderTarget **renderTarget - // ) PURE; - - // TODO: really ID2D1DCRenderTarget - /// - /// Creates a render target that draws to a GDI device context. - /// - IRenderTarget CreateDCRenderTarget( - in RenderTargetProperties renderTargetProperties); - } - - public static class FactoryExtensions - { - public unsafe static IStrokeStyle CreateStrokeStyle( - this IFactory factory, - in StrokeStyleProperties strokeStyleProperties) - => factory.CreateStrokeStyle(strokeStyleProperties, null, 0); - } -} diff --git a/src/WInterop.DirectX/Direct2d/IGeometry.cs b/src/WInterop.DirectX/Direct2d/IGeometry.cs deleted file mode 100644 index c92eede8..00000000 --- a/src/WInterop.DirectX/Direct2d/IGeometry.cs +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright (c) Jeremy W. Kuhne. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Drawing; -using System.Numerics; -using System.Runtime.InteropServices; - -namespace WInterop.Direct2d -{ - /// - /// [ID2D1Geometry] - /// - [ComImport, - Guid(InterfaceIds.IID_ID2D1Geometry), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public unsafe interface IGeometry : IResource - { - // ID2D1Resource - [PreserveSig] - new void GetFactory( - out IFactory factory); - - /// - /// Retrieve the bounds of the geometry, with an optional applied transform. - /// - LtrbRectangleF GetBounds( - Matrix3x2* worldTransform); - - /// - /// Get the bounds of the corresponding geometry after it has been widened or have - /// an optional pen style applied. - /// - LtrbRectangleF GetWidenedBounds( - float strokeWidth, - IStrokeStyle strokeStyle, - Matrix3x2* worldTransform, - float flatteningTolerance); - - /// - /// Checks to see whether the corresponding penned and widened geometry contains the - /// given point. - /// - IntBoolean StrokeContainsPoint( - PointF point, - float strokeWidth, - IStrokeStyle strokeStyle, - Matrix3x2* worldTransform, - float flatteningTolerance); - - /// - /// Test whether the given fill of this geometry would contain this point. - /// - IntBoolean FillContainsPoint( - PointF point, - Matrix3x2* worldTransform, - float flatteningTolerance); - - /// - /// Compare how one geometry intersects or contains another geometry. - /// - GeometryRelation CompareWithGeometry( - IGeometry inputGeometry, - Matrix3x2* inputGeometryTransform, - float flatteningTolerance); - - /// - /// Converts a geometry to a simplified geometry that has arcs and quadratic beziers - /// removed. - /// - void Simplify( - GeometrySimplificationOption simplificationOption, - Matrix3x2* worldTransform, - float flatteningTolerance, - ISimplifiedGeometrySink geometrySink); - - /// - /// Tessellates a geometry into triangles. - /// - void Tessellate( - Matrix3x2* worldTransform, - float flatteningTolerance, - ITesselationSink tessellationSink); - - /// - /// Performs a combine operation between the two geometries to produce a resulting - /// geometry. - /// - void CombineWithGeometry( - IGeometry inputGeometry, - CombineMode combineMode, - Matrix3x2* inputGeometryTransform, - float flatteningTolerance, - ISimplifiedGeometrySink geometrySink); - - /// - /// Computes the outline of the geometry. The result is written back into a - /// simplified geometry sink. - /// - void Outline( - Matrix3x2* worldTransform, - float flatteningTolerance, - ISimplifiedGeometrySink geometrySink); - - /// - /// Computes the area of the geometry. - /// - float ComputeArea( - Matrix3x2* worldTransform, - float flatteningTolerance); - - /// - /// Computes the length of the geometry. - /// - float ComputeLength( - Matrix3x2* worldTransform, - float flatteningTolerance); - - /// - /// Computes the point and tangent a given distance along the path. - /// - void ComputePointAtLength( - float length, - Matrix3x2* worldTransform, - float flatteningTolerance, - PointF* point, - PointF* unitTangentVector); - - /// - /// Get the geometry and widen it as well as apply an optional pen style. - /// - void Widen( - float strokeWidth, - IStrokeStyle strokeStyle, - Matrix3x2* worldTransform, - float flatteningTolerance, - ISimplifiedGeometrySink geometrySink); - } - - public static class GeometryExtensions - { - /// - /// Retrieve the bounds of the geometry. - /// - public static unsafe RectangleF GetBounds(this IGeometry geometry) => geometry.GetBounds(null); - - /// - /// Retrieve the bounds of the geometry with a transform. - /// - public static unsafe RectangleF GetBounds(this IGeometry geometry, Matrix3x2 worldTransform) - => geometry.GetBounds(&worldTransform); - } -} diff --git a/src/WInterop.DirectX/Direct2d/IGeometryGroup.cs b/src/WInterop.DirectX/Direct2d/IGeometryGroup.cs deleted file mode 100644 index 96295fa0..00000000 --- a/src/WInterop.DirectX/Direct2d/IGeometryGroup.cs +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright (c) Jeremy W. Kuhne. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Drawing; -using System.Numerics; -using System.Runtime.InteropServices; - -namespace WInterop.Direct2d -{ - /// - /// [ID2D1GeometryGroup] - /// - [ComImport, - Guid(InterfaceIds.IID_ID2D1GeometryGroup), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public unsafe interface IGeometryGroup : IGeometry - { - #region ID2D1Resource - [PreserveSig] - new void GetFactory( - out IFactory factory); - #endregion - - #region ID2D1Geometry - /// - /// Retrieve the bounds of the geometry, with an optional applied transform. - /// - new LtrbRectangleF GetBounds( - Matrix3x2* worldTransform); - - /// - /// Get the bounds of the corresponding geometry after it has been widened or have - /// an optional pen style applied. - /// - new LtrbRectangleF GetWidenedBounds( - float strokeWidth, - IStrokeStyle strokeStyle, - Matrix3x2* worldTransform, - float flatteningTolerance); - - /// - /// Checks to see whether the corresponding penned and widened geometry contains the - /// given point. - /// - new IntBoolean StrokeContainsPoint( - PointF point, - float strokeWidth, - IStrokeStyle strokeStyle, - Matrix3x2* worldTransform, - float flatteningTolerance); - - /// - /// Test whether the given fill of this geometry would contain this point. - /// - new IntBoolean FillContainsPoint( - PointF point, - Matrix3x2* worldTransform, - float flatteningTolerance); - - /// - /// Compare how one geometry intersects or contains another geometry. - /// - new GeometryRelation CompareWithGeometry( - IGeometry inputGeometry, - Matrix3x2* inputGeometryTransform, - float flatteningTolerance); - - /// - /// Converts a geometry to a simplified geometry that has arcs and quadratic beziers - /// removed. - /// - new void Simplify( - GeometrySimplificationOption simplificationOption, - Matrix3x2* worldTransform, - float flatteningTolerance, - ISimplifiedGeometrySink geometrySink); - - /// - /// Tessellates a geometry into triangles. - /// - new void Tessellate( - Matrix3x2* worldTransform, - float flatteningTolerance, - ITesselationSink tessellationSink); - - /// - /// Performs a combine operation between the two geometries to produce a resulting - /// geometry. - /// - new void CombineWithGeometry( - IGeometry inputGeometry, - CombineMode combineMode, - Matrix3x2* inputGeometryTransform, - float flatteningTolerance, - ISimplifiedGeometrySink geometrySink); - - /// - /// Computes the outline of the geometry. The result is written back into a - /// simplified geometry sink. - /// - new void Outline( - Matrix3x2* worldTransform, - float flatteningTolerance, - ISimplifiedGeometrySink geometrySink); - - /// - /// Computes the area of the geometry. - /// - new float ComputeArea( - Matrix3x2* worldTransform, - float flatteningTolerance); - - /// - /// Computes the length of the geometry. - /// - new float ComputeLength( - Matrix3x2* worldTransform, - float flatteningTolerance); - - /// - /// Computes the point and tangent a given distance along the path. - /// - new void ComputePointAtLength( - float length, - Matrix3x2* worldTransform, - float flatteningTolerance, - PointF* point, - PointF* unitTangentVector); - - /// - /// Get the geometry and widen it as well as apply an optional pen style. - /// - new void Widen( - float strokeWidth, - IStrokeStyle strokeStyle, - Matrix3x2* worldTransform, - float flatteningTolerance, - ISimplifiedGeometrySink geometrySink); - #endregion - - [PreserveSig] - FillMode GetFillMode(); - - [PreserveSig] - uint GetSourceGeometryCount(); - - [PreserveSig] - unsafe void GetSourceGeometries( - [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] - out IGeometry[] geometries, - uint geometriesCount); - } -} diff --git a/src/WInterop.DirectX/Direct2d/IGeometrySink.cs b/src/WInterop.DirectX/Direct2d/IGeometrySink.cs deleted file mode 100644 index 684cabe1..00000000 --- a/src/WInterop.DirectX/Direct2d/IGeometrySink.cs +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (c) Jeremy W. Kuhne. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Drawing; -using System.Runtime.InteropServices; - -namespace WInterop.Direct2d -{ - /// - /// Describes a geometric path that can contain lines, arcs, cubic Bezier curves, - /// and quadratic Bezier curves. [ID2D1GeometrySink] - /// - [ComImport, - Guid(InterfaceIds.IID_ID2D1GeometrySink), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IGeometrySink : ISimplifiedGeometrySink - { - #region ID2D1SimplifiedGeometrySink - [PreserveSig] - new void SetFillMode( - FillMode fillMode); - - [PreserveSig] - new void SetSegmentFlags( - PathSegment vertexFlags); - - [PreserveSig] - new void BeginFigure( - PointF startPoint, - FigureBegin figureBegin); - - [PreserveSig] - unsafe new void AddLines( - PointF* points, - uint pointsCount); - - [PreserveSig] - unsafe new void AddBeziers( - BezierSegment* beziers, - uint beziersCount); - - [PreserveSig] - new void EndFigure( - FigureEnd figureEnd); - - [PreserveSig] - new void Close(); - #endregion - - [PreserveSig] - void AddLine( - PointF point); - - [PreserveSig] - void AddBezier( - in BezierSegment bezier); - - [PreserveSig] - void AddQuadraticBezier( - in QuadraticBezierSegment bezier); - - [PreserveSig] - void AddQuadraticBeziers( - in QuadraticBezierSegment bezier, - uint beziersCount); - - [PreserveSig] - void AddArc( - in ArcSegment arc); - } - - public static class GeometrySinkExtensions - { - public unsafe static void AddBezier(this IGeometrySink sink, (float X, float Y) point1, (float X, float Y) point2, (float X, float Y) point3) - => sink.AddBezier(new BezierSegment(point1, point2, point3)); - } -} diff --git a/src/WInterop.DirectX/Direct2d/IGradientStopCollection.cs b/src/WInterop.DirectX/Direct2d/IGradientStopCollection.cs deleted file mode 100644 index 32b8c60d..00000000 --- a/src/WInterop.DirectX/Direct2d/IGradientStopCollection.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) Jeremy W. Kuhne. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Runtime.InteropServices; - -namespace WInterop.Direct2d -{ - /// - /// Represents an collection of gradient stops that can then be the source resource - /// for either a linear or radial gradient brush. [ID2D1GradientStopCollection] - /// - [ComImport, - Guid(InterfaceIds.IID_ID2D1GradientStopCollection), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IGradientStopCollection : IResource - { - #region ID2D1Resource - [PreserveSig] - new void GetFactory( - out IFactory factory); - #endregion - - /// - /// Returns the number of stops in the gradient. - /// - [PreserveSig] - uint GetGradientStopCount(); - - /// - /// Copies the gradient stops from the collection into the caller's interface. The - /// returned colors have straight alpha. - /// - [PreserveSig] - unsafe void GetGradientStops( - GradientStop* gradientStops, - uint gradientStopsCount); - - /// - /// Returns whether the interpolation occurs with 1.0 or 2.2 gamma. - /// - [PreserveSig] - Gamma GetColorInterpolationGamma(); - - [PreserveSig] - ExtendMode GetExtendMode(); - } -} diff --git a/src/WInterop.DirectX/Direct2d/IImage.cs b/src/WInterop.DirectX/Direct2d/IImage.cs deleted file mode 100644 index 8a3661cc..00000000 --- a/src/WInterop.DirectX/Direct2d/IImage.cs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Jeremy W. Kuhne. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Runtime.InteropServices; - -namespace WInterop.Direct2d -{ - /// - /// Represents a producer of pixels that can fill an arbitrary 2D plane. [ID2D1Image] - /// - [ComImport, - Guid(InterfaceIds.IID_ID2D1Image), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IImage : IResource - { - #region ID2D1Resource - [PreserveSig] - new void GetFactory( - out IFactory factory); - #endregion - } -} diff --git a/src/WInterop.DirectX/Direct2d/IPathGeometry.cs b/src/WInterop.DirectX/Direct2d/IPathGeometry.cs deleted file mode 100644 index d2d27bee..00000000 --- a/src/WInterop.DirectX/Direct2d/IPathGeometry.cs +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright (c) Jeremy W. Kuhne. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Drawing; -using System.Numerics; -using System.Runtime.InteropServices; - -namespace WInterop.Direct2d -{ - /// - /// Represents a complex shape that may be composed of arcs, curves, and lines. [ID2D1PathGeometry] - /// - [ComImport, - Guid(InterfaceIds.IID_ID2D1PathGeometry), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public unsafe interface IPathGeometry : IGeometry - { - #region ID2D1Resource - [PreserveSig] - new void GetFactory( - out IFactory factory); - #endregion - - #region ID2D1Geometry - /// - /// Retrieve the bounds of the geometry, with an optional applied transform. - /// - new LtrbRectangleF GetBounds( - Matrix3x2* worldTransform); - - /// - /// Get the bounds of the corresponding geometry after it has been widened or have - /// an optional pen style applied. - /// - new LtrbRectangleF GetWidenedBounds( - float strokeWidth, - IStrokeStyle strokeStyle, - Matrix3x2* worldTransform, - float flatteningTolerance); - - /// - /// Checks to see whether the corresponding penned and widened geometry contains the - /// given point. - /// - new IntBoolean StrokeContainsPoint( - PointF point, - float strokeWidth, - IStrokeStyle strokeStyle, - Matrix3x2* worldTransform, - float flatteningTolerance); - - /// - /// Test whether the given fill of this geometry would contain this point. - /// - new IntBoolean FillContainsPoint( - PointF point, - Matrix3x2* worldTransform, - float flatteningTolerance); - - /// - /// Compare how one geometry intersects or contains another geometry. - /// - new GeometryRelation CompareWithGeometry( - IGeometry inputGeometry, - Matrix3x2* inputGeometryTransform, - float flatteningTolerance); - - /// - /// Converts a geometry to a simplified geometry that has arcs and quadratic beziers - /// removed. - /// - new void Simplify( - GeometrySimplificationOption simplificationOption, - Matrix3x2* worldTransform, - float flatteningTolerance, - ISimplifiedGeometrySink geometrySink); - - /// - /// Tessellates a geometry into triangles. - /// - new void Tessellate( - Matrix3x2* worldTransform, - float flatteningTolerance, - ITesselationSink tessellationSink); - - /// - /// Performs a combine operation between the two geometries to produce a resulting - /// geometry. - /// - new void CombineWithGeometry( - IGeometry inputGeometry, - CombineMode combineMode, - Matrix3x2* inputGeometryTransform, - float flatteningTolerance, - ISimplifiedGeometrySink geometrySink); - - /// - /// Computes the outline of the geometry. The result is written back into a - /// simplified geometry sink. - /// - new void Outline( - Matrix3x2* worldTransform, - float flatteningTolerance, - ISimplifiedGeometrySink geometrySink); - - /// - /// Computes the area of the geometry. - /// - new float ComputeArea( - Matrix3x2* worldTransform, - float flatteningTolerance); - - /// - /// Computes the length of the geometry. - /// - new float ComputeLength( - Matrix3x2* worldTransform, - float flatteningTolerance); - - /// - /// Computes the point and tangent a given distance along the path. - /// - new void ComputePointAtLength( - float length, - Matrix3x2* worldTransform, - float flatteningTolerance, - PointF* point, - PointF* unitTangentVector); - - /// - /// Get the geometry and widen it as well as apply an optional pen style. - /// - new void Widen( - float strokeWidth, - IStrokeStyle strokeStyle, - Matrix3x2* worldTransform, - float flatteningTolerance, - ISimplifiedGeometrySink geometrySink); - #endregion - - /// - /// Opens a geometry sink that will be used to create this path geometry. - /// - IGeometrySink Open(); - - /// - /// Retrieve the contents of this geometry. The caller passes an implementation of a - /// ID2D1GeometrySink interface to receive the data. - /// - void Stream( - IGeometrySink geometrySink); - - uint GetSegmentCount(); - - uint GetFigureCount(); - } -} diff --git a/src/WInterop.DirectX/Direct2d/IRadialGradientBrush.cs b/src/WInterop.DirectX/Direct2d/IRadialGradientBrush.cs deleted file mode 100644 index cee9bb3f..00000000 --- a/src/WInterop.DirectX/Direct2d/IRadialGradientBrush.cs +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (c) Jeremy W. Kuhne. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Drawing; -using System.Numerics; -using System.Runtime.InteropServices; - -namespace WInterop.Direct2d -{ - /// - /// Paints an area with a radial gradient. [ID2D1RadialGradientBrush] - /// - [ComImport, - Guid(InterfaceIds.IID_ID2D1RadialGradientBrush), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IRadialGradientBrush : IBrush - { - #region ID2D1Resource - [PreserveSig] - new void GetFactory( - out IFactory factory); - #endregion - - #region ID2D1Brush - /// - /// Sets the opacity for when the brush is drawn over the entire fill of the brush. - /// - [PreserveSig] - new void SetOpacity( - float opacity); - - /// - /// Sets the transform that applies to everything drawn by the brush. - /// - [PreserveSig] - new void SetTransform( - ref Matrix3x2 transform); - - [PreserveSig] - new float GetOpacity(); - - [PreserveSig] - new void GetTransform( - out Matrix3x2 transform); - #endregion - - /// - /// Sets the center of the radial gradient. This will be in local coordinates and - /// will not depend on the geometry being filled. - /// - [PreserveSig] - void SetCenter(PointF center); - - /// - /// Sets offset of the origin relative to the radial gradient center. - /// - [PreserveSig] - void SetGradientOriginOffset(PointF gradientOriginOffset); - - [PreserveSig] - void SetRadiusX(float radiusX); - - [PreserveSig] - void SetRadiusY(float radiusY); - - // TODO: Bug in COM interop, should return PointF - [PreserveSig] - void GetCenter(out PointF center); - - // TODO: Bug in COM interop, should return PointF - [PreserveSig] - void GetGradientOriginOffset(out PointF offset); - - [PreserveSig] - float GetRadiusX(); - - [PreserveSig] - float GetRadiusY(); - - [PreserveSig] - void GetGradientStopCollection(out IGradientStopCollection gradientStopCollection); - } -} diff --git a/src/WInterop.DirectX/Direct2d/IRectangleGeometry.cs b/src/WInterop.DirectX/Direct2d/IRectangleGeometry.cs deleted file mode 100644 index 7fae1471..00000000 --- a/src/WInterop.DirectX/Direct2d/IRectangleGeometry.cs +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright (c) Jeremy W. Kuhne. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Drawing; -using System.Numerics; -using System.Runtime.InteropServices; - -namespace WInterop.Direct2d -{ - [ComImport, - Guid(InterfaceIds.IID_ID2D1RectangleGeometry), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public unsafe interface IRectangleGeometry : IGeometry - { - #region ID2D1Resource - [PreserveSig] - new void GetFactory( - out IFactory factory); - #endregion - - #region ID2D1Geometry - /// - /// Retrieve the bounds of the geometry, with an optional applied transform. - /// - new LtrbRectangleF GetBounds( - Matrix3x2* worldTransform); - - /// - /// Get the bounds of the corresponding geometry after it has been widened or have - /// an optional pen style applied. - /// - new LtrbRectangleF GetWidenedBounds( - float strokeWidth, - IStrokeStyle strokeStyle, - Matrix3x2* worldTransform, - float flatteningTolerance); - - /// - /// Checks to see whether the corresponding penned and widened geometry contains the - /// given point. - /// - new IntBoolean StrokeContainsPoint( - PointF point, - float strokeWidth, - IStrokeStyle strokeStyle, - Matrix3x2* worldTransform, - float flatteningTolerance); - - /// - /// Test whether the given fill of this geometry would contain this point. - /// - new IntBoolean FillContainsPoint( - PointF point, - Matrix3x2* worldTransform, - float flatteningTolerance); - - /// - /// Compare how one geometry intersects or contains another geometry. - /// - new GeometryRelation CompareWithGeometry( - IGeometry inputGeometry, - Matrix3x2* inputGeometryTransform, - float flatteningTolerance); - - /// - /// Converts a geometry to a simplified geometry that has arcs and quadratic beziers - /// removed. - /// - new void Simplify( - GeometrySimplificationOption simplificationOption, - Matrix3x2* worldTransform, - float flatteningTolerance, - ISimplifiedGeometrySink geometrySink); - - /// - /// Tessellates a geometry into triangles. - /// - new void Tessellate( - Matrix3x2* worldTransform, - float flatteningTolerance, - ITesselationSink tessellationSink); - - /// - /// Performs a combine operation between the two geometries to produce a resulting - /// geometry. - /// - new void CombineWithGeometry( - IGeometry inputGeometry, - CombineMode combineMode, - Matrix3x2* inputGeometryTransform, - float flatteningTolerance, - ISimplifiedGeometrySink geometrySink); - - /// - /// Computes the outline of the geometry. The result is written back into a - /// simplified geometry sink. - /// - new void Outline( - Matrix3x2* worldTransform, - float flatteningTolerance, - ISimplifiedGeometrySink geometrySink); - - /// - /// Computes the area of the geometry. - /// - new float ComputeArea( - Matrix3x2* worldTransform, - float flatteningTolerance); - - /// - /// Computes the length of the geometry. - /// - new float ComputeLength( - Matrix3x2* worldTransform, - float flatteningTolerance); - - /// - /// Computes the point and tangent a given distance along the path. - /// - new void ComputePointAtLength( - float length, - Matrix3x2* worldTransform, - float flatteningTolerance, - PointF* point, - PointF* unitTangentVector); - - /// - /// Get the geometry and widen it as well as apply an optional pen style. - /// - new void Widen( - float strokeWidth, - IStrokeStyle strokeStyle, - Matrix3x2* worldTransform, - float flatteningTolerance, - ISimplifiedGeometrySink geometrySink); - #endregion - - [PreserveSig] - void GetRect(out LtrbRectangleF rect); - } -} diff --git a/src/WInterop.DirectX/Direct2d/IRenderTarget.cs b/src/WInterop.DirectX/Direct2d/IRenderTarget.cs index cb5a0084..8ccc0b18 100644 --- a/src/WInterop.DirectX/Direct2d/IRenderTarget.cs +++ b/src/WInterop.DirectX/Direct2d/IRenderTarget.cs @@ -4,250 +4,125 @@ using System; using System.Drawing; using System.Numerics; -using System.Runtime.InteropServices; using WInterop.DirectWrite; -using WInterop.Errors; namespace WInterop.Direct2d { - /// - /// Represents an object that can receive drawing commands. Interfaces that inherit - /// from render the drawing commands they receive in different - /// ways. [ID2D1RenderTarget] - /// - [ComImport, - Guid(InterfaceIds.IID_ID2D1RenderTarget), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IRenderTarget : IResource + public interface IRenderTarget : IResource, IDisposable { - #region ID2D1Resource - [PreserveSig] - new void GetFactory( - out IFactory factory); - #endregion + SolidColorBrush CreateSolidColorBrush(ColorF color); /// - /// Create a D2D bitmap by copying from memory, or create uninitialized. + /// Creates a bitmap brush. The bitmap is scaled, rotated, skewed or tiled to fill or pen a geometry. /// - /// Byte count of each scanline, ignored if is null. - unsafe IBitmap CreateBitmap( - SizeU size, - void* srcData, - uint pitch, - in BitmapProperties bitmapProperties); + BitmapBrush CreateBitmapBrush( + Bitmap bitmap, + BitmapBrushProperties bitmapBrushProperties, + BrushProperties brushProperties); - /// - /// Create a D2D bitmap by copying a WIC bitmap. - /// - unsafe IBitmap CreateBitmapFromWicBitmap( - object wicBitmapSource, // IWICBitmapSource - BitmapProperties* bitmapProperties); - - /// - /// Create a D2D bitmap by sharing bits from another resource. The bitmap must be - /// compatible with the render target for the call to succeed. For example, an - /// IWICBitmap can be shared with a software target, or a DXGI surface can be shared - /// with a DXGI render target. - /// - unsafe IBitmap CreateSharedBitmap( - in Guid riid, - void* data, - BitmapProperties* bitmapProperties); - - /// - /// Creates a bitmap brush. The bitmap is scaled, rotated, skewed or tiled to fill - /// or pen a geometry. - /// - unsafe IBitmapBrush CreateBitmapBrush( - IBitmap bitmap, - BitmapBrushProperties* bitmapBrushProperties, - BrushProperties* brushProperties); - - unsafe ISolidColorBrush CreateSolidColorBrush( - in ColorF color, - BrushProperties* brushProperties); + SolidColorBrush CreateSolidColorBrush( + ColorF color, + BrushProperties brushProperties); /// /// A gradient stop collection represents a set of stops in an ideal unit length. /// This is the source resource for a linear gradient and radial gradient brush. /// - /// Specifies which space the color - /// interpolation occurs in. - /// Specifies how the gradient will be extended outside of - /// the unit length. - unsafe IGradientStopCollection CreateGradientStopCollection( - GradientStop* gradientStops, - uint gradientStopsCount, - Gamma colorInterpolationGamma, - ExtendMode extendMode); - - void CreateLinearGradientBrushSTUB(); - //STDMETHOD(CreateLinearGradientBrush)( - // _In_ CONST D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES *linearGradientBrushProperties, - // _In_opt_ CONST D2D1_BRUSH_PROPERTIES* brushProperties, - // _In_ ID2D1GradientStopCollection* gradientStopCollection, - // _COM_Outptr_ ID2D1LinearGradientBrush** linearGradientBrush - // ) PURE; - - unsafe IRadialGradientBrush CreateRadialGradientBrush( - in RadialGradientBrushProperties radialGradientBrushProperties, - BrushProperties* brushProperties, - IGradientStopCollection gradientStopCollection); - - /// - /// Creates a bitmap render target whose bitmap can be used as a source for - /// rendering in the API. - /// - /// The requested size of the target in DIPs. If the pixel - /// size is not specified, the DPI is inherited from the parent target. However, the - /// render target will never contain a fractional number of pixels. - /// The requested size of the render target in - /// pixels. If the DIP size is also specified, the DPI is calculated from these two - /// values. If the desired size is not specified, the DPI is inherited from the - /// parent render target. If neither value is specified, the compatible render - /// target will be the same size and have the same DPI as the parent target. - /// The desired pixel format. The format must be - /// compatible with the parent render target type. If the format is not specified, - /// it will be inherited from the parent render target. - /// Allows the caller to retrieve a GDI compatible render - /// target. - /// The returned bitmap render target. - unsafe IBitmapRenderTarget CreateCompatibleRenderTarget( - SizeF* desiredSize, - SizeU* desiredPixelSize, - PixelFormat* desiredFormat, - CompatibleRenderTargetOptions options); + /// + /// Specifies which space the color interpolation occurs in. + /// + /// + /// Specifies how the gradient will be extended outside of the unit length. + /// + GradientStopCollection CreateGradientStopCollection( + ReadOnlySpan gradientStops, + Gamma colorInterpolationGamma = Gamma.ColorSpace_2_2, + ExtendMode extendMode = ExtendMode.Clamp); - /// - /// Creates a layer resource that can be used on any target and which will resize - /// under the covers if necessary. - /// - /// The resolution independent minimum size hint for the layer - /// resource. Specify this to prevent unwanted reallocation of the layer backing - /// store. The size is in DIPs, but, it is unaffected by the current world - /// transform. If the size is unspecified, the returned resource is a placeholder - /// and the backing store will be allocated to be the minimum size that can hold the - /// content when the layer is pushed. - void CreateLayerStub(); - //STDMETHOD(CreateLayer)( - // _In_opt_ CONST D2D1_SIZE_F *size, - // _COM_Outptr_ ID2D1Layer **layer - // ) PURE; + RadialGradientBrush CreateRadialGradientBrush( + RadialGradientBrushProperties radialGradientBrushProperties, + BrushProperties brushProperties, + GradientStopCollection gradientStopCollection); /// - /// Create a D2D mesh. + /// Creates a bitmap render target whose bitmap can be used as a source for rendering in the API. /// - void CreateMeshSTUB(); - //STDMETHOD(CreateMesh)( - // _COM_Outptr_ ID2D1Mesh ** mesh - // ) PURE; + /// + /// The requested size of the target in DIPs. If the pixel size is not specified, the DPI is inherited from + /// the parent target. However, the render target will never contain a fractional number of pixels. + /// + /// + /// The requested size of the render target in pixels. If the DIP size is also specified, the DPI is + /// calculated from these two values. If the desired size is not specified, the DPI is inherited from the + /// parent render target. If neither value is specified, the compatible render target will be the same size + /// and have the same DPI as the parent target. + /// + /// + /// The desired pixel format. The format must be compatible with the parent render target type. If the format + /// is not specified, it will be inherited from the parent render target. + /// + /// + /// Allows the caller to retrieve a GDI compatible render target. + /// + /// The bitmap render target. + IBitmapRenderTarget CreateCompatibleRenderTarget( + SizeF? desiredSize = default, + SizeU? desiredPixelSize = default, + PixelFormat? desiredFormat = default, + CompatibleRenderTargetOptions options = CompatibleRenderTargetOptions.None); - [PreserveSig] void DrawLine( PointF point0, PointF point1, - IBrush brush, + Brush brush, float strokeWidth = 1.0f, - IStrokeStyle strokeStyle = null); + StrokeStyle strokeStyle = default); - [PreserveSig] void DrawRectangle( - in LtrbRectangleF rect, - IBrush brush, + LtrbRectangleF rectangle, + Brush brush, float strokeWidth = 1.0f, - IStrokeStyle strokeStyle = null); + StrokeStyle strokeStyle = default); - [PreserveSig] void FillRectangle( - in LtrbRectangleF rect, - IBrush brush); + LtrbRectangleF rectangle, + Brush brush); - [PreserveSig] void DrawRoundedRectangle( - in RoundedRectangle roundedRect, - IBrush brush, + RoundedRectangle roundedRectangle, + Brush brush, float strokeWidth = 1.0f, - IStrokeStyle strokeStyle = null); + StrokeStyle strokeStyle = default); - [PreserveSig] void FillRoundedRectangle( - in RoundedRectangle roundedRect, - IBrush brush); + RoundedRectangle roundedRectangle, + Brush brush); - [PreserveSig] void DrawEllipse( - in Ellipse ellipse, - IBrush brush, + Ellipse ellipse, + Brush brush, float strokeWidth = 1.0f, - IStrokeStyle strokeStyle = null); + StrokeStyle strokeStyle = default); - [PreserveSig] void FillEllipse( - in Ellipse ellipse, - IBrush brush); + Ellipse ellipse, + Brush brush); - [PreserveSig] void DrawGeometry( - IGeometry geometry, - IBrush brush, + Geometry geometry, + Brush brush, float strokeWidth = 1.0f, - IStrokeStyle strokeStyle = null); + StrokeStyle strokeStyle = default); - /// An optionally specified opacity brush. Only the alpha - /// channel of the corresponding brush will be sampled and will be applied to the - /// entire fill of the geometry. If this brush is specified, the fill brush must be - /// a bitmap brush with an extend mode of D2D1_EXTEND_MODE_CLAMP. - [PreserveSig] + /// + /// An optionally specified opacity brush. Only the alpha channel of the corresponding brush will be sampled + /// and will be applied to the entire fill of the geometry. If this brush is specified, the fill brush must be + /// a bitmap brush with an extend mode of . + /// void FillGeometry( - IGeometry geometry, - IBrush brush, - IBrush opacityBrush = null); - - /// - /// Fill a mesh. Since meshes can only render aliased content, the render target - /// antialiasing mode must be set to aliased. - /// - void FillMeshSTUB(); - //STDMETHOD_(void, FillMesh)( - // _In_ ID2D1Mesh * mesh, - // _In_ ID2D1Brush* brush - // ) PURE; - - /// - /// Fill using the alpha channel of the supplied opacity mask bitmap. The brush - /// opacity will be modulated by the mask. The render target antialiasing mode must - /// be set to aliased. - /// - void FillOpacityMaskSTUB(); - //STDMETHOD_(void, FillOpacityMask)( - // _In_ ID2D1Bitmap * opacityMask, - // _In_ ID2D1Brush* brush, - // D2D1_OPACITY_MASK_CONTENT content, - // _In_opt_ CONST D2D1_RECT_F* destinationRectangle = NULL, - // _In_opt_ CONST D2D1_RECT_F *sourceRectangle = NULL - // ) PURE; - - [PreserveSig] - unsafe void DrawBitmap( - IBitmap bitmap, - LtrbRectangleF* destinationRectangle = null, - float opacity = 1.0f, - BitmapInterpolationMode interpolationMode = BitmapInterpolationMode.Linear, - LtrbRectangleF* sourceRectangle = null); - - /// - /// Draws the text within the given layout rectangle and by default also performs - /// baseline snapping. - /// - [PreserveSig] - unsafe void DrawText( - char* @string, - uint stringLength, - ITextFormat textFormat, - in LtrbRectangleF layoutRect, - IBrush defaultFillBrush, - DrawTextOptions options = DrawTextOptions.None, - MeasuringMode measuringMode = MeasuringMode.Natural); + Geometry geometry, + Brush brush, + Brush opacityBrush = default); /// /// Draw a text layout object. If the layout is not subsequently changed, this can @@ -256,111 +131,42 @@ unsafe void DrawText( /// /// The specified text options. If is used, the text /// is clipped to the layout bounds. These bounds are derived from the origin and the - /// layout bounds of the corresponding object. + /// layout bounds of the corresponding object. /// - [PreserveSig] void DrawTextLayout( PointF origin, - ITextLayout textLayout, - IBrush defaultFillBrush, + TextLayout textLayout, + Brush defaultFillBrush, DrawTextOptions options = DrawTextOptions.None); - [PreserveSig] + /* void DrawGlyphRun( PointF baselineOrigin, - in GlyphRun glyphRun, - IBrush foregroundBrush, + GlyphRun glyphRun, + Brush foregroundBrush, MeasuringMode measuringMode = MeasuringMode.Natural); + */ - [PreserveSig] - void SetTransform( - ref Matrix3x2 transform); + Matrix3x2 Transform { get; set; } - [PreserveSig] - void GetTransform( - out Matrix3x2 transform); + AntialiasMode AntialiasMode { get; set; } - [PreserveSig] - void SetAntialiasMode( - AntialiasMode antialiasMode); - - [PreserveSig] - AntialiasMode GetAntialiasMode(); - - [PreserveSig] - void SetTextAntialiasMode( - TextAntialiasMode textAntialiasMode); - - [PreserveSig] - TextAntialiasMode GetTextAntialiasMode(); - - [PreserveSig] - void SetTextRenderingParams( - DirectWrite.IRenderingParams textRenderingParams = null); - - /// - /// Retrieve the text render parameters. NOTE: If NULL is specified to - /// SetTextRenderingParameters, NULL will be returned. - /// - [PreserveSig] - void GetTextRenderingParams( - out DirectWrite.IRenderingParams textRenderingParams); + TextAntialiasMode TextAntialiasMode { get; set; } /// /// Set a tag to correspond to the succeeding primitives. If an error occurs /// rendering a primitive, the tags can be returned from the Flush or EndDraw call. + /// + /// This does not retrieve the tags corresponding to any primitive that is in error. /// - [PreserveSig] - void SetTags( - ulong tag1, - ulong tag2); - - /// - /// Retrieves the currently set tags. This does not retrieve the tags corresponding - /// to any primitive that is in error. - /// - [PreserveSig] - void GetTags( - out ulong tag1, - out ulong tag2); - - /// - /// Start a layer of drawing calls. The way in which the layer must be resolved is - /// specified first as well as the logical resource that stores the layer - /// parameters. The supplied layer resource might grow if the specified content - /// cannot fit inside it. The layer will grow monotonically on each axis. If a NULL - /// ID2D1Layer is provided, then a layer resource will be allocated automatically. - /// - void PushLayerSTUB(); - //STDMETHOD_(void, PushLayer)( - // _In_ CONST D2D1_LAYER_PARAMETERS *layerParameters, - //_In_opt_ ID2D1Layer *layer - //) PURE; + public Tags Tags { get; set; } /// /// Ends a layer that was defined with particular layer resources. /// - [PreserveSig] void PopLayer(); - void Flush( - out ulong tag1, - out ulong tag2); - - /// - /// Gets the current drawing state and saves it into the supplied - /// IDrawingStatckBlock. - /// - [PreserveSig] - void SaveDrawingState( - IDrawingStateBlock drawingStateBlock); - - /// - /// Copies the state stored in the block interface. - /// - [PreserveSig] - void RestoreDrawingState( - IDrawingStateBlock drawingStateBlock); + Tags Flush(); /// /// Pushes a clip. The clip can be antialiased. The clip must be axis aligned. If @@ -368,74 +174,53 @@ void RestoreDrawingState( /// transformed clip rect will be used. The clip will remain in effect until a /// PopAxisAligned clip call is made. /// - [PreserveSig] void PushAxisAlignedClip( - in LtrbRectangleF clipRect, + LtrbRectangleF clipRect, AntialiasMode antialiasMode); - [PreserveSig] void PopAxisAlignedClip(); - [PreserveSig] - unsafe void Clear( - ColorF* clearColor = null); + void Clear(); + + void Clear(ColorF clearColor); /// /// Start drawing on this render target. Draw calls can only be issued between a /// BeginDraw and EndDraw call. /// - [PreserveSig] void BeginDraw(); /// /// Ends drawing on the render target, error results can be retrieved at this time, /// or when calling flush. /// - [PreserveSig] - HResult EndDraw( - out ulong tag1, - out ulong tag2); + Tags EndDraw(out bool recreateTarget); - [PreserveSig] - void GetPixelFormat(out PixelFormat pixelFormat); + PixelFormat PixelFormat { get; } /// - /// Sets the DPI on the render target. This results in the render target being + /// The DPI on the render target. This results in the render target being /// interpreted to a different scale. Neither DPI can be negative. If zero is /// specified for both, the system DPI is chosen. If one is zero and the other /// unspecified, the DPI is not changed. /// - [PreserveSig] - void SetDpi( - float dpiX, - float dpiY); - - /// - /// Return the current DPI from the target. - /// - [PreserveSig] - void GetDpi( - out float dpiX, - out float dpiY); + PointF Dpi { get; set; } /// /// Returns the size of the render target in DIPs. /// - [PreserveSig] - void GetSize(out SizeF size); + SizeF Size { get; } /// /// Returns the size of the render target in pixels. /// - [PreserveSig] - void GetPixelSize(out SizeU pixelSize); + SizeU PixelSize { get; } /// /// Returns the maximum bitmap and render target size that is guaranteed to be /// supported by the render target. /// - [PreserveSig] - uint GetMaximumBitmapSize(); + uint MaximumBitmapSize { get; } /// /// Returns true if the given properties are supported by this render target. The @@ -443,76 +228,6 @@ void GetDpi( /// D2D1_FEATURE_LEVEL_9 nor D2D1_FEATURE_LEVEL_10 will be considered to be /// supported. /// - [PreserveSig] - IntBoolean IsSupported( - in RenderTargetProperties renderTargetProperties); - } - - public static class RenderTargetExtensions - { - public unsafe static IBitmap CreateBitmap(this IRenderTarget renderTarget, Size size, in BitmapProperties properties) - => renderTarget.CreateBitmap(size, null, 0, properties); - - public unsafe static ISolidColorBrush CreateSolidColorBrush(this IRenderTarget renderTarget, in ColorF color) - => renderTarget.CreateSolidColorBrush(color, null); - - public unsafe static ISolidColorBrush CreateSolidColorBrush( - this IRenderTarget renderTarget, in ColorF color, in BrushProperties properties) - { - fixed (BrushProperties* p = &properties) - return renderTarget.CreateSolidColorBrush(color, p); - } - - public unsafe static IBitmapRenderTarget CreateCompatibleRenderTarget(this IRenderTarget renderTarget, SizeF desiredSize) - => renderTarget.CreateCompatibleRenderTarget(&desiredSize, null, null, CompatibleRenderTargetOptions.None); - - public unsafe static IBitmapBrush CreateBitmapBrush(this IRenderTarget renderTarget, IBitmap bitmap, BitmapBrushProperties bitmapBrushProperties) - => renderTarget.CreateBitmapBrush(bitmap, &bitmapBrushProperties, null); - - public unsafe static IRadialGradientBrush CreateRadialGradientBrush( - this IRenderTarget renderTarget, - in RadialGradientBrushProperties properties, - IGradientStopCollection gradientStopCollection) - { - return renderTarget.CreateRadialGradientBrush(properties, null, gradientStopCollection); - } - - public unsafe static IGradientStopCollection CreateGradienStopCollection( - this IRenderTarget renderTarget, - ReadOnlySpan gradientStops, - Gamma gamma = Gamma.ColorSpace_2_2, - ExtendMode extendMode = ExtendMode.Clamp) - { - fixed (GradientStop* gs = &MemoryMarshal.GetReference(gradientStops)) - { - return renderTarget.CreateGradientStopCollection(gs, (uint)gradientStops.Length, gamma, extendMode); - } - } - - public unsafe static void Clear(this IRenderTarget renderTarget) - => renderTarget.Clear(null); - - public unsafe static void Clear(this IRenderTarget renderTarget, in ColorF color) - { - fixed (ColorF* c = &color) - renderTarget.Clear(c); - } - - public static SizeF GetSize(this IRenderTarget renderTarget) - { - renderTarget.GetSize(out SizeF size); - return size; - } - - /// - /// Set the transform to identity. - /// - public static void SetTransform(this IRenderTarget renderTarget) - { - Matrix3x2 identity = Matrix3x2.Identity; - renderTarget.SetTransform(ref identity); - } - - public static HResult EndDraw(this IRenderTarget renderTarget) => renderTarget.EndDraw(out _, out _); + bool IsSupported(RenderTargetProperties renderTargetProperties); } } diff --git a/src/WInterop.DirectX/Direct2d/IResource.cs b/src/WInterop.DirectX/Direct2d/IResource.cs deleted file mode 100644 index 56d303ec..00000000 --- a/src/WInterop.DirectX/Direct2d/IResource.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) Jeremy W. Kuhne. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Runtime.InteropServices; - -namespace WInterop.Direct2d -{ - /// - /// [ID2D1Resource] - /// - [ComImport, - Guid(InterfaceIds.IID_ID2D1Resource), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IResource - { - [PreserveSig] - void GetFactory( - out IFactory factory); - } -} diff --git a/src/WInterop.DirectX/Direct2d/IRoundedRectangleGeometry.cs b/src/WInterop.DirectX/Direct2d/IRoundedRectangleGeometry.cs deleted file mode 100644 index f2306eb2..00000000 --- a/src/WInterop.DirectX/Direct2d/IRoundedRectangleGeometry.cs +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright (c) Jeremy W. Kuhne. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Drawing; -using System.Numerics; -using System.Runtime.InteropServices; - -namespace WInterop.Direct2d -{ - /// - /// [ID2D1RoundedRectangleGeometry] - /// - [ComImport, - Guid(InterfaceIds.IID_ID2D1RoundedRectangleGeometry), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public unsafe interface IRoundedRectangleGeometry : IGeometry - { - #region ID2D1Resource - [PreserveSig] - new void GetFactory( - out IFactory factory); - #endregion - - #region ID2D1Geometry - /// - /// Retrieve the bounds of the geometry, with an optional applied transform. - /// - new LtrbRectangleF GetBounds( - Matrix3x2* worldTransform); - - /// - /// Get the bounds of the corresponding geometry after it has been widened or have - /// an optional pen style applied. - /// - new LtrbRectangleF GetWidenedBounds( - float strokeWidth, - IStrokeStyle strokeStyle, - Matrix3x2* worldTransform, - float flatteningTolerance); - - /// - /// Checks to see whether the corresponding penned and widened geometry contains the - /// given point. - /// - new IntBoolean StrokeContainsPoint( - PointF point, - float strokeWidth, - IStrokeStyle strokeStyle, - Matrix3x2* worldTransform, - float flatteningTolerance); - - /// - /// Test whether the given fill of this geometry would contain this point. - /// - new IntBoolean FillContainsPoint( - PointF point, - Matrix3x2* worldTransform, - float flatteningTolerance); - - /// - /// Compare how one geometry intersects or contains another geometry. - /// - new GeometryRelation CompareWithGeometry( - IGeometry inputGeometry, - Matrix3x2* inputGeometryTransform, - float flatteningTolerance); - - /// - /// Converts a geometry to a simplified geometry that has arcs and quadratic beziers - /// removed. - /// - new void Simplify( - GeometrySimplificationOption simplificationOption, - Matrix3x2* worldTransform, - float flatteningTolerance, - ISimplifiedGeometrySink geometrySink); - - /// - /// Tessellates a geometry into triangles. - /// - new void Tessellate( - Matrix3x2* worldTransform, - float flatteningTolerance, - ITesselationSink tessellationSink); - - /// - /// Performs a combine operation between the two geometries to produce a resulting - /// geometry. - /// - new void CombineWithGeometry( - IGeometry inputGeometry, - CombineMode combineMode, - Matrix3x2* inputGeometryTransform, - float flatteningTolerance, - ISimplifiedGeometrySink geometrySink); - - /// - /// Computes the outline of the geometry. The result is written back into a - /// simplified geometry sink. - /// - new void Outline( - Matrix3x2* worldTransform, - float flatteningTolerance, - ISimplifiedGeometrySink geometrySink); - - /// - /// Computes the area of the geometry. - /// - new float ComputeArea( - Matrix3x2* worldTransform, - float flatteningTolerance); - - /// - /// Computes the length of the geometry. - /// - new float ComputeLength( - Matrix3x2* worldTransform, - float flatteningTolerance); - - /// - /// Computes the point and tangent a given distance along the path. - /// - new void ComputePointAtLength( - float length, - Matrix3x2* worldTransform, - float flatteningTolerance, - PointF* point, - PointF* unitTangentVector); - - /// - /// Get the geometry and widen it as well as apply an optional pen style. - /// - new void Widen( - float strokeWidth, - IStrokeStyle strokeStyle, - Matrix3x2* worldTransform, - float flatteningTolerance, - ISimplifiedGeometrySink geometrySink); - #endregion - - [PreserveSig] - void GetRoundedRect( - out RoundedRectangle roundedRect); - } -} diff --git a/src/WInterop.DirectX/Direct2d/ISimplifiedGeometrySink.cs b/src/WInterop.DirectX/Direct2d/ISimplifiedGeometrySink.cs deleted file mode 100644 index 64e2057c..00000000 --- a/src/WInterop.DirectX/Direct2d/ISimplifiedGeometrySink.cs +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) Jeremy W. Kuhne. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Drawing; -using System.Runtime.InteropServices; - -namespace WInterop.Direct2d -{ - /// - /// Describes a geometric path that does not contain quadratic bezier curves or arcs. - /// [ID2D1SimplifiedGeometrySink] - /// - [ComImport, - Guid(InterfaceIds.IID_ID2D1SimplifiedGeometrySink), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface ISimplifiedGeometrySink - { - [PreserveSig] - void SetFillMode( - FillMode fillMode); - - [PreserveSig] - void SetSegmentFlags( - PathSegment vertexFlags); - - [PreserveSig] - void BeginFigure( - PointF startPoint, - FigureBegin figureBegin); - - [PreserveSig] - unsafe void AddLines( - PointF* points, - uint pointsCount); - - [PreserveSig] - unsafe void AddBeziers( - BezierSegment* beziers, - uint beziersCount); - - [PreserveSig] - void EndFigure( - FigureEnd figureEnd); - - [PreserveSig] - void Close(); - } - - public static class SimplifiedGeometrySinkExtensions - { - public unsafe static void AddLines(this IGeometrySink sink, ReadOnlySpan points) - { - fixed (PointF* p = &MemoryMarshal.GetReference(points)) - { - sink.AddLines(p, (uint)points.Length); - } - } - } -} diff --git a/src/WInterop.DirectX/Direct2d/ISolidColorBrush.cs b/src/WInterop.DirectX/Direct2d/ISolidColorBrush.cs deleted file mode 100644 index 96e153ad..00000000 --- a/src/WInterop.DirectX/Direct2d/ISolidColorBrush.cs +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) Jeremy W. Kuhne. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Numerics; -using System.Runtime.InteropServices; - -namespace WInterop.Direct2d -{ - /// - /// Paints an area with a solid color. [ID2D1SolidColorBrush] - /// - [ComImport, - Guid(InterfaceIds.IID_ID2D1SolidColorBrush), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface ISolidColorBrush : IBrush - { - #region ID2D1Resource - [PreserveSig] - new void GetFactory( - out IFactory factory); - #endregion - - #region ID2D1Brush - /// - /// Sets the opacity for when the brush is drawn over the entire fill of the brush. - /// - [PreserveSig] - new void SetOpacity( - float opacity); - - /// - /// Sets the transform that applies to everything drawn by the brush. - /// - [PreserveSig] - new void SetTransform( - ref Matrix3x2 transform); - - [PreserveSig] - new float GetOpacity(); - - [PreserveSig] - new void GetTransform( - out Matrix3x2 transform); - #endregion - - [PreserveSig] - void SetColor( - in ColorF color); - - [PreserveSig] - void GetColor( - out ColorF color); - } -} diff --git a/src/WInterop.DirectX/Direct2d/IStrokeStyle.cs b/src/WInterop.DirectX/Direct2d/IStrokeStyle.cs deleted file mode 100644 index 627f8881..00000000 --- a/src/WInterop.DirectX/Direct2d/IStrokeStyle.cs +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) Jeremy W. Kuhne. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Runtime.InteropServices; - -namespace WInterop.Direct2d -{ - /// - /// [ID2D1StrokeStyle] - /// - [ComImport, - Guid(InterfaceIds.IID_ID2D1StrokeStyle), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IStrokeStyle : IResource - { - #region ID2D1Resource - [PreserveSig] - new void GetFactory( - out IFactory factory); - #endregion - - [PreserveSig] - CapStyle GetStartCap(); - - [PreserveSig] - CapStyle GetEndCap(); - - [PreserveSig] - CapStyle GetDashCap(); - - [PreserveSig] - float GetMiterLimit(); - - [PreserveSig] - LineJoin GetLineJoin(); - - [PreserveSig] - float GetDashOffset(); - - [PreserveSig] - DashStyle GetDashStyle(); - - [PreserveSig] - uint GetDashesCount(); - - /// - /// Returns the dashes from the object into a user allocated array. The user must - /// call GetDashesCount to retrieve the required size. - /// - [PreserveSig] - unsafe void GetDashes( - float* dashes, - uint dashesCount); - } -} diff --git a/src/WInterop.DirectX/Direct2d/ITesselationSink.cs b/src/WInterop.DirectX/Direct2d/ITesselationSink.cs index 45bce9ee..6e0db719 100644 --- a/src/WInterop.DirectX/Direct2d/ITesselationSink.cs +++ b/src/WInterop.DirectX/Direct2d/ITesselationSink.cs @@ -9,17 +9,34 @@ namespace WInterop.Direct2d /// /// [ID2D1TessellationSink] /// - [ComImport, - Guid(InterfaceIds.IID_ID2D1TessellationSink), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface ITesselationSink + [Guid(InterfaceIds.IID_ID2D1TessellationSink)] + public readonly unsafe struct TesselationSink : TesselationSink.Interface, IDisposable { - [PreserveSig] - void AddTriangles( - ref Triangle triangles, - uint trianglesCount); + private readonly ID2D1TessellationSink* _handle; - [PreserveSig] - void Close(); + internal TesselationSink(ID2D1TessellationSink* handle) => _handle = handle; + + public void AddTriangles(ReadOnlySpan triangles) + { + fixed(void* t = triangles) + { + _handle->AddTriangles((D2D1_TRIANGLE*)t, (uint)triangles.Length); + } + } + + public void Close() => _handle->Close(); + + public void Dispose() + { + Close(); + _handle->Release(); + } + + internal interface Interface + { + void AddTriangles(ReadOnlySpan triangles); + + void Close(); + } } } diff --git a/src/WInterop.DirectX/Direct2d/ITransformedGeometry.cs b/src/WInterop.DirectX/Direct2d/ITransformedGeometry.cs deleted file mode 100644 index 3d67575a..00000000 --- a/src/WInterop.DirectX/Direct2d/ITransformedGeometry.cs +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright (c) Jeremy W. Kuhne. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Drawing; -using System.Numerics; -using System.Runtime.InteropServices; - -namespace WInterop.Direct2d -{ - /// - /// Represents a geometry that has been transformed. [ID2D1TransformedGeometry] - /// - [ComImport, - Guid(InterfaceIds.IID_ID2D1TransformedGeometry), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public unsafe interface ITransformedGeometry : IGeometry - { - #region ID2D1Resource - [PreserveSig] - new void GetFactory( - out IFactory factory); - #endregion - - #region ID2D1Geometry - /// - /// Retrieve the bounds of the geometry, with an optional applied transform. - /// - new LtrbRectangleF GetBounds( - Matrix3x2* worldTransform); - - /// - /// Get the bounds of the corresponding geometry after it has been widened or have - /// an optional pen style applied. - /// - new LtrbRectangleF GetWidenedBounds( - float strokeWidth, - IStrokeStyle strokeStyle, - Matrix3x2* worldTransform, - float flatteningTolerance); - - /// - /// Checks to see whether the corresponding penned and widened geometry contains the - /// given point. - /// - new IntBoolean StrokeContainsPoint( - PointF point, - float strokeWidth, - IStrokeStyle strokeStyle, - Matrix3x2* worldTransform, - float flatteningTolerance); - - /// - /// Test whether the given fill of this geometry would contain this point. - /// - new IntBoolean FillContainsPoint( - PointF point, - Matrix3x2* worldTransform, - float flatteningTolerance); - - /// - /// Compare how one geometry intersects or contains another geometry. - /// - new GeometryRelation CompareWithGeometry( - IGeometry inputGeometry, - Matrix3x2* inputGeometryTransform, - float flatteningTolerance); - - /// - /// Converts a geometry to a simplified geometry that has arcs and quadratic beziers - /// removed. - /// - new void Simplify( - GeometrySimplificationOption simplificationOption, - Matrix3x2* worldTransform, - float flatteningTolerance, - ISimplifiedGeometrySink geometrySink); - - /// - /// Tessellates a geometry into triangles. - /// - new void Tessellate( - Matrix3x2* worldTransform, - float flatteningTolerance, - ITesselationSink tessellationSink); - - /// - /// Performs a combine operation between the two geometries to produce a resulting - /// geometry. - /// - new void CombineWithGeometry( - IGeometry inputGeometry, - CombineMode combineMode, - Matrix3x2* inputGeometryTransform, - float flatteningTolerance, - ISimplifiedGeometrySink geometrySink); - - /// - /// Computes the outline of the geometry. The result is written back into a - /// simplified geometry sink. - /// - new void Outline( - Matrix3x2* worldTransform, - float flatteningTolerance, - ISimplifiedGeometrySink geometrySink); - - /// - /// Computes the area of the geometry. - /// - new float ComputeArea( - Matrix3x2* worldTransform, - float flatteningTolerance); - - /// - /// Computes the length of the geometry. - /// - new float ComputeLength( - Matrix3x2* worldTransform, - float flatteningTolerance); - - /// - /// Computes the point and tangent a given distance along the path. - /// - new void ComputePointAtLength( - float length, - Matrix3x2* worldTransform, - float flatteningTolerance, - PointF* point, - PointF* unitTangentVector); - - /// - /// Get the geometry and widen it as well as apply an optional pen style. - /// - new void Widen( - float strokeWidth, - IStrokeStyle strokeStyle, - Matrix3x2* worldTransform, - float flatteningTolerance, - ISimplifiedGeometrySink geometrySink); - #endregion - - [PreserveSig] - void GetSourceGeometry( - out IGeometry sourceGeometry); - - [PreserveSig] - void GetTransform( - out Matrix3x2 transform); - } -} diff --git a/src/WInterop.DirectX/Direct2d/IWindowRenderTarget.cs b/src/WInterop.DirectX/Direct2d/IWindowRenderTarget.cs index 46d13bf0..bf4bd7a5 100644 --- a/src/WInterop.DirectX/Direct2d/IWindowRenderTarget.cs +++ b/src/WInterop.DirectX/Direct2d/IWindowRenderTarget.cs @@ -1,451 +1,10 @@ // Copyright (c) Jeremy W. Kuhne. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System; -using System.Drawing; -using System.Numerics; -using System.Runtime.InteropServices; -using WInterop.DirectWrite; -using WInterop.Windows.Native; - namespace WInterop.Direct2d { - /// - /// Renders drawing instructions to a window. [ID2D1HwndRenderTarget] - /// - [ComImport, - Guid(InterfaceIds.IID_ID2D1HwndRenderTarget), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public interface IWindowRenderTarget : IRenderTarget { - #region ID2D1Resource - [PreserveSig] - new void GetFactory( - out IFactory factory); - #endregion - - #region ID2D1RenderTarget - /// - /// Create a D2D bitmap by copying from memory, or create uninitialized. - /// - new unsafe IBitmap CreateBitmap( - SizeU size, - void* srcData, - uint pitch, - in BitmapProperties bitmapProperties); - - /// - /// Create a D2D bitmap by copying a WIC bitmap. - /// - new unsafe IBitmap CreateBitmapFromWicBitmap( - object wicBitmapSource, // IWICBitmapSource - BitmapProperties* bitmapProperties); - - /// - /// Create a D2D bitmap by sharing bits from another resource. The bitmap must be - /// compatible with the render target for the call to succeed. For example, an - /// IWICBitmap can be shared with a software target, or a DXGI surface can be shared - /// with a DXGI render target. - /// - new unsafe IBitmap CreateSharedBitmap( - in Guid riid, - void* data, - BitmapProperties* bitmapProperties); - - /// - /// Creates a bitmap brush. The bitmap is scaled, rotated, skewed or tiled to fill - /// or pen a geometry. - /// - new unsafe IBitmapBrush CreateBitmapBrush( - IBitmap bitmap, - BitmapBrushProperties* bitmapBrushProperties, - BrushProperties* brushProperties); - - new unsafe ISolidColorBrush CreateSolidColorBrush( - in ColorF color, - BrushProperties* brushProperties); - - /// - /// A gradient stop collection represents a set of stops in an ideal unit length. - /// This is the source resource for a linear gradient and radial gradient brush. - /// - /// Specifies which space the color - /// interpolation occurs in. - /// Specifies how the gradient will be extended outside of - /// the unit length. - new unsafe IGradientStopCollection CreateGradientStopCollection( - GradientStop* gradientStops, - uint gradientStopsCount, - Gamma colorInterpolationGamma, - ExtendMode extendMode); - - new void CreateLinearGradientBrushSTUB(); - //STDMETHOD(CreateLinearGradientBrush)( - // _In_ CONST D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES *linearGradientBrushProperties, - // _In_opt_ CONST D2D1_BRUSH_PROPERTIES* brushProperties, - // _In_ ID2D1GradientStopCollection* gradientStopCollection, - // _COM_Outptr_ ID2D1LinearGradientBrush** linearGradientBrush - // ) PURE; - - new unsafe IRadialGradientBrush CreateRadialGradientBrush( - in RadialGradientBrushProperties radialGradientBrushProperties, - BrushProperties* brushProperties, - IGradientStopCollection gradientStopCollection); - - /// - /// Creates a bitmap render target whose bitmap can be used as a source for - /// rendering in the API. - /// - /// The requested size of the target in DIPs. If the pixel - /// size is not specified, the DPI is inherited from the parent target. However, the - /// render target will never contain a fractional number of pixels. - /// The requested size of the render target in - /// pixels. If the DIP size is also specified, the DPI is calculated from these two - /// values. If the desired size is not specified, the DPI is inherited from the - /// parent render target. If neither value is specified, the compatible render - /// target will be the same size and have the same DPI as the parent target. - /// The desired pixel format. The format must be - /// compatible with the parent render target type. If the format is not specified, - /// it will be inherited from the parent render target. - /// Allows the caller to retrieve a GDI compatible render - /// target. - /// The returned bitmap render target. - new unsafe IBitmapRenderTarget CreateCompatibleRenderTarget( - SizeF* desiredSize, - SizeU* desiredPixelSize, - PixelFormat* desiredFormat, - CompatibleRenderTargetOptions options); - - /// - /// Creates a layer resource that can be used on any target and which will resize - /// under the covers if necessary. - /// - /// The resolution independent minimum size hint for the layer - /// resource. Specify this to prevent unwanted reallocation of the layer backing - /// store. The size is in DIPs, but, it is unaffected by the current world - /// transform. If the size is unspecified, the returned resource is a placeholder - /// and the backing store will be allocated to be the minimum size that can hold the - /// content when the layer is pushed. - new void CreateLayerStub(); - //STDMETHOD(CreateLayer)( - // _In_opt_ CONST D2D1_SIZE_F *size, - // _COM_Outptr_ ID2D1Layer **layer - // ) PURE; - - /// - /// Create a D2D mesh. - /// - new void CreateMeshSTUB(); - //STDMETHOD(CreateMesh)( - // _COM_Outptr_ ID2D1Mesh ** mesh - // ) PURE; - - [PreserveSig] - new void DrawLine( - PointF point0, - PointF point1, - IBrush brush, - float strokeWidth = 1.0f, - IStrokeStyle strokeStyle = null); - - [PreserveSig] - new void DrawRectangle( - in LtrbRectangleF rect, - IBrush brush, - float strokeWidth = 1.0f, - IStrokeStyle strokeStyle = null); - - [PreserveSig] - new void FillRectangle( - in LtrbRectangleF rect, - IBrush brush); - - [PreserveSig] - new void DrawRoundedRectangle( - in RoundedRectangle roundedRect, - IBrush brush, - float strokeWidth = 1.0f, - IStrokeStyle strokeStyle = null); - - [PreserveSig] - new void FillRoundedRectangle( - in RoundedRectangle roundedRect, - IBrush brush); - - [PreserveSig] - new void DrawEllipse( - in Ellipse ellipse, - IBrush brush, - float strokeWidth = 1.0f, - IStrokeStyle strokeStyle = null); - - [PreserveSig] - new void FillEllipse( - in Ellipse ellipse, - IBrush brush); - - [PreserveSig] - new void DrawGeometry( - IGeometry geometry, - IBrush brush, - float strokeWidth = 1.0f, - IStrokeStyle strokeStyle = null); - - /// An optionally specified opacity brush. Only the alpha - /// channel of the corresponding brush will be sampled and will be applied to the - /// entire fill of the geometry. If this brush is specified, the fill brush must be - /// a bitmap brush with an extend mode of D2D1_EXTEND_MODE_CLAMP. - [PreserveSig] - new void FillGeometry( - IGeometry geometry, - IBrush brush, - IBrush opacityBrush = null); - - /// - /// Fill a mesh. Since meshes can only render aliased content, the render target - /// antialiasing mode must be set to aliased. - /// - new void FillMeshSTUB(); - //STDMETHOD_(void, FillMesh)( - // _In_ ID2D1Mesh * mesh, - // _In_ ID2D1Brush* brush - // ) PURE; - - /// - /// Fill using the alpha channel of the supplied opacity mask bitmap. The brush - /// opacity will be modulated by the mask. The render target antialiasing mode must - /// be set to aliased. - /// - new void FillOpacityMaskSTUB(); - //STDMETHOD_(void, FillOpacityMask)( - // _In_ ID2D1Bitmap * opacityMask, - // _In_ ID2D1Brush* brush, - // D2D1_OPACITY_MASK_CONTENT content, - // _In_opt_ CONST D2D1_RECT_F* destinationRectangle = NULL, - // _In_opt_ CONST D2D1_RECT_F *sourceRectangle = NULL - // ) PURE; - - [PreserveSig] - new unsafe void DrawBitmap( - IBitmap bitmap, - LtrbRectangleF* destinationRectangle = null, - float opacity = 1.0f, - BitmapInterpolationMode interpolationMode = BitmapInterpolationMode.Linear, - LtrbRectangleF* sourceRectangle = null); - - /// - /// Draws the text within the given layout rectangle and by default also performs - /// baseline snapping. - /// - [PreserveSig] - new unsafe void DrawText( - char* @string, - uint stringLength, - ITextFormat textFormat, - in LtrbRectangleF layoutRect, - IBrush defaultFillBrush, - DrawTextOptions options = DrawTextOptions.None, - MeasuringMode measuringMode = MeasuringMode.Natural); - - /// - /// Draw a text layout object. If the layout is not subsequently changed, this can - /// be more efficient than DrawText when drawing the same layout repeatedly. - /// - /// - /// The specified text options. If is used, the text - /// is clipped to the layout bounds. These bounds are derived from the origin and the - /// layout bounds of the corresponding object. - /// - [PreserveSig] - new void DrawTextLayout( - PointF origin, - ITextLayout textLayout, - IBrush defaultFillBrush, - DrawTextOptions options = DrawTextOptions.None); - - [PreserveSig] - new void DrawGlyphRun( - PointF baselineOrigin, - in GlyphRun glyphRun, - IBrush foregroundBrush, - MeasuringMode measuringMode = MeasuringMode.Natural); - - [PreserveSig] - new void SetTransform( - ref Matrix3x2 transform); - - [PreserveSig] - new void GetTransform( - out Matrix3x2 transform); - - [PreserveSig] - new void SetAntialiasMode( - AntialiasMode antialiasMode); - - [PreserveSig] - new AntialiasMode GetAntialiasMode(); - - [PreserveSig] - new void SetTextAntialiasMode( - TextAntialiasMode textAntialiasMode); - - [PreserveSig] - new TextAntialiasMode GetTextAntialiasMode(); - - [PreserveSig] - new void SetTextRenderingParams( - DirectWrite.IRenderingParams textRenderingParams = null); - - /// - /// Retrieve the text render parameters. NOTE: If NULL is specified to - /// SetTextRenderingParameters, NULL will be returned. - /// - [PreserveSig] - new void GetTextRenderingParams( - out DirectWrite.IRenderingParams textRenderingParams); - - /// - /// Set a tag to correspond to the succeeding primitives. If an error occurs - /// rendering a primitive, the tags can be returned from the Flush or EndDraw call. - /// - [PreserveSig] - new void SetTags( - ulong tag1, - ulong tag2); - - /// - /// Retrieves the currently set tags. This does not retrieve the tags corresponding - /// to any primitive that is in error. - /// - [PreserveSig] - new void GetTags( - out ulong tag1, - out ulong tag2); - - /// - /// Start a layer of drawing calls. The way in which the layer must be resolved is - /// specified first as well as the logical resource that stores the layer - /// parameters. The supplied layer resource might grow if the specified content - /// cannot fit inside it. The layer will grow monotonically on each axis. If a NULL - /// ID2D1Layer is provided, then a layer resource will be allocated automatically. - /// - new void PushLayerSTUB(); - //STDMETHOD_(void, PushLayer)( - // _In_ CONST D2D1_LAYER_PARAMETERS *layerParameters, - //_In_opt_ ID2D1Layer *layer - //) PURE; - - /// - /// Ends a layer that was defined with particular layer resources. - /// - [PreserveSig] - new void PopLayer(); - - new void Flush( - out ulong tag1, - out ulong tag2); - - /// - /// Gets the current drawing state and saves it into the supplied - /// IDrawingStatckBlock. - /// - [PreserveSig] - new void SaveDrawingState( - IDrawingStateBlock drawingStateBlock); - - /// - /// Copies the state stored in the block interface. - /// - [PreserveSig] - new void RestoreDrawingState( - IDrawingStateBlock drawingStateBlock); - - /// - /// Pushes a clip. The clip can be antialiased. The clip must be axis aligned. If - /// the current world transform is not axis preserving, then the bounding box of the - /// transformed clip rect will be used. The clip will remain in effect until a - /// PopAxisAligned clip call is made. - /// - [PreserveSig] - new void PushAxisAlignedClip( - in LtrbRectangleF clipRect, - AntialiasMode antialiasMode); - - [PreserveSig] - new void PopAxisAlignedClip(); - - [PreserveSig] - new unsafe void Clear( - ColorF* clearColor = null); - - /// - /// Start drawing on this render target. Draw calls can only be issued between a - /// BeginDraw and EndDraw call. - /// - [PreserveSig] - new void BeginDraw(); - - /// - /// Ends drawing on the render target, error results can be retrieved at this time, - /// or when calling flush. - /// - new void EndDraw( - out ulong tag1, - out ulong tag2); - - [PreserveSig] - new void GetPixelFormat(out PixelFormat pixelFormat); - - /// - /// Sets the DPI on the render target. This results in the render target being - /// interpreted to a different scale. Neither DPI can be negative. If zero is - /// specified for both, the system DPI is chosen. If one is zero and the other - /// unspecified, the DPI is not changed. - /// - [PreserveSig] - new void SetDpi( - float dpiX, - float dpiY); - - /// - /// Return the current DPI from the target. - /// - [PreserveSig] - new void GetDpi( - out float dpiX, - out float dpiY); - - /// - /// Returns the size of the render target in DIPs. - /// - [PreserveSig] - new void GetSize(out SizeF size); - - /// - /// Returns the size of the render target in pixels. - /// - [PreserveSig] - new SizeU GetPixelSize(out SizeU pixelSize); - - /// - /// Returns the maximum bitmap and render target size that is guaranteed to be - /// supported by the render target. - /// - [PreserveSig] - new uint GetMaximumBitmapSize(); - - /// - /// Returns true if the given properties are supported by this render target. The - /// DPI is ignored. NOTE: If the render target type is software, then neither - /// D2D1_FEATURE_LEVEL_9 nor D2D1_FEATURE_LEVEL_10 will be considered to be - /// supported. - /// - [PreserveSig] - new IntBoolean IsSupported( - in RenderTargetProperties renderTargetProperties); - #endregion - - [PreserveSig] WindowState CheckWindowState(); /// @@ -456,10 +15,8 @@ public interface IWindowRenderTarget : IRenderTarget /// from it when EndDraw is called. In addition an appropriate failure result will /// be returned from Resize. /// - void Resize( - in SizeU pixelSize); + void Resize(SizeU pixelSize); - [PreserveSig] - HWND GetHwnd(); + Windows.Native.HWND GetHwnd(); } } diff --git a/src/WInterop.DirectX/Direct2d/Image.cs b/src/WInterop.DirectX/Direct2d/Image.cs new file mode 100644 index 00000000..67486b4b --- /dev/null +++ b/src/WInterop.DirectX/Direct2d/Image.cs @@ -0,0 +1,25 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace WInterop.Direct2d +{ + /// + /// Represents a producer of pixels that can fill an arbitrary 2D plane. [ID2D1Image] + /// + [StructLayout(LayoutKind.Sequential)] + [Guid(InterfaceIds.IID_ID2D1Image)] + public unsafe struct Image : Resource.Interface, IDisposable + { + internal readonly ID2D1Image* _handle; + + internal Image(ID2D1Image* handle) => _handle = handle; + + public unsafe Factory GetFactory() => Resource.From(this).GetFactory(); + + public void Dispose() => _handle->Release(); + } +} diff --git a/src/WInterop.DirectX/Direct2d/LineJoin.cs b/src/WInterop.DirectX/Direct2d/LineJoin.cs index ff9770de..0d7565c8 100644 --- a/src/WInterop.DirectX/Direct2d/LineJoin.cs +++ b/src/WInterop.DirectX/Direct2d/LineJoin.cs @@ -11,21 +11,21 @@ public enum LineJoin : uint /// /// Miter join. [D2D1_LINE_JOIN_MITER] /// - Miter = 0, + Miter = D2D1_LINE_JOIN.D2D1_LINE_JOIN_MITER, /// /// Bevel join. [D2D1_LINE_JOIN_BEVEL] /// - Bevel = 1, + Bevel = D2D1_LINE_JOIN.D2D1_LINE_JOIN_BEVEL, /// /// Round join. [D2D1_LINE_JOIN_ROUND] /// - Round = 2, + Round = D2D1_LINE_JOIN.D2D1_LINE_JOIN_ROUND, /// /// Miter/Bevel join. [D2D1_LINE_JOIN_MITER_OR_BEVEL] /// - MiterOrBevel = 3 + MiterOrBevel = D2D1_LINE_JOIN.D2D1_LINE_JOIN_MITER_OR_BEVEL } } diff --git a/src/WInterop.DirectX/Direct2d/LtrbRectangleF.cs b/src/WInterop.DirectX/Direct2d/LtrbRectangleF.cs index 3bb2638d..8d65cd3b 100644 --- a/src/WInterop.DirectX/Direct2d/LtrbRectangleF.cs +++ b/src/WInterop.DirectX/Direct2d/LtrbRectangleF.cs @@ -9,10 +9,10 @@ namespace WInterop.Direct2d // https://docs.microsoft.com/en-us/windows/desktop/api/dcommon/ns-dcommon-d2d_rect_f public readonly struct LtrbRectangleF { - public readonly float Left; - public readonly float Top; - public readonly float Right; - public readonly float Bottom; + public float Left { get; } + public float Top { get; } + public float Right { get; } + public float Bottom { get; } public LtrbRectangleF(RectangleF rectangle) { @@ -33,13 +33,13 @@ public LtrbRectangleF(SizeF size) public static implicit operator RectangleF(LtrbRectangleF rect) => RectangleF.FromLTRB(rect.Left, rect.Top, rect.Right, rect.Bottom); - public static implicit operator LtrbRectangleF(RectangleF rectangle) - => new LtrbRectangleF(rectangle); + public unsafe static implicit operator LtrbRectangleF((float Left, float Top, float Right, float Bottom) rectangle) + => *(LtrbRectangleF*)&rectangle; - public static implicit operator LtrbRectangleF(Rectangle rectangle) - => new LtrbRectangleF(rectangle); + public static implicit operator LtrbRectangleF(RectangleF rectangle) => new(rectangle); - public static implicit operator LtrbRectangleF(SizeF size) - => new LtrbRectangleF(size); + public static implicit operator LtrbRectangleF(Rectangle rectangle) => new(rectangle); + + public static implicit operator LtrbRectangleF(SizeF size) => new(size); } } diff --git a/src/WInterop.DirectX/Direct2d/Native/Imports.cs b/src/WInterop.DirectX/Direct2d/Native/Imports.cs deleted file mode 100644 index 6cadec9b..00000000 --- a/src/WInterop.DirectX/Direct2d/Native/Imports.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) Jeremy W. Kuhne. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Runtime.InteropServices; -using WInterop.Errors; - -namespace WInterop.Direct2d.Native -{ - /// - /// Direct usage of Imports isn't recommended. Use the wrappers that do the heavy lifting for you. - /// - public static partial class Imports - { - // https://docs.microsoft.com/en-us/windows/desktop/api/d2d1/nf-d2d1-d2d1createfactory - [DllImport(Libraries.D2Dd1, ExactSpelling = true)] - public static extern HResult D2D1CreateFactory( - FactoryType factoryType, - in Guid riid, - in DebugLevel pFactoryOptions, - out IFactory ppIFactory); - } -} diff --git a/src/WInterop.DirectX/Direct2d/PathGeometry.cs b/src/WInterop.DirectX/Direct2d/PathGeometry.cs new file mode 100644 index 00000000..bfdf6aa8 --- /dev/null +++ b/src/WInterop.DirectX/Direct2d/PathGeometry.cs @@ -0,0 +1,69 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Drawing; +using System.Numerics; +using System.Runtime.InteropServices; + +namespace WInterop.Direct2d +{ + /// + /// Represents a complex shape that may be composed of arcs, curves, and lines. [ID2D1PathGeometry] + /// + [Guid(InterfaceIds.IID_ID2D1PathGeometry)] + [StructLayout(LayoutKind.Sequential)] + public readonly unsafe struct PathGeometry : PathGeometry.Interface, IDisposable + { + internal readonly ID2D1PathGeometry* _handle; + + internal PathGeometry(ID2D1PathGeometry* handle) => _handle = handle; + + public RectangleF GetBounds() => Geometry.From(this).GetBounds(); + + public RectangleF GetBounds(Matrix3x2 worldTransform) + => Geometry.From(this).GetBounds(worldTransform); + + public void CombineWithGeometry(Geometry inputGeometry, CombineMode combineMode, SimplifiedGeometrySink geometrySink) + => Geometry.From(this).CombineWithGeometry(inputGeometry, combineMode, geometrySink); + + public Factory GetFactory() => Geometry.From(this).GetFactory(); + + public uint GetFigureCount() + { + uint count; + _handle->GetFigureCount(&count).ThrowIfFailed(); + return count; + } + + public uint GetSegmentCount() + { + uint count; + _handle->GetSegmentCount(&count).ThrowIfFailed(); + return count; + } + + public GeometrySink Open() + { + GeometrySink sink; + _handle->Open((ID2D1GeometrySink**)&sink).ThrowIfFailed(); + return sink; + } + + public void Dispose() => _handle->Release(); + + public static implicit operator Geometry(PathGeometry brush) => new((ID2D1Geometry*)brush._handle); + + internal unsafe interface Interface : Geometry.Interface + { + /// + /// Opens a geometry sink that will be used to create this path geometry. + /// + GeometrySink Open(); + + uint GetSegmentCount(); + + uint GetFigureCount(); + } + } +} diff --git a/src/WInterop.DirectX/Direct2d/PathSegment.cs b/src/WInterop.DirectX/Direct2d/PathSegment.cs index 92ddc466..c8a1189f 100644 --- a/src/WInterop.DirectX/Direct2d/PathSegment.cs +++ b/src/WInterop.DirectX/Direct2d/PathSegment.cs @@ -15,16 +15,16 @@ public enum PathSegment : uint /// /// [D2D1_PATH_SEGMENT_NONE] /// - None = 0x00000000, + None = D2D1_PATH_SEGMENT.D2D1_PATH_SEGMENT_NONE, /// /// [D2D1_PATH_SEGMENT_FORCE_UNSTROKED] /// - ForceUnstroked = 0x00000001, + ForceUnstroked = D2D1_PATH_SEGMENT.D2D1_PATH_SEGMENT_FORCE_UNSTROKED, /// /// [D2D1_PATH_SEGMENT_FORCE_ROUND_LINE_JOIN] /// - ForceRoundLineJoin = 0x00000002 + ForceRoundLineJoin = D2D1_PATH_SEGMENT.D2D1_PATH_SEGMENT_FORCE_ROUND_LINE_JOIN } } diff --git a/src/WInterop.DirectX/Direct2d/PixelFormat.cs b/src/WInterop.DirectX/Direct2d/PixelFormat.cs index c2bccae1..f61d3564 100644 --- a/src/WInterop.DirectX/Direct2d/PixelFormat.cs +++ b/src/WInterop.DirectX/Direct2d/PixelFormat.cs @@ -1,6 +1,8 @@ // Copyright (c) Jeremy W. Kuhne. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using System.Runtime.CompilerServices; + namespace WInterop.Direct2d { /// @@ -11,10 +13,18 @@ public readonly struct PixelFormat public readonly Dxgi.Format Format; public readonly AlphaMode AlphaMode; - public PixelFormat(Dxgi.Format format = Dxgi.Format.DXGI_FORMAT_UNKNOWN, AlphaMode alphaMode = AlphaMode.Unknown) + public PixelFormat(Dxgi.Format format = Dxgi.Format.Unknown, AlphaMode alphaMode = AlphaMode.Unknown) { Format = format; AlphaMode = alphaMode; } + + internal PixelFormat(D2D1_PIXEL_FORMAT format) + { + Format = (Dxgi.Format)format.format; + AlphaMode = (AlphaMode)format.alphaMode; + } + + internal D2D1_PIXEL_FORMAT ToD2D() => Unsafe.As(ref Unsafe.AsRef(this)); } } diff --git a/src/WInterop.DirectX/Direct2d/RadialGradientBrush.cs b/src/WInterop.DirectX/Direct2d/RadialGradientBrush.cs new file mode 100644 index 00000000..02896771 --- /dev/null +++ b/src/WInterop.DirectX/Direct2d/RadialGradientBrush.cs @@ -0,0 +1,98 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Drawing; +using System.Numerics; +using System.Runtime.InteropServices; + +namespace WInterop.Direct2d +{ + /// + /// Paints an area with a radial gradient. [ID2D1RadialGradientBrush] + /// + [StructLayout(LayoutKind.Sequential)] + [Guid(InterfaceIds.IID_ID2D1RadialGradientBrush)] + public readonly unsafe struct RadialGradientBrush : RadialGradientBrush.Interface, IDisposable + { + private readonly ID2D1RadialGradientBrush* _handle; + + public Factory GetFactory() => Resource.From(this).GetFactory(); + + public float Opacity + { + get => Brush.From(this).Opacity; + set => Brush.From(this).Opacity = value; + } + + public Matrix3x2 Transform + { + get => Brush.From(this).Transform; + set => Brush.From(this).Transform = value; + } + + /// + public PointF Center + { + get => _handle->GetCenter().ToPointF(); + set => _handle->SetCenter(value.ToD2D()); + } + + public PointF GradientOriginOffset + { + get => _handle->GetGradientOriginOffset().ToPointF(); + set => _handle->SetGradientOriginOffset(value.ToD2D()); + } + + public float RadiusX + { + get => _handle->GetRadiusX(); + set => _handle->SetRadiusX(value); + } + + public float RadiusY + { + get => _handle->GetRadiusY(); + set => _handle->SetRadiusY(value); + } + + public PointF GetCenter() => _handle->GetCenter().ToPointF(); + + public PointF GetGradientOriginOffset() => _handle->GetGradientOriginOffset().ToPointF(); + + public GradientStopCollection GetGradientStopCollection() + { + ID2D1GradientStopCollection* collection; + _handle->GetGradientStopCollection(&collection); + return new(collection); + } + + public void Dispose() => _handle->Release(); + + public static implicit operator Brush(RadialGradientBrush brush) => new((ID2D1Brush*)brush._handle); + + internal interface Interface : Brush.Interface + { + /// + /// The center of the radial gradient. This will be in local coordinates and + /// will not depend on the geometry being filled. + /// + PointF Center { get; set; } + + /// + /// The offset of the origin relative to the radial gradient center. + /// + PointF GradientOriginOffset { get; set; } + + float RadiusX { get; set; } + + float RadiusY { get; set; } + + PointF GetCenter(); + + PointF GetGradientOriginOffset(); + + GradientStopCollection GetGradientStopCollection(); + } + } +} diff --git a/src/WInterop.DirectX/Direct2d/RadialGradientBrushProperties.cs b/src/WInterop.DirectX/Direct2d/RadialGradientBrushProperties.cs index cf5538d7..50f64ff1 100644 --- a/src/WInterop.DirectX/Direct2d/RadialGradientBrushProperties.cs +++ b/src/WInterop.DirectX/Direct2d/RadialGradientBrushProperties.cs @@ -7,7 +7,7 @@ namespace WInterop.Direct2d { /// /// Contains the gradient origin offset and the size and position of the gradient - /// ellipse for an . [D2D1_RADIAL_GRADIENT_BRUSH_PROPERTIES] + /// ellipse for an . [D2D1_RADIAL_GRADIENT_BRUSH_PROPERTIES] /// public readonly struct RadialGradientBrushProperties { @@ -23,5 +23,13 @@ public RadialGradientBrushProperties(PointF center, PointF gradientOriginOffset, RadiusX = radiusX; RadiusY = radiusY; } + + public unsafe RadialGradientBrushProperties((float X, float Y) center, (float X, float Y) gradientOriginOffset, float radiusX, float radiusY) + { + Center = *(PointF*)¢er; + GradientOriginOffset = *(PointF*)&gradientOriginOffset; + RadiusX = radiusX; + RadiusY = radiusY; + } } } diff --git a/src/WInterop.DirectX/Direct2d/RectangleGeometry.cs b/src/WInterop.DirectX/Direct2d/RectangleGeometry.cs new file mode 100644 index 00000000..4fd6f499 --- /dev/null +++ b/src/WInterop.DirectX/Direct2d/RectangleGeometry.cs @@ -0,0 +1,45 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Drawing; +using System.Numerics; +using System.Runtime.InteropServices; + +namespace WInterop.Direct2d +{ + [StructLayout(LayoutKind.Sequential)] + [Guid(InterfaceIds.IID_ID2D1RectangleGeometry)] + public readonly unsafe struct RectangleGeometry : RectangleGeometry.Interface, IDisposable + { + internal readonly ID2D1RectangleGeometry* _handle; + + internal RectangleGeometry(ID2D1RectangleGeometry* handle) => _handle = handle; + + public RectangleF GetBounds() => Geometry.From(this).GetBounds(); + + public RectangleF GetBounds(Matrix3x2 worldTransform) + => Geometry.From(this).GetBounds(worldTransform); + + public void CombineWithGeometry(Geometry inputGeometry, CombineMode combineMode, SimplifiedGeometrySink geometrySink) + => Geometry.From(this).CombineWithGeometry(inputGeometry, combineMode, geometrySink); + + public Factory GetFactory() => Resource.From(this).GetFactory(); + + public RectangleF GetRect() + { + D2D_RECT_F rect; + _handle->GetRect(&rect); + return rect.ToRectangleF(); + } + + public void Dispose() => _handle->Release(); + + public static implicit operator Geometry(RectangleGeometry brush) => new((ID2D1Geometry*)brush._handle); + + internal unsafe interface Interface : Geometry.Interface + { + RectangleF GetRect(); + } + } +} diff --git a/src/WInterop.DirectX/Direct2d/RenderTarget.cs b/src/WInterop.DirectX/Direct2d/RenderTarget.cs new file mode 100644 index 00000000..2350d0e5 --- /dev/null +++ b/src/WInterop.DirectX/Direct2d/RenderTarget.cs @@ -0,0 +1,295 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Drawing; +using System.Numerics; +using System.Runtime.InteropServices; +using WInterop.DirectWrite; +using WInterop.Errors; + +namespace WInterop.Direct2d +{ + /// + /// Represents an object that can receive drawing commands. Interfaces that inherit + /// from this render the drawing commands they receive in different + /// ways. [ID2D1RenderTarget] + /// + [StructLayout(LayoutKind.Sequential)] + [Guid(InterfaceIds.IID_ID2D1RenderTarget)] + internal unsafe class RenderTarget : IRenderTarget, IResource + { + private readonly ID2D1RenderTarget* _handle; + + ID2D1RenderTarget* IHandle.Handle => _handle; + + public Factory GetFactory() => this.GetFactory(); + + internal RenderTarget(ID2D1RenderTarget* handle) => _handle = handle; + + public Matrix3x2 Transform + { + get + { + Matrix3x2 transform; + _handle->GetTransform((D2D_MATRIX_3X2_F*)&transform); + return transform; + } + set => _handle->SetTransform((D2D_MATRIX_3X2_F*)&value); + } + + public AntialiasMode AntialiasMode + { + get => (AntialiasMode)_handle->GetAntialiasMode(); + set => _handle->SetAntialiasMode((D2D1_ANTIALIAS_MODE)value); + } + + public TextAntialiasMode TextAntialiasMode + { + get => (TextAntialiasMode)_handle->GetTextAntialiasMode(); + set => _handle->SetTextAntialiasMode((D2D1_TEXT_ANTIALIAS_MODE)value); + } + + public PointF Dpi + { + get + { + float x; + float y; + _handle->GetDpi(&x, &y); + return new(x, y); + } + set => _handle->SetDpi(value.X, value.Y); + } + + public void BeginDraw() => _handle->BeginDraw(); + + public SolidColorBrush CreateSolidColorBrush(ColorF color) + { + SolidColorBrush brush; + _handle->CreateSolidColorBrush( + (DXGI_RGBA*)&color, + (ID2D1SolidColorBrush**)&brush).ThrowIfFailed(); + + return brush; + } + + public BitmapBrush CreateBitmapBrush( + Bitmap bitmap, + BitmapBrushProperties bitmapBrushProperties, + BrushProperties brushProperties) + { + ID2D1BitmapBrush* brush; + _handle->CreateBitmapBrush( + bitmap._handle, + (D2D1_BITMAP_BRUSH_PROPERTIES*)&bitmapBrushProperties, + (D2D1_BRUSH_PROPERTIES*)&brushProperties, + &brush).ThrowIfFailed(); + + return new(brush); + } + + public SolidColorBrush CreateSolidColorBrush(ColorF color, BrushProperties brushProperties) + { + SolidColorBrush brush; + _handle->CreateSolidColorBrush( + (DXGI_RGBA*)&color, + (D2D1_BRUSH_PROPERTIES*)&brushProperties, + (ID2D1SolidColorBrush**)&brush).ThrowIfFailed(); + + return brush; + } + + public GradientStopCollection CreateGradientStopCollection( + ReadOnlySpan gradientStops, + Gamma colorInterpolationGamma, + ExtendMode extendMode) + { + fixed (GradientStop* g = gradientStops) + { + GradientStopCollection collection; + _handle->CreateGradientStopCollection( + (D2D1_GRADIENT_STOP*)g, + (uint)gradientStops.Length, + (D2D1_GAMMA)colorInterpolationGamma, + (D2D1_EXTEND_MODE)extendMode, + (ID2D1GradientStopCollection**)&collection).ThrowIfFailed(); + return collection; + } + } + + public RadialGradientBrush CreateRadialGradientBrush( + RadialGradientBrushProperties radialGradientBrushProperties, + BrushProperties brushProperties, + GradientStopCollection gradientStopCollection) + { + RadialGradientBrush brush; + _handle->CreateRadialGradientBrush( + (D2D1_RADIAL_GRADIENT_BRUSH_PROPERTIES*)&radialGradientBrushProperties, + (D2D1_BRUSH_PROPERTIES*)&brushProperties, + gradientStopCollection._handle, + (ID2D1RadialGradientBrush**)&brush).ThrowIfFailed(); + + return brush; + } + + public IBitmapRenderTarget CreateCompatibleRenderTarget( + SizeF? desiredSize = default, + SizeU? desiredPixelSize = default, + PixelFormat? desiredFormat = default, + CompatibleRenderTargetOptions options = CompatibleRenderTargetOptions.None) + { + ID2D1BitmapRenderTarget* target; + var specifiedSize = desiredSize.GetValueOrDefault(); + var specifiedPixelSize = desiredPixelSize.GetValueOrDefault(); + var specifiedFormat = desiredFormat.GetValueOrDefault(); + _handle->CreateCompatibleRenderTarget(specifiedSize.ToD2D(), specifiedPixelSize.ToD2D(), specifiedFormat.ToD2D(), &target); + return new BitmapRenderTarget(target); + } + + public void DrawLine(PointF point0, PointF point1, Brush brush, float strokeWidth = 1, StrokeStyle strokeStyle = default) + { + _handle->DrawLine( + point0.ToD2D(), + point1.ToD2D(), + brush.Handle, + strokeWidth, + strokeStyle._handle); + } + + public void DrawRectangle(LtrbRectangleF rectangle, Brush brush, float strokeWidth = 1, StrokeStyle strokeStyle = default) + { + _handle->DrawRectangle( + (D2D_RECT_F*)&rectangle, + brush.Handle, + strokeWidth, + strokeStyle._handle); + } + + public void FillRectangle(LtrbRectangleF rectangle, Brush brush) + { + _handle->FillRectangle( + (D2D_RECT_F*)&rectangle, + brush.Handle); + } + + public void DrawRoundedRectangle( + RoundedRectangle roundedRectangle, + Brush brush, + float strokeWidth = 1, + StrokeStyle strokeStyle = default) + { + _handle->DrawRoundedRectangle( + (D2D1_ROUNDED_RECT*)&roundedRectangle, + brush.Handle, + strokeWidth, + strokeStyle._handle); + } + + public void FillRoundedRectangle(RoundedRectangle roundedRectangle, Brush brush) + { + _handle->FillRoundedRectangle( + (D2D1_ROUNDED_RECT*)&roundedRectangle, + brush.Handle); + } + + public void DrawEllipse(Ellipse ellipse, Brush brush, float strokeWidth = 1, StrokeStyle strokeStyle = default) + { + _handle->DrawEllipse( + (D2D1_ELLIPSE*)&ellipse, + brush.Handle, + strokeWidth, + strokeStyle._handle); + } + + public void FillEllipse(Ellipse ellipse, Brush brush) + { + _handle->FillEllipse( + (D2D1_ELLIPSE*)&ellipse, + brush.Handle); + } + + public void DrawGeometry(Geometry geometry, Brush brush, float strokeWidth = 1, StrokeStyle strokeStyle = default) + { + _handle->DrawGeometry( + geometry._handle, + brush.Handle, + strokeWidth, + strokeStyle._handle); + } + + public void FillGeometry(Geometry geometry, Brush brush, Brush opacityBrush = default) + { + _handle->FillGeometry( + geometry._handle, + brush.Handle, + opacityBrush.Handle); + } + + public Tags Tags + { + get + { + Tags tags; + _handle->GetTags(&tags.One, &tags.Two); + return tags; + } + set => _handle->SetTags(value.One, value.Two); + } + + public void PopLayer() => _handle->PopLayer(); + + public Tags Flush() + { + Tags tags; + _handle->Flush(&tags.One, &tags.Two); + return tags; + } + + public void PushAxisAlignedClip(LtrbRectangleF clipRect, AntialiasMode antialiasMode) + { + _handle->PushAxisAlignedClip((D2D_RECT_F*)&clipRect, (D2D1_ANTIALIAS_MODE)antialiasMode); + } + + public void PopAxisAlignedClip() => _handle->PopAxisAlignedClip(); + + public void Clear() => _handle->Clear(); + + public void Clear(ColorF clearColor) => _handle->Clear((DXGI_RGBA*)&clearColor); + + public Tags EndDraw(out bool recreateTarget) + { + Tags tags; + HResult result = _handle->EndDraw(&tags.One, &tags.Two).ToHResult(); + recreateTarget = result == HResult.D2DERR_RECREATE_TARGET; + result.ThrowIfFailed(); + return tags; + } + + public PixelFormat PixelFormat => new(_handle->GetPixelFormat()); + + public SizeF Size => _handle->GetSize().ToSizeF(); + + public SizeU PixelSize => new(_handle->GetPixelSize()); + + public uint MaximumBitmapSize => _handle->GetMaximumBitmapSize(); + + public bool IsSupported(RenderTargetProperties renderTargetProperties) + => _handle->IsSupported((D2D1_RENDER_TARGET_PROPERTIES*)&renderTargetProperties); + + public void Dispose() => _handle->Release(); + + public void DrawTextLayout( + PointF origin, + TextLayout textLayout, + Brush defaultFillBrush, + DrawTextOptions options = DrawTextOptions.None) + { + _handle->DrawTextLayout( + origin.ToD2D(), + textLayout.Handle, + defaultFillBrush.Handle, + (D2D1_DRAW_TEXT_OPTIONS)options); + } + } +} diff --git a/src/WInterop.DirectX/Direct2d/RenderTargetExtensions.cs b/src/WInterop.DirectX/Direct2d/RenderTargetExtensions.cs new file mode 100644 index 00000000..9adf5946 --- /dev/null +++ b/src/WInterop.DirectX/Direct2d/RenderTargetExtensions.cs @@ -0,0 +1,59 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Drawing; + +namespace WInterop.Direct2d +{ + public static class RenderTargetExtensions + { + public static SolidColorBrush CreateSolidColorBrush( + this IRenderTarget renderTarget, + float r, + float g, + float b, + float a = 1.0f) + => renderTarget.CreateSolidColorBrush(new(r, g, b, a)); + + public static IBitmapRenderTarget CreateCompatibleRenderTarget( + this IRenderTarget renderTarget, + (float X, float Y) desiredSize) + => renderTarget.CreateCompatibleRenderTarget(new(desiredSize.X, desiredSize.Y)); + + public static BitmapBrush CreateBitmapBrush( + this IRenderTarget renderTarget, + Bitmap bitmap, + BitmapBrushProperties bitmapBrushProperties) + => renderTarget.CreateBitmapBrush(bitmap, bitmapBrushProperties, BrushProperties.Default); + + public static RadialGradientBrush CreateRadialGradientBrush( + this IRenderTarget renderTarget, + RadialGradientBrushProperties radialGradientBrushProperties, + GradientStopCollection gradientStopCollection) + => renderTarget.CreateRadialGradientBrush(radialGradientBrushProperties, BrushProperties.Default, gradientStopCollection); + + public static Tags EndDraw( + this IRenderTarget renderTarget) + => renderTarget.EndDraw(out _); + + public unsafe static void DrawLine( + this IRenderTarget renderTarget, + (float X, float Y) point0, + (float X, float Y) point1, + Brush brush, + float strokeWidth = 1.0f, + StrokeStyle strokeStyle = default) + => renderTarget.DrawLine( + *(PointF*)&point0, + *(PointF*)&point1, + brush, + strokeWidth, + strokeStyle); + + //public static void FillRectangle( + // this IRenderTarget renderTarget, + // (float Left, float Top, float Right, float Bottom) rectangle, + // Brush brush) + // => renderTarget.FillRectangle(LtrbRectangleF.) + } +} diff --git a/src/WInterop.DirectX/Direct2d/RenderTargetProperties.cs b/src/WInterop.DirectX/Direct2d/RenderTargetProperties.cs index 7ff41fb4..88fded4b 100644 --- a/src/WInterop.DirectX/Direct2d/RenderTargetProperties.cs +++ b/src/WInterop.DirectX/Direct2d/RenderTargetProperties.cs @@ -1,6 +1,8 @@ // Copyright (c) Jeremy W. Kuhne. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using System.Runtime.CompilerServices; + namespace WInterop.Direct2d { /// @@ -16,5 +18,11 @@ public readonly struct RenderTargetProperties public readonly float DpiY; public readonly RenderTargetUsage Usage; public readonly FeatureLevel MinLevel; + + public static implicit operator RenderTargetProperties(in D2D1_RENDER_TARGET_PROPERTIES properties) + => Unsafe.As(ref Unsafe.AsRef(properties)); + + public static implicit operator D2D1_RENDER_TARGET_PROPERTIES(in RenderTargetProperties properties) + => Unsafe.As(ref Unsafe.AsRef(properties)); } } diff --git a/src/WInterop.DirectX/Direct2d/Resource.cs b/src/WInterop.DirectX/Direct2d/Resource.cs new file mode 100644 index 00000000..60a7ed37 --- /dev/null +++ b/src/WInterop.DirectX/Direct2d/Resource.cs @@ -0,0 +1,63 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace WInterop.Direct2d +{ + public interface IResource + { + Factory GetFactory(); + } + + internal interface IResource : IHandle where T : unmanaged + { + } + + internal unsafe static class ResourceExtensions + { + public static Factory GetFactory(this T resource) where T : IResource where H : unmanaged + { + ID2D1Factory* factory; + ((ID2D1Resource*)resource.Handle)->GetFactory(&factory); + return new(factory); + } + } + + [Guid(InterfaceIds.IID_ID2D1Resource)] + [StructLayout(LayoutKind.Sequential)] + public readonly unsafe struct Resource : Resource.Interface + { + private readonly ID2D1Resource* _resource; + + public Factory GetFactory() + { + ID2D1Factory* factory; + _resource->GetFactory(&factory); + return new(factory); + } + + internal static Factory GetFactory(ID2D1Resource* resource) + { + ID2D1Factory* factory; + resource->GetFactory(&factory); + return new(factory); + } + + internal static ref Brush From(in TFrom from) + where TFrom : unmanaged, Interface + => ref Unsafe.AsRef(Unsafe.AsPointer(ref Unsafe.AsRef(from))); + + public void Dispose() => _resource->Release(); + + /// + /// [ID2D1Resource] + /// + internal interface Interface : IDisposable + { + Factory GetFactory(); + } + } +} diff --git a/src/WInterop.DirectX/Direct2d/RoundedRectangle.cs b/src/WInterop.DirectX/Direct2d/RoundedRectangle.cs index 4777374c..df36e246 100644 --- a/src/WInterop.DirectX/Direct2d/RoundedRectangle.cs +++ b/src/WInterop.DirectX/Direct2d/RoundedRectangle.cs @@ -2,25 +2,27 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.Drawing; +using System.Runtime.InteropServices; namespace WInterop.Direct2d { /// /// [D2D1_ROUNDED_RECT] /// + [StructLayout(LayoutKind.Sequential)] public readonly struct RoundedRectangle { - private readonly LtrbRectangleF rect; + private readonly LtrbRectangleF _rect; public readonly float RadiusX; public readonly float RadiusY; public RoundedRectangle(RectangleF rectangle, float radiusX, float radiusY) { - rect = new LtrbRectangleF(rectangle); + _rect = new LtrbRectangleF(rectangle); RadiusX = radiusX; RadiusY = radiusY; } - public RectangleF Rectangle => rect; + public RectangleF Rectangle => _rect; } } diff --git a/src/WInterop.DirectX/Direct2d/RoundedRectangleGeometry.cs b/src/WInterop.DirectX/Direct2d/RoundedRectangleGeometry.cs new file mode 100644 index 00000000..fed8ed8a --- /dev/null +++ b/src/WInterop.DirectX/Direct2d/RoundedRectangleGeometry.cs @@ -0,0 +1,48 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Drawing; +using System.Numerics; +using System.Runtime.InteropServices; + +namespace WInterop.Direct2d +{ + /// + /// [ID2D1RoundedRectangleGeometry] + /// + [StructLayout(LayoutKind.Sequential)] + [Guid(InterfaceIds.IID_ID2D1RoundedRectangleGeometry)] + public unsafe struct RoundedRectangleGeometry : RoundedRectangleGeometry.Interface + { + private readonly ID2D1RoundedRectangleGeometry* _handle; + + internal RoundedRectangleGeometry(ID2D1RoundedRectangleGeometry* handle) => _handle = handle; + + public RectangleF GetBounds() => Geometry.From(this).GetBounds(); + + public RectangleF GetBounds(Matrix3x2 worldTransform) + => Geometry.From(this).GetBounds(worldTransform); + + public void CombineWithGeometry(Geometry inputGeometry, CombineMode combineMode, SimplifiedGeometrySink geometrySink) + => Geometry.From(this).CombineWithGeometry(inputGeometry, combineMode, geometrySink); + + public Factory GetFactory() => Resource.From(this).GetFactory(); + + public RoundedRectangle GetRoundedRect(RoundedRectangle roundedRect) + { + RoundedRectangle rect; + _handle->GetRoundedRect((D2D1_ROUNDED_RECT*) &rect); + return rect; + } + + public void Dispose() => _handle->Release(); + + public static implicit operator Geometry(RoundedRectangleGeometry geometry) => new((ID2D1Geometry*)geometry._handle); + + internal interface Interface : Geometry.Interface + { + RoundedRectangle GetRoundedRect(RoundedRectangle roundedRect); + } + } +} diff --git a/src/WInterop.DirectX/Direct2d/SimplifiedGeometrySink.cs b/src/WInterop.DirectX/Direct2d/SimplifiedGeometrySink.cs new file mode 100644 index 00000000..c628966a --- /dev/null +++ b/src/WInterop.DirectX/Direct2d/SimplifiedGeometrySink.cs @@ -0,0 +1,82 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Drawing; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace WInterop.Direct2d +{ + /// + /// Describes a geometric path that does not contain quadratic bezier curves or arcs. + /// [ID2D1SimplifiedGeometrySink] + /// + [StructLayout(LayoutKind.Sequential)] + [Guid(InterfaceIds.IID_ID2D1SimplifiedGeometrySink)] + public unsafe struct SimplifiedGeometrySink : SimplifiedGeometrySink.Interface, IDisposable + { + internal ID2D1SimplifiedGeometrySink* Handle { get; } + + internal SimplifiedGeometrySink(ID2D1SimplifiedGeometrySink* handle) => Handle = handle; + + public void AddBeziers(ReadOnlySpan beziers) + { + fixed(BezierSegment* b = beziers) + { + Handle->AddBeziers((D2D1_BEZIER_SEGMENT*)b, (uint)beziers.Length); + } + } + + public void AddLines(ReadOnlySpan points) + { + fixed(PointF* p = points) + { + Handle->AddLines((D2D_POINT_2F*)p, (uint)points.Length); + } + } + + public void BeginFigure(PointF startPoint, FigureBegin figureBegin) + => Handle->BeginFigure(startPoint.ToD2D(), (D2D1_FIGURE_BEGIN)figureBegin); + + public void BeginFigure((float X, float Y) startPoint, FigureBegin figureBegin) + => Handle->BeginFigure(new D2D_POINT_2F(startPoint.X, startPoint.Y), (D2D1_FIGURE_BEGIN)figureBegin); + + public void Close() => Handle->Close().ThrowIfFailed(); + + public void EndFigure(FigureEnd figureEnd) => Handle->EndFigure((D2D1_FIGURE_END)figureEnd); + + public void SetFillMode(FillMode fillMode) => Handle->SetFillMode((D2D1_FILL_MODE)fillMode); + + public void SetSegmentFlags(PathSegment vertexFlags) => Handle->SetSegmentFlags((D2D1_PATH_SEGMENT)vertexFlags); + + internal static ref SimplifiedGeometrySink From(in TFrom from) + where TFrom : unmanaged, Interface + => ref Unsafe.AsRef(Unsafe.AsPointer(ref Unsafe.AsRef(from))); + + public void Dispose() + { + Handle->Close(); + Handle->Release(); + } + + internal interface Interface : IDisposable + { + void SetFillMode(FillMode fillMode); + + void SetSegmentFlags(PathSegment vertexFlags); + + void BeginFigure( + PointF startPoint, + FigureBegin figureBegin); + + void AddLines(ReadOnlySpan points); + + void AddBeziers(ReadOnlySpan beziers); + + void EndFigure(FigureEnd figureEnd); + + void Close(); + } + } +} diff --git a/src/WInterop.DirectX/Direct2d/SizeU.cs b/src/WInterop.DirectX/Direct2d/SizeU.cs index 9a3cb91f..4657cf30 100644 --- a/src/WInterop.DirectX/Direct2d/SizeU.cs +++ b/src/WInterop.DirectX/Direct2d/SizeU.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.Drawing; +using System.Runtime.CompilerServices; namespace WInterop.Direct2d { @@ -19,7 +20,15 @@ public SizeU(uint width, uint height) Height = height; } - public static implicit operator Size(SizeU size) => new Size((int)size.Width, (int)size.Height); - public static implicit operator SizeU(Size size) => new SizeU((uint)size.Width, (uint)size.Height); + internal SizeU(D2D_SIZE_U size) + { + Width = size.width; + Height = size.height; + } + + public static implicit operator Size(SizeU size) => checked(new((int)size.Width, (int)size.Height)); + public static implicit operator SizeU(Size size) => checked(new((uint)size.Width, (uint)size.Height)); + + internal D2D_SIZE_U ToD2D() => Unsafe.As(ref Unsafe.AsRef(this)); } } diff --git a/src/WInterop.DirectX/Direct2d/SolidColorBrush.cs b/src/WInterop.DirectX/Direct2d/SolidColorBrush.cs new file mode 100644 index 00000000..a756a3ed --- /dev/null +++ b/src/WInterop.DirectX/Direct2d/SolidColorBrush.cs @@ -0,0 +1,48 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Numerics; +using System.Runtime.InteropServices; + +namespace WInterop.Direct2d +{ + /// + /// Paints an area with a solid color. [ID2D1SolidColorBrush] + /// + [StructLayout(LayoutKind.Sequential)] + [Guid(InterfaceIds.IID_ID2D1SolidColorBrush)] + public readonly unsafe struct SolidColorBrush : SolidColorBrush.Interface, IDisposable + { + private readonly ID2D1SolidColorBrush* _handle; + + public Factory GetFactory() => Resource.From(this).GetFactory(); + + public float Opacity + { + get => Brush.From(this).Opacity; + set => Brush.From(this).Opacity = value; + } + + public Matrix3x2 Transform + { + get => Brush.From(this).Transform; + set => Brush.From(this).Transform = value; + } + + public ColorF Color + { + get => _handle->GetColor(); + set => _handle->SetColor((DXGI_RGBA*)&value); + } + + public void Dispose() => _handle->Release(); + + public static implicit operator Brush(SolidColorBrush brush) => new((ID2D1Brush*)brush._handle); + + internal interface Interface : Brush.Interface + { + ColorF Color { get; set; } + } + } +} diff --git a/src/WInterop.DirectX/Direct2d/StrokeStyle.cs b/src/WInterop.DirectX/Direct2d/StrokeStyle.cs new file mode 100644 index 00000000..dd1853c7 --- /dev/null +++ b/src/WInterop.DirectX/Direct2d/StrokeStyle.cs @@ -0,0 +1,70 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Runtime.InteropServices; + +namespace WInterop.Direct2d +{ + [StructLayout(LayoutKind.Sequential)] + [Guid(InterfaceIds.IID_ID2D1StrokeStyle)] + public readonly unsafe struct StrokeStyle : StrokeStyle.Interface, IDisposable + { + internal readonly ID2D1StrokeStyle* _handle; + + internal StrokeStyle(ID2D1StrokeStyle* handle) => _handle = handle; + + public Factory GetFactory() => Resource.From(this).GetFactory(); + + public CapStyle StartCap => (CapStyle)_handle->GetStartCap(); + + public CapStyle EndCap => (CapStyle)_handle->GetEndCap(); + + public CapStyle DashCap => (CapStyle)_handle->GetDashCap(); + + public float MiterLimit => _handle->GetMiterLimit(); + + public LineJoin LineJoin => (LineJoin)_handle->GetLineJoin(); + + public float DashOffset => _handle->GetDashOffset(); + + public DashStyle DashStyle => (DashStyle)_handle->GetDashStyle(); + + public uint DashesCount => _handle->GetDashesCount(); + + public void GetDashes(Span dashes) + { + fixed (float* f = dashes) + { + _handle->GetDashes(f, (uint)dashes.Length); + } + } + + public void Dispose() => _handle->Release(); + + internal interface Interface : Resource.Interface + { + CapStyle StartCap { get; } + + CapStyle EndCap { get; } + + CapStyle DashCap { get; } + + float MiterLimit { get; } + + LineJoin LineJoin { get; } + + float DashOffset { get; } + + DashStyle DashStyle { get; } + + uint DashesCount { get; } + + /// + /// Returns the dashes from the object into a user allocated array. + /// Call to retrieve the required size. + /// + void GetDashes(Span dashes); + } + } +} diff --git a/src/WInterop.DirectX/Direct2d/SweepDirection.cs b/src/WInterop.DirectX/Direct2d/SweepDirection.cs index 5c44c8b9..cb65f5f6 100644 --- a/src/WInterop.DirectX/Direct2d/SweepDirection.cs +++ b/src/WInterop.DirectX/Direct2d/SweepDirection.cs @@ -11,11 +11,11 @@ public enum SweepDirection : uint /// /// [D2D1_SWEEP_DIRECTION_COUNTER_CLOCKWISE] /// - CounterClockwise = 0, + CounterClockwise = D2D1_SWEEP_DIRECTION.D2D1_SWEEP_DIRECTION_COUNTER_CLOCKWISE, /// /// [D2D1_SWEEP_DIRECTION_CLOCKWISE] /// - Clockwise = 1 + Clockwise = D2D1_SWEEP_DIRECTION.D2D1_SWEEP_DIRECTION_CLOCKWISE } } diff --git a/src/WInterop.DirectX/Direct2d/Tags.cs b/src/WInterop.DirectX/Direct2d/Tags.cs new file mode 100644 index 00000000..9746d0d7 --- /dev/null +++ b/src/WInterop.DirectX/Direct2d/Tags.cs @@ -0,0 +1,11 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace WInterop.Direct2d +{ + public struct Tags + { + public ulong One; + public ulong Two; + } +} diff --git a/src/WInterop.DirectX/Direct2d/TransformedGeometry.cs b/src/WInterop.DirectX/Direct2d/TransformedGeometry.cs new file mode 100644 index 00000000..65cf3207 --- /dev/null +++ b/src/WInterop.DirectX/Direct2d/TransformedGeometry.cs @@ -0,0 +1,63 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Drawing; +using System.Numerics; +using System.Runtime.InteropServices; + +namespace WInterop.Direct2d +{ + /// + /// Represents a geometry that has been transformed. [ID2D1TransformedGeometry] + /// + [Guid(InterfaceIds.IID_ID2D1TransformedGeometry)] + [StructLayout(LayoutKind.Sequential)] + public readonly unsafe struct TransformedGeometry : TransformedGeometry.Interface, IDisposable + { + internal readonly ID2D1TransformedGeometry* _handle; + + internal TransformedGeometry(ID2D1TransformedGeometry* handle) => _handle = handle; + + public RectangleF GetBounds() => Geometry.From(this).GetBounds(); + + public RectangleF GetBounds(Matrix3x2 worldTransform) + => Geometry.From(this).GetBounds(worldTransform); + + public void CombineWithGeometry(Geometry inputGeometry, CombineMode combineMode, SimplifiedGeometrySink geometrySink) + => Geometry.From(this).CombineWithGeometry(inputGeometry, combineMode, geometrySink); + + public Factory GetFactory() => Resource.From(this).GetFactory(); + + public Geometry SourceGeometry + { + get + { + Geometry geometry; + _handle->GetSourceGeometry((ID2D1Geometry**)&geometry); + return geometry; + } + } + + public Matrix3x2 Transform + { + get + { + Matrix3x2 transform; + _handle->GetTransform((D2D_MATRIX_3X2_F*)&transform); + return transform; + } + } + + public static implicit operator Geometry(TransformedGeometry geometry) => new((ID2D1Geometry*)geometry._handle); + + public void Dispose() => _handle->Release(); + + internal interface Interface : Geometry.Interface + { + Geometry SourceGeometry { get; } + + Matrix3x2 Transform { get; } + } + } +} diff --git a/src/WInterop.DirectX/Direct2d/WindowRenderTarget.cs b/src/WInterop.DirectX/Direct2d/WindowRenderTarget.cs new file mode 100644 index 00000000..9587ce5d --- /dev/null +++ b/src/WInterop.DirectX/Direct2d/WindowRenderTarget.cs @@ -0,0 +1,26 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Runtime.InteropServices; + +namespace WInterop.Direct2d +{ + /// + /// Renders drawing instructions to a window. [ID2D1HwndRenderTarget] + /// + [StructLayout(LayoutKind.Sequential)] + internal unsafe class WindowRenderTarget : RenderTarget, IWindowRenderTarget + { + private readonly ID2D1HwndRenderTarget* _handle; + + internal WindowRenderTarget(ID2D1HwndRenderTarget* handle) + : base ((ID2D1RenderTarget*)handle) + => _handle = handle; + + public WindowState CheckWindowState() => (WindowState)_handle->CheckWindowState(); + + public void Resize(SizeU pixelSize) => _handle->Resize((D2D_SIZE_U*)&pixelSize).ThrowIfFailed(); + + public Windows.Native.HWND GetHwnd() => new(_handle->GetHwnd()); + } +} diff --git a/src/WInterop.DirectX/Direct2d/WindowRenderTargetProperties.cs b/src/WInterop.DirectX/Direct2d/WindowRenderTargetProperties.cs index 885ffcb1..5640a5ab 100644 --- a/src/WInterop.DirectX/Direct2d/WindowRenderTargetProperties.cs +++ b/src/WInterop.DirectX/Direct2d/WindowRenderTargetProperties.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.Drawing; +using System.Runtime.InteropServices; using WInterop.Windows; using WInterop.Windows.Native; @@ -11,6 +12,7 @@ namespace WInterop.Direct2d /// Contains the HWND, pixel size, and presentation options for an ID2D1HwndRenderTarget. /// [D2D1_HWND_RENDER_TARGET_PROPERTIES] /// + [StructLayout(LayoutKind.Sequential)] public readonly struct WindowRenderTargetProperties { private readonly HWND _hwnd; diff --git a/src/WInterop.DirectX/DirectWrite/DirectWrite.cs b/src/WInterop.DirectX/DirectWrite/DirectWrite.cs index 30873e41..9d27a1fc 100644 --- a/src/WInterop.DirectX/DirectWrite/DirectWrite.cs +++ b/src/WInterop.DirectX/DirectWrite/DirectWrite.cs @@ -9,10 +9,10 @@ namespace WInterop.DirectWrite { public static class DirectWrite { - public static IFactory CreateFactory(FactoryType factoryType = FactoryType.Shared) + public static WriteFactory CreateFactory(FactoryType factoryType = FactoryType.Shared) { Imports.DWriteCreateFactory( - factoryType, new Guid(InterfaceIds.IID_IDWriteFactory), out IFactory factory) + factoryType, new Guid(InterfaceIds.IID_IDWriteFactory), out WriteFactory factory) .ThrowIfFailed(); return factory; diff --git a/src/WInterop.DirectX/DirectWrite/FlowDirection.cs b/src/WInterop.DirectX/DirectWrite/FlowDirection.cs index 0c9b3e41..b6643ac7 100644 --- a/src/WInterop.DirectX/DirectWrite/FlowDirection.cs +++ b/src/WInterop.DirectX/DirectWrite/FlowDirection.cs @@ -11,21 +11,21 @@ public enum FlowDirection : uint /// /// Text lines are placed from top to bottom. /// - TopToBottom = 0, + TopToBottom = DWRITE_FLOW_DIRECTION.DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM, /// /// Text lines are placed from bottom to top. /// - BottomToTop = 1, + BottomToTop = DWRITE_FLOW_DIRECTION.DWRITE_FLOW_DIRECTION_BOTTOM_TO_TOP, /// /// Text lines are placed from left to right. /// - LeftToRight = 2, + LeftToRight = DWRITE_FLOW_DIRECTION.DWRITE_FLOW_DIRECTION_LEFT_TO_RIGHT, /// /// Text lines are placed from right to left. /// - RightToLeft = 3, + RightToLeft = DWRITE_FLOW_DIRECTION.DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT, } } diff --git a/src/WInterop.DirectX/DirectWrite/Font.cs b/src/WInterop.DirectX/DirectWrite/Font.cs new file mode 100644 index 00000000..e72540ab --- /dev/null +++ b/src/WInterop.DirectX/DirectWrite/Font.cs @@ -0,0 +1,151 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Runtime.InteropServices; +using WInterop.Direct2d; + +namespace WInterop.DirectWrite +{ + /// + /// The interface represents a physical font in a font collection. + /// [IDWriteFont] + /// + [Guid(InterfaceIds.IID_IDWriteFont)] + public readonly unsafe struct Font : Font.Interface, IDisposable + { + private readonly IDWriteFont* _handle; + + internal Font(IDWriteFont* handle) => _handle = handle; + + public FontWeight Weight => (FontWeight)_handle->GetWeight(); + + public FontStretch Stretch => (FontStretch)_handle->GetStretch(); + + public FontStyle Style => (FontStyle)_handle->GetStyle(); + + public bool IsSymbolFont => _handle->IsSymbolFont(); + + public FontSimulations Simulations => (FontSimulations)_handle->GetSimulations(); + + public FontMetrics Metrics + { + get + { + FontMetrics* metrics; + _handle->GetMetrics((DWRITE_FONT_METRICS*)&metrics); + return Metrics; + } + } + + public FontFace CreateFontFace() + { + IDWriteFontFace* fontFace; + _handle->CreateFontFace(&fontFace).ThrowIfFailed(); + return new(fontFace); + } + + public void Dispose() => _handle->Release(); + + public LocalizedStrings GetFaceNames() + { + IDWriteLocalizedStrings* strings; + _handle->GetFaceNames(&strings).ThrowIfFailed(); + return new(strings); + } + + public FontFamily GetFontFamily() + { + IDWriteFontFamily* family; + _handle->GetFontFamily(&family).ThrowIfFailed(); + return new(family); + } + + public bool GetInformationalStrings(InformationalStringId informationalStringID, out LocalizedStrings informationalStrings) + { + IDWriteLocalizedStrings* strings; + TerraFX.Interop.Windows.BOOL exists; + _handle->GetInformationalStrings((DWRITE_INFORMATIONAL_STRING_ID)informationalStringID, &strings, &exists).ThrowIfFailed(); + informationalStrings = new(strings); + return exists; + } + + public bool HasCharacter(uint unicodeValue) + { + TerraFX.Interop.Windows.BOOL exists; + _handle->HasCharacter(unicodeValue, &exists).ThrowIfFailed(); + return exists; + } + + internal interface Interface + { + /// + /// Gets the font family to which the specified font belongs. + /// + FontFamily GetFontFamily(); + + /// + /// Gets the weight of the specified font. + /// + FontWeight Weight { get; } + + /// + /// Gets the stretch (aka. width) of the specified font. + /// + FontStretch Stretch { get; } + + /// + /// Gets the style (aka. slope) of the specified font. + /// + FontStyle Style { get; } + + /// + /// Returns TRUE if the font is a symbol font or FALSE if not. + /// + bool IsSymbolFont { get; } + + /// + /// Gets a localized strings collection containing the face names for the font (e.g., Regular or Bold), indexed by locale name. + /// + /// + /// A pointer to the newly created localized strings object. + /// + LocalizedStrings GetFaceNames(); + + /// + /// Gets a localized strings collection containing the specified informational strings, indexed by locale name. + /// + /// Identifies the string to get. + /// Receives a pointer to the newly created localized strings object. + bool GetInformationalStrings( + InformationalStringId informationalStringID, + out LocalizedStrings informationalStrings); + + /// + /// Gets a value that indicates what simulation are applied to the specified font. + /// + FontSimulations Simulations { get; } + + /// + /// Gets the metrics for the font. + /// + /// Receives the font metrics. + FontMetrics Metrics { get; } + + /// + /// Determines whether the font supports the specified character. + /// + /// Unicode (UCS-4) character value. + /// Receives the value TRUE if the font supports the specified character or FALSE if not. + bool HasCharacter(uint unicodeValue); + + /// + /// Creates a font face object for the font. + /// + /// + /// S pointer to the newly created font face object. + /// + FontFace CreateFontFace(); + } + } +} diff --git a/src/WInterop.DirectX/DirectWrite/FontCollection.cs b/src/WInterop.DirectX/DirectWrite/FontCollection.cs new file mode 100644 index 00000000..e23c92d7 --- /dev/null +++ b/src/WInterop.DirectX/DirectWrite/FontCollection.cs @@ -0,0 +1,79 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Runtime.InteropServices; + +namespace WInterop.DirectWrite +{ + /// + /// The IDWriteFontCollection encapsulates a collection of font families. [IDWriteFontCollection] + /// + [Guid(InterfaceIds.IID_IDWriteFontCollection)] + public readonly unsafe struct FontCollection : FontCollection.Interface, IDisposable + { + internal IDWriteFontCollection* Handle { get; } + + internal FontCollection(IDWriteFontCollection* handle) => Handle = handle; + + public uint FontFamilyCount => Handle->GetFontFamilyCount(); + + public void Dispose() => Handle->Release(); + + public bool FindFamilyName(string familyName, out uint index) + { + TerraFX.Interop.Windows.BOOL exists; + fixed (void* n = familyName) + fixed (uint* i = &index) + { + Handle->FindFamilyName((ushort*)n, i, &exists).ThrowIfFailed(); + } + + return exists; + } + + public FontFamily GetFontFamily(uint index) + { + IDWriteFontFamily* family; + Handle->GetFontFamily(index, &family).ThrowIfFailed(); + return new(family); + } + + public Font GetFontFromFontFace(FontFace fontFace) + { + IDWriteFont* font; + Handle->GetFontFromFontFace(fontFace._handle, &font).ThrowIfFailed(); + return new(font); + } + + internal interface Interface + { + /// + /// Gets the number of font families in the collection. + /// + uint FontFamilyCount { get; } + + /// + /// Creates a font family object given a zero-based font family index. + /// + /// Zero-based index of the font family. + FontFamily GetFontFamily(uint index); + + /// + /// Finds the font family with the specified family name. + /// + /// Name of the font family. The name is not case-sensitive but must otherwise exactly match a family name in the collection. + /// Receives the zero-based index of the matching font family if the family name was found or UINT_MAX otherwise. + bool FindFamilyName( + string familyName, + out uint index); + + /// + /// Gets the font object that corresponds to the same physical font as the specified font face object. The specified physical font must belong + /// to the font collection. + /// + /// Font face object that specifies the physical font. + Font GetFontFromFontFace(FontFace fontFace); + } + } +} diff --git a/src/WInterop.DirectX/DirectWrite/FontFace.cs b/src/WInterop.DirectX/DirectWrite/FontFace.cs new file mode 100644 index 00000000..0c6001c6 --- /dev/null +++ b/src/WInterop.DirectX/DirectWrite/FontFace.cs @@ -0,0 +1,358 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Numerics; +using System.Runtime.InteropServices; +using WInterop.Direct2d; + +namespace WInterop.DirectWrite +{ + /// + /// This interface exposes various font data such as metrics, names, and glyph outlines. + /// It contains font face type, appropriate file references and face identification data. + /// [IDWriteFontFace] + /// + [Guid(InterfaceIds.IID_IDWriteFontFace)] + public unsafe readonly struct FontFace : FontFace.Interface, IDisposable + { + internal readonly IDWriteFontFace* _handle; + + internal FontFace(IDWriteFontFace* handle) => _handle = handle; + + public FontFaceType Type => (FontFaceType)_handle->GetType(); + + public uint Index => _handle->GetIndex(); + + public FontSimulations Simulations => (FontSimulations)_handle->GetSimulations(); + + public FontMetrics Metrics + { + get + { + FontMetrics metrics; + _handle->GetMetrics((DWRITE_FONT_METRICS*)&metrics); + return metrics; + } + } + + public void Dispose() => _handle->Release(); + + public void GetGdiCompatibleGlyphMetrics( + float emSize, + float pixelsPerDip, + Matrix3x2 transform, + bool useGdiNatural, + ReadOnlySpan glyphIndices, + Span glyphMetrics, + bool isSideways) + { + if (glyphMetrics.Length != glyphIndices.Length) + throw new ArgumentException($"{nameof(glyphIndices)} and {nameof(glyphMetrics)} must have matching lengths"); + + fixed (ushort* i = glyphIndices) + fixed (GlyphMetrics* m = glyphMetrics) + { + _handle->GetGdiCompatibleGlyphMetrics( + emSize, + pixelsPerDip, + (DWRITE_MATRIX*)&transform, + useGdiNatural, + i, + (uint)glyphIndices.Length, + (DWRITE_GLYPH_METRICS*)m, + isSideways).ThrowIfFailed(); + } + } + + public FontMetrics GetGdiCompatibleMetrics(float emSize, float pixelsPerDip, Matrix3x2 transform) + { + FontMetrics metrics; + _handle->GetGdiCompatibleMetrics(emSize, + pixelsPerDip, + (DWRITE_MATRIX*)&transform, + (DWRITE_FONT_METRICS*)&metrics).ThrowIfFailed(); + return metrics; + } + + public ushort GlyphCount => _handle->GetGlyphCount(); + + public void GetGlyphRunOutline( + float emSize, + ReadOnlySpan glyphIndices, + ReadOnlySpan glyphAdvances, + ReadOnlySpan glyphOffsets, + bool isSideways, + bool isRightToLeft, + SimplifiedGeometrySink geometrySink) + { + fixed (ushort* gi = glyphIndices) + fixed (float* ga = glyphAdvances) + fixed (void* go = glyphOffsets) + { + _handle->GetGlyphRunOutline( + emSize, + gi, + ga, + (DWRITE_GLYPH_OFFSET*)go, + (uint)glyphIndices.Length, + isSideways, + isRightToLeft, + geometrySink.Handle).ThrowIfFailed(); + } + } + + public RenderingMode GetRecommendedRenderingMode( + float emSize, + float pixelsPerDip, + MeasuringMode measuringMode, + RenderingParams renderingParams) + { + RenderingMode renderingMode; + _handle->GetRecommendedRenderingMode( + emSize, + pixelsPerDip, + (DWRITE_MEASURING_MODE)measuringMode, + renderingParams.Handle, + (DWRITE_RENDERING_MODE*)&renderingMode).ThrowIfFailed(); + + return renderingMode; + } + + public bool IsSymbolFont() => _handle->IsSymbolFont(); + + internal interface Interface + { + /// + /// Obtains the file format type of a font face. + /// + FontFaceType Type { get; } + +/* + /// + /// Obtains the font files representing a font face. + /// + /// The number of files representing the font face. + /// User provided array that stores pointers to font files representing the font face. + /// This parameter can be NULL if the user is only interested in the number of files representing the font face. + /// This API increments reference count of the font file pointers returned according to COM conventions, and the client + /// should release them when finished. + /// + /// Standard HRESULT error code. + /// + //STDMETHOD(GetFiles)( + // _Inout_ UINT32* numberOfFiles, + // _Out_writes_opt_(*numberOfFiles) IDWriteFontFile** fontFiles + //) PURE; +*/ + + /// + /// Obtains the zero-based index of the font face in its font file or files. If the font files contain a single face, + /// the return value is zero. + /// + uint Index { get; } + + /// + /// Obtains the algorithmic style simulation flags of a font face. + /// + FontSimulations Simulations { get; } + + /// + /// Determines whether the font is a symbol font. + /// + bool IsSymbolFont(); + + /// + /// Obtains design units and common metrics for the font face. + /// These metrics are applicable to all the glyphs within a fontface and are used by applications for layout calculations. + /// + FontMetrics Metrics { get; } + + /// + /// Obtains the number of glyphs in the font face. + /// + ushort GlyphCount { get; } + +/* + ///// An array of glyph indices to compute the metrics for. + ///// The number of elements in the glyphIndices array. + ///// Array of DWRITE_GLYPH_METRICS structures filled by this function. + ///// The metrics returned by this function are in font design units. + ///// Indicates whether the font is being used in a sideways run. + ///// This can affect the glyph metrics if the font has oblique simulation + ///// because sideways oblique simulation differs from non-sideways oblique simulation. + /// + /// Obtains ideal glyph metrics in font design units. Design glyphs metrics are used for glyph positioning. + /// + /// + /// Standard HRESULT error code. If any of the input glyph indices are outside of the valid glyph index range + /// for the current font face, E_INVALIDARG will be returned. + /// + // void GetDesignGlyphMetricsSTUB(); + //STDMETHOD(GetDesignGlyphMetrics)( + // _In_reads_(glyphCount) UINT16 const* glyphIndices, + // UINT32 glyphCount, + //_Out_writes_(glyphCount) DWRITE_GLYPH_METRICS* glyphMetrics, + //BOOL isSideways = FALSE + //) PURE; + + /// + /// Returns the nominal mapping of UTF-32 Unicode code points to glyph indices as defined by the font 'cmap' + /// table. Note that this mapping is primarily provided for line layout engines built on top of the physical + /// font API. Because of OpenType glyph substitution and line layout character substitution, the nominal + /// conversion does not always correspond to how a Unicode string will map to glyph indices when rendering + /// using a particular font face. Also, note that Unicode Variation Selectors provide for alternate mappings + /// for character to glyph. This call will always return the default variant. + /// + /// An array of UTF-32 code points to obtain nominal glyph indices from. + /// The number of elements in the codePoints array. + /// Array of nominal glyph indices filled by this function. + /// + /// Standard HRESULT error code. + /// + //unsafe void GetGlyphIndices( + // uint* codePoints, + // uint codePointCount, + // ushort* glyphIndices); + + /// + /// Finds the specified OpenType font table if it exists and returns a pointer to it. + /// The function accesses the underlying font data via the IDWriteFontFileStream interface + /// implemented by the font file loader. + /// + /// Four character tag of table to find. + /// Use the DWRITE_MAKE_OPENTYPE_TAG() macro to create it. + /// Unlike GDI, it does not support the special TTCF and null tags to access the whole font. + /// + /// Pointer to base of table in memory. + /// The pointer is only valid so long as the FontFace used to get the font table still exists + /// (not any other FontFace, even if it actually refers to the same physical font). + /// + /// Byte size of table. + /// + /// Opaque context which must be freed by calling ReleaseFontTable. + /// The context actually comes from the lower level IDWriteFontFileStream, + /// which may be implemented by the application or DWrite itself. + /// It is possible for a NULL tableContext to be returned, especially if + /// the implementation directly memory maps the whole file. + /// Nevertheless, always release it later, and do not use it as a test for function success. + /// The same table can be queried multiple times, + /// but each returned context can be different, so release each separately. + /// + /// True if table exists. + /// + /// Standard HRESULT error code. + /// If a table can not be found, the function will not return an error, but the size will be 0, table NULL, and exists = FALSE. + /// The context does not need to be freed if the table was not found. + /// + /// + /// The context for the same tag may be different for each call, + /// so each one must be held and released separately. + /// + //unsafe IntBoolean TryGetFontTable( + // uint openTypeTableTag, + // void** tableData, + // out uint tableSize, + // out IntPtr tableContext, + // out IntBoolean exists); + + /// + /// Releases the table obtained earlier from TryGetFontTable. + /// + /// Opaque context from TryGetFontTable. + //void ReleaseFontTable(IntPtr tableContext); + + */ + + /// + /// Computes the outline of a run of glyphs by calling back to the outline sink interface. + /// + /// Logical size of the font in DIP units. A DIP ("device-independent pixel") equals 1/96 inch. + /// Array of glyph indices. + /// Optional array of glyph advances in DIPs. + /// Optional array of glyph offsets. + /// If true, specifies that glyphs are rotated 90 degrees to the left and vertical metrics are used. + /// A client can render a vertical run by specifying isSideways = true and rotating the resulting geometry 90 degrees to the + /// right using a transform. + /// If true, specifies that the advance direction is right to left. By default, the advance direction + /// is left to right. + /// Interface the function calls back to draw each element of the geometry. + unsafe void GetGlyphRunOutline( + float emSize, + ReadOnlySpan glyphIndices, + ReadOnlySpan glyphAdvances, + ReadOnlySpan glyphOffsets, + bool isSideways, + bool isRightToLeft, + SimplifiedGeometrySink geometrySink); + + /// + /// Determines the recommended rendering mode for the font given the specified size and rendering parameters. + /// + /// Logical size of the font in DIP units. A DIP ("device-independent pixel") equals 1/96 inch. + /// Number of physical pixels per DIP. For example, if the DPI of the rendering surface is 96 this + /// value is 1.0f. If the DPI is 120, this value is 120.0f/96. + /// Specifies measuring mode that will be used for glyphs in the font. + /// Renderer implementations may choose different rendering modes for given measuring modes, but + /// best results are seen when the corresponding modes match: + /// for + /// for + /// for + /// + /// Rendering parameters object. This parameter is necessary in case the rendering parameters + /// object overrides the rendering mode. + /// + /// The recommended rendering mode to use. + /// + RenderingMode GetRecommendedRenderingMode( + float emSize, + float pixelsPerDip, + MeasuringMode measuringMode, + RenderingParams renderingParams); + + /// + /// Obtains design units and common metrics for the font face. + /// These metrics are applicable to all the glyphs within a fontface and are used by applications for layout calculations. + /// + /// Logical size of the font in DIP units. A DIP ("device-independent pixel") equals 1/96 inch. + /// Number of physical pixels per DIP. For example, if the DPI of the rendering surface is 96 this + /// value is 1.0f. If the DPI is 120, this value is 120.0f/96. + /// Optional transform applied to the glyphs and their positions. This transform is applied after the + /// scaling specified by the font size and pixelsPerDip. + unsafe FontMetrics GetGdiCompatibleMetrics( + float emSize, + float pixelsPerDip, + Matrix3x2 transform); + + /// + /// Obtains glyph metrics in font design units with the return values compatible with what GDI would produce. + /// Glyphs metrics are used for positioning of individual glyphs. + /// + /// Logical size of the font in DIP units. A DIP ("device-independent pixel") equals 1/96 inch. + /// Number of physical pixels per DIP. For example, if the DPI of the rendering surface is 96 this + /// value is 1.0f. If the DPI is 120, this value is 120.0f/96. + /// Optional transform applied to the glyphs and their positions. This transform is applied after the + /// scaling specified by the font size and pixelsPerDip. + /// + /// When set to FALSE, the metrics are the same as the metrics of GDI aliased text. + /// When set to TRUE, the metrics are the same as the metrics of text measured by GDI using a font + /// created with CLEARTYPE_NATURAL_QUALITY. + /// + /// An array of glyph indices to compute the metrics for. + /// The number of elements in the glyphIndices array. + /// Array of DWRITE_GLYPH_METRICS structures filled by this function. + /// The metrics returned by this function are in font design units. + /// Indicates whether the font is being used in a sideways run. + /// This can affect the glyph metrics if the font has oblique simulation + /// because sideways oblique simulation differs from non-sideways oblique simulation. + unsafe void GetGdiCompatibleGlyphMetrics( + float emSize, + float pixelsPerDip, + Matrix3x2 transform, + bool useGdiNatural, + ReadOnlySpan glyphIndices, + Span glyphMetrics, + bool isSideways); + } + } +} diff --git a/src/WInterop.DirectX/DirectWrite/FontFaceType.cs b/src/WInterop.DirectX/DirectWrite/FontFaceType.cs index 075f96a7..a17c4756 100644 --- a/src/WInterop.DirectX/DirectWrite/FontFaceType.cs +++ b/src/WInterop.DirectX/DirectWrite/FontFaceType.cs @@ -15,37 +15,37 @@ public enum FontFaceType : uint /// /// OpenType font face with CFF outlines. /// - Cff, + Cff = DWRITE_FONT_FACE_TYPE.DWRITE_FONT_FACE_TYPE_CFF, /// /// OpenType font face with TrueType outlines. /// - TrueType, + TrueType = DWRITE_FONT_FACE_TYPE.DWRITE_FONT_FACE_TYPE_TRUETYPE, /// /// OpenType font face that is a part of a TrueType or CFF collection. /// - OpenTypeCollection, + OpenTypeCollection = DWRITE_FONT_FACE_TYPE.DWRITE_FONT_FACE_TYPE_OPENTYPE_COLLECTION, /// /// A Type 1 font face. /// - Type1, + Type1 = DWRITE_FONT_FACE_TYPE.DWRITE_FONT_FACE_TYPE_TYPE1, /// /// A vector .FON format font face. /// - Vector, + Vector = DWRITE_FONT_FACE_TYPE.DWRITE_FONT_FACE_TYPE_VECTOR, /// /// A bitmap .FON format font face. /// - Bitmap, + Bitmap = DWRITE_FONT_FACE_TYPE.DWRITE_FONT_FACE_TYPE_BITMAP, /// /// Font face type is not recognized by the DirectWrite font system. /// - Unknown, + Unknown = DWRITE_FONT_FACE_TYPE.DWRITE_FONT_FACE_TYPE_UNKNOWN, /// /// The font data includes only the CFF table from an OpenType CFF font. @@ -53,6 +53,6 @@ public enum FontFaceType : uint /// font file loaders) and the resulting font face object supports only the /// minimum functionality necessary to render glyphs. /// - RawCff + RawCff = DWRITE_FONT_FACE_TYPE.DWRITE_FONT_FACE_TYPE_RAW_CFF } } diff --git a/src/WInterop.DirectX/DirectWrite/FontFamily.cs b/src/WInterop.DirectX/DirectWrite/FontFamily.cs new file mode 100644 index 00000000..14432e49 --- /dev/null +++ b/src/WInterop.DirectX/DirectWrite/FontFamily.cs @@ -0,0 +1,90 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Runtime.InteropServices; +using WInterop.Direct2d; + +namespace WInterop.DirectWrite +{ + /// + /// The IDWriteFontFamily interface represents a set of fonts that share the same design but are differentiated + /// by weight, stretch, and style. [IDWriteFontFamily] + /// + [Guid(InterfaceIds.IID_IDWriteFontFamily)] + public readonly unsafe struct FontFamily : FontFamily.Interface, IDisposable + { + private readonly IDWriteFontFamily* _handle; + + internal FontFamily(IDWriteFontFamily* handle) => _handle = handle; + + public uint FontCount => throw new NotImplementedException(); + + public void Dispose() => _handle->Release(); + + public LocalizedStrings GetFamilyNames() + { + IDWriteLocalizedStrings* names; + _handle->GetFamilyNames(&names).ThrowIfFailed(); + return new(names); + } + + public Font GetFont(uint index) => FontList.From(this).GetFont(index); + + public FontCollection GetFontCollection() => FontList.From(this).GetFontCollection(); + + public Font GetFirstMatchingFont(FontWeight weight, FontStretch stretch, FontStyle style) + { + IDWriteFont* font; + _handle->GetFirstMatchingFont( + (DWRITE_FONT_WEIGHT)weight, + (DWRITE_FONT_STRETCH)stretch, + (DWRITE_FONT_STYLE)style, + &font).ThrowIfFailed(); + + return new(font); + } + + public FontList GetMatchingFonts(FontWeight weight, FontStretch stretch, FontStyle style) + { + IDWriteFontList* fontList; + _handle->GetMatchingFonts( + (DWRITE_FONT_WEIGHT)weight, + (DWRITE_FONT_STRETCH)stretch, + (DWRITE_FONT_STYLE)style, + &fontList).ThrowIfFailed(); + + return new(fontList); + } + + internal interface Interface : FontList.Interface + { + /// + /// Creates a localized strings object that contains the family names for the font family, indexed by locale name. + /// + LocalizedStrings GetFamilyNames(); + + /// + /// Gets the font that best matches the specified properties. + /// + /// Requested font weight. + /// Requested font stretch. + /// Requested font style. + Font GetFirstMatchingFont( + FontWeight weight, + FontStretch stretch, + FontStyle style); + + /// + /// Gets a list of fonts in the font family ranked in order of how well they match the specified properties. + /// + /// Requested font weight. + /// Requested font stretch. + /// Requested font style. + FontList GetMatchingFonts( + FontWeight weight, + FontStretch stretch, + FontStyle style); + } + } +} diff --git a/src/WInterop.DirectX/DirectWrite/FontFeatureTag.cs b/src/WInterop.DirectX/DirectWrite/FontFeatureTag.cs index 8eb68b08..f857cd51 100644 --- a/src/WInterop.DirectX/DirectWrite/FontFeatureTag.cs +++ b/src/WInterop.DirectX/DirectWrite/FontFeatureTag.cs @@ -8,86 +8,86 @@ namespace WInterop.DirectWrite /// public enum FontFeatureTag : uint { - AlternativeFractions = ((byte)'a') | ((byte)'f' << 8) | ((byte)'r' << 16) | ((byte)'c' << 24), - PetiteCapitalsFromCapitals = ((byte)'c') | ((byte)'2' << 8) | ((byte)'p' << 16) | ((byte)'c' << 24), - SmallCapitalsFromCapitals = ((byte)'c') | ((byte)'2' << 8) | ((byte)'s' << 16) | ((byte)'c' << 24), - ContextualAlternates = ((byte)'c') | ((byte)'a' << 8) | ((byte)'l' << 16) | ((byte)'t' << 24), - CaseSensitiveForms = ((byte)'c') | ((byte)'a' << 8) | ((byte)'s' << 16) | ((byte)'e' << 24), - GlyphCompositionDecomposition = ((byte)'c') | ((byte)'c' << 8) | ((byte)'m' << 16) | ((byte)'p' << 24), - ContextualLigatures = ((byte)'c') | ((byte)'l' << 8) | ((byte)'i' << 16) | ((byte)'g' << 24), - CapitalSpacing = ((byte)'c') | ((byte)'p' << 8) | ((byte)'s' << 16) | ((byte)'p' << 24), - ContextualSwash = ((byte)'c') | ((byte)'s' << 8) | ((byte)'w' << 16) | ((byte)'h' << 24), - CursivePositioning = ((byte)'c') | ((byte)'u' << 8) | ((byte)'r' << 16) | ((byte)'s' << 24), - Default = ((byte)'d') | ((byte)'f' << 8) | ((byte)'l' << 16) | ((byte)'t' << 24), - DiscretionaryLigatures = ((byte)'d') | ((byte)'l' << 8) | ((byte)'i' << 16) | ((byte)'g' << 24), - ExpertForms = ((byte)'e') | ((byte)'x' << 8) | ((byte)'p' << 16) | ((byte)'t' << 24), - Fractions = ((byte)'f') | ((byte)'r' << 8) | ((byte)'a' << 16) | ((byte)'c' << 24), - FullWidth = ((byte)'f') | ((byte)'w' << 8) | ((byte)'i' << 16) | ((byte)'d' << 24), - HalfForms = ((byte)'h') | ((byte)'a' << 8) | ((byte)'l' << 16) | ((byte)'f' << 24), - HalantForms = ((byte)'h') | ((byte)'a' << 8) | ((byte)'l' << 16) | ((byte)'n' << 24), - AlternateHalfWidth = ((byte)'h') | ((byte)'a' << 8) | ((byte)'l' << 16) | ((byte)'t' << 24), - HistoricalForms = ((byte)'h') | ((byte)'i' << 8) | ((byte)'s' << 16) | ((byte)'t' << 24), - HorizontalKanaAlternates = ((byte)'h') | ((byte)'k' << 8) | ((byte)'n' << 16) | ((byte)'a' << 24), - HistoricalLigatures = ((byte)'h') | ((byte)'l' << 8) | ((byte)'i' << 16) | ((byte)'g' << 24), - HalfWidth = ((byte)'h') | ((byte)'w' << 8) | ((byte)'i' << 16) | ((byte)'d' << 24), - HojoKanjiForms = ((byte)'h') | ((byte)'o' << 8) | ((byte)'j' << 16) | ((byte)'o' << 24), - Jis04Forms = ((byte)'j') | ((byte)'p' << 8) | ((byte)'0' << 16) | ((byte)'4' << 24), - Jis78Forms = ((byte)'j') | ((byte)'p' << 8) | ((byte)'7' << 16) | ((byte)'8' << 24), - Jis83Forms = ((byte)'j') | ((byte)'p' << 8) | ((byte)'8' << 16) | ((byte)'3' << 24), - Jis90Forms = ((byte)'j') | ((byte)'p' << 8) | ((byte)'9' << 16) | ((byte)'0' << 24), - Kerning = ((byte)'k') | ((byte)'e' << 8) | ((byte)'r' << 16) | ((byte)'n' << 24), - StandardLigatures = ((byte)'l') | ((byte)'i' << 8) | ((byte)'g' << 16) | ((byte)'a' << 24), - LiningFigures = ((byte)'l') | ((byte)'n' << 8) | ((byte)'u' << 16) | ((byte)'m' << 24), - LocalizedForms = ((byte)'l') | ((byte)'o' << 8) | ((byte)'c' << 16) | ((byte)'l' << 24), - MarkPositioning = ((byte)'m') | ((byte)'a' << 8) | ((byte)'r' << 16) | ((byte)'k' << 24), - MathematicalGreek = ((byte)'m') | ((byte)'g' << 8) | ((byte)'r' << 16) | ((byte)'k' << 24), - MarkToMarkPositioning = ((byte)'m') | ((byte)'k' << 8) | ((byte)'m' << 16) | ((byte)'k' << 24), - AlternateAnnotationForms = ((byte)'n') | ((byte)'a' << 8) | ((byte)'l' << 16) | ((byte)'t' << 24), - NlcKanjiForms = ((byte)'n') | ((byte)'l' << 8) | ((byte)'c' << 16) | ((byte)'k' << 24), - OldStyleFigures = ((byte)'o') | ((byte)'n' << 8) | ((byte)'u' << 16) | ((byte)'m' << 24), - Ordinals = ((byte)'o') | ((byte)'r' << 8) | ((byte)'d' << 16) | ((byte)'n' << 24), - ProportionalAlternateWidth = ((byte)'p') | ((byte)'a' << 8) | ((byte)'l' << 16) | ((byte)'t' << 24), - PetiteCapitals = ((byte)'p') | ((byte)'c' << 8) | ((byte)'a' << 16) | ((byte)'p' << 24), - ProportionalFigures = ((byte)'p') | ((byte)'n' << 8) | ((byte)'u' << 16) | ((byte)'m' << 24), - ProportionalWidths = ((byte)'p') | ((byte)'w' << 8) | ((byte)'i' << 16) | ((byte)'d' << 24), - QuarterWidths = ((byte)'q') | ((byte)'w' << 8) | ((byte)'i' << 16) | ((byte)'d' << 24), - RequiredLigatures = ((byte)'r') | ((byte)'l' << 8) | ((byte)'i' << 16) | ((byte)'g' << 24), - RubyNotationForms = ((byte)'r') | ((byte)'u' << 8) | ((byte)'b' << 16) | ((byte)'y' << 24), - StylisticAlternates = ((byte)'s') | ((byte)'a' << 8) | ((byte)'l' << 16) | ((byte)'t' << 24), - ScientificInferiors = ((byte)'s') | ((byte)'i' << 8) | ((byte)'n' << 16) | ((byte)'f' << 24), - SmallCapitals = ((byte)'s') | ((byte)'m' << 8) | ((byte)'c' << 16) | ((byte)'p' << 24), - SimplifiedForms = ((byte)'s') | ((byte)'m' << 8) | ((byte)'p' << 16) | ((byte)'l' << 24), - StylisticSet1 = ((byte)'s') | ((byte)'s' << 8) | ((byte)'0' << 16) | ((byte)'1' << 24), - StylisticSet2 = ((byte)'s') | ((byte)'s' << 8) | ((byte)'0' << 16) | ((byte)'2' << 24), - StylisticSet3 = ((byte)'s') | ((byte)'s' << 8) | ((byte)'0' << 16) | ((byte)'3' << 24), - StylisticSet4 = ((byte)'s') | ((byte)'s' << 8) | ((byte)'0' << 16) | ((byte)'4' << 24), - StylisticSet5 = ((byte)'s') | ((byte)'s' << 8) | ((byte)'0' << 16) | ((byte)'5' << 24), - StylisticSet6 = ((byte)'s') | ((byte)'s' << 8) | ((byte)'0' << 16) | ((byte)'6' << 24), - StylisticSet7 = ((byte)'s') | ((byte)'s' << 8) | ((byte)'0' << 16) | ((byte)'7' << 24), - StylisticSet8 = ((byte)'s') | ((byte)'s' << 8) | ((byte)'0' << 16) | ((byte)'8' << 24), - StylisticSet9 = ((byte)'s') | ((byte)'s' << 8) | ((byte)'0' << 16) | ((byte)'9' << 24), - StylisticSet10 = ((byte)'s') | ((byte)'s' << 8) | ((byte)'1' << 16) | ((byte)'0' << 24), - StylisticSet11 = ((byte)'s') | ((byte)'s' << 8) | ((byte)'1' << 16) | ((byte)'1' << 24), - StylisticSet12 = ((byte)'s') | ((byte)'s' << 8) | ((byte)'1' << 16) | ((byte)'2' << 24), - StylisticSet13 = ((byte)'s') | ((byte)'s' << 8) | ((byte)'1' << 16) | ((byte)'3' << 24), - StylisticSet14 = ((byte)'s') | ((byte)'s' << 8) | ((byte)'1' << 16) | ((byte)'4' << 24), - StylisticSet15 = ((byte)'s') | ((byte)'s' << 8) | ((byte)'1' << 16) | ((byte)'5' << 24), - StylisticSet16 = ((byte)'s') | ((byte)'s' << 8) | ((byte)'1' << 16) | ((byte)'6' << 24), - StylisticSet17 = ((byte)'s') | ((byte)'s' << 8) | ((byte)'1' << 16) | ((byte)'7' << 24), - StylisticSet18 = ((byte)'s') | ((byte)'s' << 8) | ((byte)'1' << 16) | ((byte)'8' << 24), - StylisticSet19 = ((byte)'s') | ((byte)'s' << 8) | ((byte)'1' << 16) | ((byte)'9' << 24), - StylisticSet20 = ((byte)'s') | ((byte)'s' << 8) | ((byte)'2' << 16) | ((byte)'0' << 24), - Subscript = ((byte)'s') | ((byte)'u' << 8) | ((byte)'b' << 16) | ((byte)'s' << 24), - Superscript = ((byte)'s') | ((byte)'u' << 8) | ((byte)'p' << 16) | ((byte)'s' << 24), - Swash = ((byte)'s') | ((byte)'w' << 8) | ((byte)'s' << 16) | ((byte)'h' << 24), - Titling = ((byte)'t') | ((byte)'i' << 8) | ((byte)'t' << 16) | ((byte)'l' << 24), - TraditionalNameForms = ((byte)'t') | ((byte)'n' << 8) | ((byte)'a' << 16) | ((byte)'m' << 24), - TabularFigures = ((byte)'t') | ((byte)'n' << 8) | ((byte)'u' << 16) | ((byte)'m' << 24), - TraditionalForms = ((byte)'t') | ((byte)'r' << 8) | ((byte)'a' << 16) | ((byte)'d' << 24), - ThirdWidths = ((byte)'t') | ((byte)'w' << 8) | ((byte)'i' << 16) | ((byte)'d' << 24), - Unicase = ((byte)'u') | ((byte)'n' << 8) | ((byte)'i' << 16) | ((byte)'c' << 24), - VerticalWriting = ((byte)'v') | ((byte)'e' << 8) | ((byte)'r' << 16) | ((byte)'t' << 24), - VerticalAlternatesAndRotation = ((byte)'v') | ((byte)'r' << 8) | ((byte)'t' << 16) | ((byte)'2' << 24), - SlashedZero = ((byte)'z') | ((byte)'e' << 8) | ((byte)'r' << 16) | ((byte)'o' << 24), + AlternativeFractions = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_ALTERNATIVE_FRACTIONS, + PetiteCapitalsFromCapitals = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_PETITE_CAPITALS_FROM_CAPITALS, + SmallCapitalsFromCapitals = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_SMALL_CAPITALS_FROM_CAPITALS, + ContextualAlternates = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_CONTEXTUAL_ALTERNATES, + CaseSensitiveForms = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_CASE_SENSITIVE_FORMS, + GlyphCompositionDecomposition = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_GLYPH_COMPOSITION_DECOMPOSITION, + ContextualLigatures = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_CONTEXTUAL_LIGATURES, + CapitalSpacing = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_CAPITAL_SPACING, + ContextualSwash = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_CONTEXTUAL_SWASH, + CursivePositioning = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_CURSIVE_POSITIONING, + Default = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_DEFAULT, + DiscretionaryLigatures = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_DISCRETIONARY_LIGATURES, + ExpertForms = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_EXPERT_FORMS, + Fractions = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_FRACTIONS, + FullWidth = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_FULL_WIDTH, + HalfForms = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_HALF_FORMS, + HalantForms = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_HALANT_FORMS, + AlternateHalfWidth = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_ALTERNATE_HALF_WIDTH, + HistoricalForms = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_HISTORICAL_FORMS, + HorizontalKanaAlternates = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_HORIZONTAL_KANA_ALTERNATES, + HistoricalLigatures = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_HISTORICAL_LIGATURES, + HalfWidth = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_HALF_WIDTH, + HojoKanjiForms = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_HOJO_KANJI_FORMS, + Jis04Forms = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_JIS04_FORMS, + Jis78Forms = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_JIS78_FORMS, + Jis83Forms = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_JIS83_FORMS, + Jis90Forms = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_JIS90_FORMS, + Kerning = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_KERNING, + StandardLigatures = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_STANDARD_LIGATURES, + LiningFigures = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_LINING_FIGURES, + LocalizedForms = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_LOCALIZED_FORMS, + MarkPositioning = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_MARK_POSITIONING, + MathematicalGreek = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_MATHEMATICAL_GREEK, + MarkToMarkPositioning = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_MARK_TO_MARK_POSITIONING, + AlternateAnnotationForms = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_ALTERNATE_ANNOTATION_FORMS, + NlcKanjiForms = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_NLC_KANJI_FORMS, + OldStyleFigures = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_OLD_STYLE_FIGURES, + Ordinals = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_ORDINALS, + ProportionalAlternateWidth = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_PROPORTIONAL_ALTERNATE_WIDTH, + PetiteCapitals = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_PETITE_CAPITALS, + ProportionalFigures = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_PROPORTIONAL_FIGURES, + ProportionalWidths = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_PROPORTIONAL_WIDTHS, + QuarterWidths = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_QUARTER_WIDTHS, + RequiredLigatures = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_REQUIRED_LIGATURES, + RubyNotationForms = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_RUBY_NOTATION_FORMS, + StylisticAlternates = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_STYLISTIC_ALTERNATES, + ScientificInferiors = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_SCIENTIFIC_INFERIORS, + SmallCapitals = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_SMALL_CAPITALS, + SimplifiedForms = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_SIMPLIFIED_FORMS, + StylisticSet1 = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_1, + StylisticSet2 = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_2, + StylisticSet3 = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_3, + StylisticSet4 = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_4, + StylisticSet5 = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_5, + StylisticSet6 = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_6, + StylisticSet7 = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_7, + StylisticSet8 = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_8, + StylisticSet9 = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_9, + StylisticSet10 = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_10, + StylisticSet11 = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_11, + StylisticSet12 = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_12, + StylisticSet13 = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_13, + StylisticSet14 = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_14, + StylisticSet15 = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_15, + StylisticSet16 = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_16, + StylisticSet17 = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_17, + StylisticSet18 = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_18, + StylisticSet19 = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_19, + StylisticSet20 = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_20, + Subscript = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_SUBSCRIPT, + Superscript = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_SUPERSCRIPT, + Swash = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_SWASH, + Titling = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_TITLING, + TraditionalNameForms = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_TRADITIONAL_NAME_FORMS, + TabularFigures = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_TABULAR_FIGURES, + TraditionalForms = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_TRADITIONAL_FORMS, + ThirdWidths = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_THIRD_WIDTHS, + Unicase = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_UNICASE, + VerticalWriting = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_VERTICAL_WRITING, + VerticalAlternatesAndRotation = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_VERTICAL_ALTERNATES_AND_ROTATION, + SlashedZero = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_SLASHED_ZERO, } } diff --git a/src/WInterop.DirectX/DirectWrite/FontList.cs b/src/WInterop.DirectX/DirectWrite/FontList.cs new file mode 100644 index 00000000..5cdb6f16 --- /dev/null +++ b/src/WInterop.DirectX/DirectWrite/FontList.cs @@ -0,0 +1,63 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using WInterop.Direct2d; + +namespace WInterop.DirectWrite +{ + /// + /// The interface represents an ordered set of fonts that are part of an . + /// [IDWriteFontList] + /// + [Guid(InterfaceIds.IID_IDWriteFontList)] + public readonly unsafe struct FontList : FontList.Interface, IDisposable + { + private readonly IDWriteFontList* _handle; + + internal FontList(IDWriteFontList* handle) => _handle = handle; + + public uint FontCount => _handle->GetFontCount(); + + internal static ref FontList From(in TFrom from) + where TFrom : unmanaged, Interface + => ref Unsafe.AsRef(Unsafe.AsPointer(ref Unsafe.AsRef(from))); + + public void Dispose() => _handle->Release(); + + public Font GetFont(uint index) + { + IDWriteFont* font; + _handle->GetFont(index, &font).ThrowIfFailed(); + return new(font); + } + + public FontCollection GetFontCollection() + { + IDWriteFontCollection* collection; + _handle->GetFontCollection(&collection).ThrowIfFailed(); + return new(collection); + } + + internal interface Interface + { + /// + /// Gets the font collection that contains the fonts. + /// + FontCollection GetFontCollection(); + + /// + /// Gets the number of fonts in the font list. + /// + uint FontCount { get; } + + /// + /// Gets a font given its zero-based index. + /// + /// Zero-based index of the font in the font list. + Font GetFont(uint index); + } + } +} diff --git a/src/WInterop.DirectX/DirectWrite/FontSimulations.cs b/src/WInterop.DirectX/DirectWrite/FontSimulations.cs index 76490e50..797db7ab 100644 --- a/src/WInterop.DirectX/DirectWrite/FontSimulations.cs +++ b/src/WInterop.DirectX/DirectWrite/FontSimulations.cs @@ -16,16 +16,16 @@ public enum FontSimulations : uint /// /// No simulations are performed. /// - None = 0x0000, + None = DWRITE_FONT_SIMULATIONS.DWRITE_FONT_SIMULATIONS_NONE, /// /// Algorithmic emboldening is performed. /// - Bold = 0x0001, + Bold = DWRITE_FONT_SIMULATIONS.DWRITE_FONT_SIMULATIONS_BOLD, /// /// Algorithmic italicization is performed. /// - Oblique = 0x0002 + Oblique = DWRITE_FONT_SIMULATIONS.DWRITE_FONT_SIMULATIONS_OBLIQUE } } diff --git a/src/WInterop.DirectX/DirectWrite/GlyphRun.cs b/src/WInterop.DirectX/DirectWrite/GlyphRun.cs index b0e24f15..5d423642 100644 --- a/src/WInterop.DirectX/DirectWrite/GlyphRun.cs +++ b/src/WInterop.DirectX/DirectWrite/GlyphRun.cs @@ -17,9 +17,7 @@ public readonly unsafe struct GlyphRun /// /// The physical font face to draw with. (IFontFace) /// - private readonly IntPtr _fontFace; - - public IFontFace FontFace => (IFontFace)Marshal.GetObjectForIUnknown(_fontFace); + public readonly FontFace FontFace; /// /// Logical size of the font in DIPs, not points (equals 1/96 inch). @@ -31,20 +29,26 @@ public readonly unsafe struct GlyphRun /// public readonly uint GlyphCount; + private readonly ushort* _glyphIndices; + /// /// The indices to render. /// - public readonly ushort* GlyphIndices; + public ReadOnlySpan GlyphIndices => new(_glyphIndices, (int)GlyphCount); + + private readonly float* _glyphAdvances; /// /// Glyph advance widths. /// - public readonly float* GlyphAdvances; + public ReadOnlySpan GlyphAdvances => new(_glyphAdvances, (int)GlyphCount); + + private readonly GlyphOffset* _glyphOffsets; /// /// Glyph offsets. /// - public readonly GlyphOffset* GlyphOffsets; + public ReadOnlySpan GlyphOffsets => new(_glyphOffsets, (int)GlyphCount); /// /// If true, specifies that glyphs are rotated 90 degrees to the left and diff --git a/src/WInterop.DirectX/DirectWrite/HitTestMetrics.cs b/src/WInterop.DirectX/DirectWrite/HitTestMetrics.cs index c596963c..58ec1c01 100644 --- a/src/WInterop.DirectX/DirectWrite/HitTestMetrics.cs +++ b/src/WInterop.DirectX/DirectWrite/HitTestMetrics.cs @@ -43,14 +43,18 @@ public readonly struct HitTestMetrics /// public readonly uint BidiLevel; + private readonly TerraFX.Interop.Windows.BOOL _isText; + /// /// Geometry encloses text? /// - public readonly IntBoolean IsText; + public bool IsText => _isText; + + private readonly TerraFX.Interop.Windows.BOOL _isTrimmed; /// /// Range is trimmed. /// - public readonly IntBoolean IsTrimmed; + public bool IsTrimmed => _isTrimmed; } } diff --git a/src/WInterop.DirectX/DirectWrite/IFactory.cs b/src/WInterop.DirectX/DirectWrite/IFactory.cs deleted file mode 100644 index 3e8be9c6..00000000 --- a/src/WInterop.DirectX/DirectWrite/IFactory.cs +++ /dev/null @@ -1,386 +0,0 @@ -// Copyright (c) Jeremy W. Kuhne. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Drawing; -using System.Globalization; -using System.Numerics; -using System.Runtime.InteropServices; -using WInterop.Windows.Native; - -namespace WInterop.DirectWrite -{ - /// - /// The root factory interface for all DWrite objects. [IDWriteFactory] - /// - [ComImport, - Guid(InterfaceIds.IID_IDWriteFactory), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IFactory - { - /// - /// Gets a font collection representing the set of installed fonts. - /// - /// Receives a pointer to the system font collection object, or NULL in case of failure. - /// If this parameter is nonzero, the function performs an immediate check for changes to the set of - /// installed fonts. If this parameter is FALSE, the function will still detect changes if the font cache service is running, but - /// there may be some latency. For example, an application might specify TRUE if it has itself just installed a font and wants to - /// be sure the font collection contains that font. - void GetSystemFontCollection( - out IFontCollection fontCollection, - IntBoolean checkForUpdates); - - /// - /// Creates a font collection using a custom font collection loader. - /// - /// Application-defined font collection loader, which must have been previously - /// registered using RegisterFontCollectionLoader. - /// Key used by the loader to identify a collection of font files. - /// Size in bytes of the collection key. - /// Receives a pointer to the system font collection object, or NULL in case of failure. - void CreateCustomFontCollectionSTUB(); - //STDMETHOD(CreateCustomFontCollection)( - // _In_ IDWriteFontCollectionLoader* collectionLoader, - // _In_reads_bytes_(collectionKeySize) void const* collectionKey, - // UINT32 collectionKeySize, - // _COM_Outptr_ IDWriteFontCollection** fontCollection - // ) PURE; - - /// - /// Registers a custom font collection loader with the factory object. - /// - /// Application-defined font collection loader. - void RegisterFontCollectionLoaderSTUB(); - //STDMETHOD(RegisterFontCollectionLoader)( - // _In_ IDWriteFontCollectionLoader* fontCollectionLoader - // ) PURE; - - /// - /// Unregisters a custom font collection loader that was previously registered using RegisterFontCollectionLoader. - /// - /// Application-defined font collection loader. - /// - /// Standard HRESULT error code. - /// - void UnregisterFontCollectionLoaderSTUB(); - //STDMETHOD(UnregisterFontCollectionLoader)( - // _In_ IDWriteFontCollectionLoader* fontCollectionLoader - // ) PURE; - - /// - /// CreateFontFileReference creates a font file reference object from a local font file. - /// - /// Absolute file path. Subsequent operations on the constructed object may fail - /// if the user provided filePath doesn't correspond to a valid file on the disk. - /// Last modified time of the input file path. If the parameter is omitted, - /// the function will access the font file to obtain its last write time, so the clients are encouraged to specify this value - /// to avoid extra disk access. Subsequent operations on the constructed object may fail - /// if the user provided lastWriteTime doesn't match the file on the disk. - /// Contains newly created font file reference object, or NULL in case of failure. - void CreateFontFileReferenceSTUB(); - //STDMETHOD(CreateFontFileReference)( - // _In_z_ WCHAR const* filePath, - // _In_opt_ FILETIME const* lastWriteTime, - // _COM_Outptr_ IDWriteFontFile** fontFile - // ) PURE; - - /// - /// CreateCustomFontFileReference creates a reference to an application specific font file resource. - /// This function enables an application or a document to use a font without having to install it on the system. - /// The fontFileReferenceKey has to be unique only in the scope of the fontFileLoader used in this call. - /// - /// Font file reference key that uniquely identifies the font file resource - /// during the lifetime of fontFileLoader. - /// Size of font file reference key in bytes. - /// Font file loader that will be used by the font system to load data from the file identified by - /// fontFileReferenceKey. - /// Contains the newly created font file object, or NULL in case of failure. - /// - /// Standard HRESULT error code. - /// - /// - /// This function is provided for cases when an application or a document needs to use a font - /// without having to install it on the system. fontFileReferenceKey has to be unique only in the scope - /// of the fontFileLoader used in this call. - /// - void CreateCustomFontFileReferenceSTUB(); - //STDMETHOD(CreateCustomFontFileReference)( - // _In_reads_bytes_(fontFileReferenceKeySize) void const* fontFileReferenceKey, - // UINT32 fontFileReferenceKeySize, - // _In_ IDWriteFontFileLoader* fontFileLoader, - // _COM_Outptr_ IDWriteFontFile** fontFile - // ) PURE; - - /// - /// Creates a font face object. - /// - /// The file format of the font face. - /// The number of font files required to represent the font face. - /// Font files representing the font face. Since IDWriteFontFace maintains its own references - /// to the input font file objects, it's OK to release them after this call. - /// The zero based index of a font face in cases when the font files contain a collection of font faces. - /// If the font files contain a single face, this value should be zero. - /// Font face simulation flags for algorithmic emboldening and italicization. - /// Contains the newly created font face object, or NULL in case of failure. - void CreateFontFaceSTUB(); - //IFontFace CreateFontFace( - // FontFaceType fontFaceType, - // uint numberOfFiles, - // _In_reads_(numberOfFiles) IDWriteFontFile* const* fontFiles, - // uint faceIndex, - // DWRITE_FONT_SIMULATIONS fontFaceSimulationFlags); - - /// - /// Creates a rendering parameters object with default settings for the primary monitor. - /// - IRenderingParams CreateRenderingParams(); - - /// - /// Creates a rendering parameters object with default settings for the specified monitor. - /// - /// The monitor to read the default values from. - IRenderingParams CreateMonitorRenderingParams(HMONITOR monitor); - - /// - /// Creates a rendering parameters object with the specified properties. - /// - /// The gamma value used for gamma correction, which must be greater than zero and cannot exceed 256. - /// The amount of contrast enhancement, zero or greater. - /// The degree of ClearType level, from 0.0f (no ClearType) to 1.0f (full ClearType). - /// The geometry of a device pixel. - /// Method of rendering glyphs. In most cases, this should be DWRITE_RENDERING_MODE_DEFAULT to automatically use an appropriate mode. - IRenderingParams CreateCustomRenderingParams( - float gamma, - float enhancedContrast, - float clearTypeLevel, - PixelGeometry pixelGeometry, - RenderingMode renderingMode); - - /// - /// Registers a font file loader with DirectWrite. - /// - /// Pointer to the implementation of the IDWriteFontFileLoader for a particular file resource type. - /// - /// This function registers a font file loader with DirectWrite. - /// Font file loader interface handles loading font file resources of a particular type from a key. - /// The font file loader interface is recommended to be implemented by a singleton object. - /// A given instance can only be registered once. - /// Succeeding attempts will return an error that it has already been registered. - /// IMPORTANT: font file loader implementations must not register themselves with DirectWrite - /// inside their constructors and must not unregister themselves in their destructors, because - /// registration and unregistration operations increment and decrement the object reference count respectively. - /// Instead, registration and unregistration of font file loaders with DirectWrite should be performed - /// outside of the font file loader implementation as a separate step. - /// - void RegisterFontFileLoaderSTUB(); - //STDMETHOD(RegisterFontFileLoader)( - // _In_ IDWriteFontFileLoader* fontFileLoader - // ) PURE; - - /// - /// Unregisters a font file loader that was previously registered with the DirectWrite font system using RegisterFontFileLoader. - /// - /// Pointer to the file loader that was previously registered with the DirectWrite font system using RegisterFontFileLoader. - /// - /// This function will succeed if the user loader is requested to be removed. - /// It will fail if the pointer to the file loader identifies a standard DirectWrite loader, - /// or a loader that is never registered or has already been unregistered. - /// - /// - /// This function unregisters font file loader callbacks with the DirectWrite font system. - /// The font file loader interface is recommended to be implemented by a singleton object. - /// IMPORTANT: font file loader implementations must not register themselves with DirectWrite - /// inside their constructors and must not unregister themselves in their destructors, because - /// registration and unregistration operations increment and decrement the object reference count respectively. - /// Instead, registration and unregistration of font file loaders with DirectWrite should be performed - /// outside of the font file loader implementation as a separate step. - /// - void UnregisterFontFileLoaderSTUB(); - //STDMETHOD(UnregisterFontFileLoader)( - // _In_ IDWriteFontFileLoader* fontFileLoader - // ) PURE; - - /// - /// Create a text format object used for text layout. - /// - /// Name of the font family - /// Font collection. 'null' indicates the system font collection. - /// Logical size of the font in DIP units. A DIP ("device-independent pixel") equals 1/96 inch. - /// Locale name - ITextFormat CreateTextFormat( - [MarshalAs(UnmanagedType.LPWStr)] - string fontFamilyName, - IFontCollection fontCollection, - FontWeight fontWeight, - FontStyle fontStyle, - FontStretch fontStretch, - float fontSize, - [MarshalAs(UnmanagedType.LPWStr)] - string localeName); - - /// - /// Create a typography object used in conjunction with text format for text layout. - /// - ITypography CreateTypography(); - - /// - /// Create an object used for interoperability with GDI. - /// - /// Receives the GDI interop object if successful, or NULL in case of failure. - /// - /// Standard HRESULT error code. - /// - void GetGdiInteropSTUB(); - //STDMETHOD(GetGdiInterop)( - // _COM_Outptr_ IDWriteGdiInterop** gdiInterop - // ) PURE; - - /// - /// CreateTextLayout takes a string, format, and associated constraints - /// and produces an object representing the fully analyzed - /// and formatted result. - /// - /// The string to layout. - /// The length of the string. - /// The format to apply to the string. - /// Width of the layout box. - /// Height of the layout box. - /// The resultant object. - unsafe ITextLayout CreateTextLayout( - char* @string, - uint stringLength, - ITextFormat textFormat, - float maxWidth, - float maxHeight); - - /// - /// CreateGdiCompatibleTextLayout takes a string, format, and associated constraints - /// and produces and object representing the result formatted for a particular display resolution - /// and measuring mode. The resulting text layout should only be used for the intended resolution, - /// and for cases where text scalability is desired, CreateTextLayout should be used instead. - /// - /// The string to layout. - /// The length of the string. - /// The format to apply to the string. - /// Width of the layout box. - /// Height of the layout box. - /// Number of physical pixels per DIP. For example, if rendering onto a 96 DPI device then pixelsPerDip - /// is 1. If rendering onto a 120 DPI device then pixelsPerDip is 120/96. - /// Optional transform applied to the glyphs and their positions. This transform is applied after the - /// scaling specified the font size and pixelsPerDip. - /// - /// When set to FALSE, instructs the text layout to use the same metrics as GDI aliased text. - /// When set to TRUE, instructs the text layout to use the same metrics as text measured by GDI using a font - /// created with CLEARTYPE_NATURAL_QUALITY. - /// - /// The resultant object. - /// - /// Standard HRESULT error code. - /// - unsafe ITextLayout CreateGdiCompatibleTextLayout( - [MarshalAs(UnmanagedType.LPWStr)] - string @string, - uint stringLength, - ITextFormat textFormat, - float layoutWidth, - float layoutHeight, - float pixelsPerDip, - Matrix3x2* transform, - IntBoolean useGdiNatural); - - /// - /// The application may call this function to create an inline object for trimming, using an ellipsis as the - /// omission sign. The ellipsis will be created using the current settings of the format, including base font, - /// style, and any effects. Alternate omission signs can be created by the application by implementing - /// IDWriteInlineObject. - /// - /// Text format used as a template for the omission sign. - /// Created omission sign. - IInlineObject CreateEllipsisTrimmingSign(ITextFormat textFormat); - - ///// The resultant object. - /// - /// Return an interface to perform text analysis with. - /// - void CreateTextAnalyzerSTUB(); - //STDMETHOD(CreateTextAnalyzer)( - // _COM_Outptr_ IDWriteTextAnalyzer** textAnalyzer - // ) PURE; - - - ///// Method of number substitution to use. - ///// Which locale to obtain the digits from. - ///// Ignore the user's settings and use the locale defaults - ///// Receives a pointer to the newly created object. - /// - /// Creates a number substitution object using a locale name, - /// substitution method, and whether to ignore user overrides (uses NLS - /// defaults for the given culture instead). - /// - void CreateNumberSubstitutionSTUB(); - //STDMETHOD(CreateNumberSubstitution)( - // _In_ DWRITE_NUMBER_SUBSTITUTION_METHOD substitutionMethod, - // _In_z_ WCHAR const* localeName, - // _In_ BOOL ignoreUserOverride, - // _COM_Outptr_ IDWriteNumberSubstitution** numberSubstitution - // ) PURE; - - /// - /// Creates a glyph run analysis object, which encapsulates information - /// used to render a glyph run. - /// - /// Structure specifying the properties of the glyph run. - /// Number of physical pixels per DIP. For example, if rendering onto a 96 DPI bitmap then pixelsPerDip - /// is 1. If rendering onto a 120 DPI bitmap then pixelsPerDip is 120/96. - /// Optional transform applied to the glyphs and their positions. This transform is applied after the - /// scaling specified by the emSize and pixelsPerDip. - /// Specifies the rendering mode, which must be one of the raster rendering modes (i.e., not default - /// and not outline). - /// Specifies the method to measure glyphs. - /// Horizontal position of the baseline origin, in DIPs. - /// Vertical position of the baseline origin, in DIPs. - /// Receives a pointer to the newly created object. - void CreateGlyphRunAnalysisSTUB(); - //STDMETHOD(CreateGlyphRunAnalysis)( - // _In_ DWRITE_GLYPH_RUN const* glyphRun, - // FLOAT pixelsPerDip, - // _In_opt_ DWRITE_MATRIX const* transform, - // DWRITE_RENDERING_MODE renderingMode, - // DWRITE_MEASURING_MODE measuringMode, - // FLOAT baselineOriginX, - // FLOAT baselineOriginY, - // _COM_Outptr_ IDWriteGlyphRunAnalysis** glyphRunAnalysis - // ) PURE; - - } - - public static class FactoryExtensions - { - public unsafe static ITextLayout CreateTextLayout(this IFactory factory, ReadOnlySpan text, ITextFormat textFormat, SizeF maxSize) - { - fixed (char* c = &MemoryMarshal.GetReference(text)) - { - return factory.CreateTextLayout(c, (uint)text.Length, textFormat, maxSize.Width, maxSize.Height); - } - } - - public unsafe static ITextFormat CreateTextFormat( - this IFactory factory, - string fontFamilyName, - FontWeight fontWeight = FontWeight.Normal, - FontStyle fontStyle = FontStyle.Normal, - FontStretch fontStretch = FontStretch.Normal, - float fontSize = 12.0f, - string localeName = null) - { - return factory.CreateTextFormat( - fontFamilyName, - fontCollection: null, - fontWeight, - fontStyle, - fontStretch, - fontSize, - localeName ?? CultureInfo.CurrentCulture.Name); - } - } -} diff --git a/src/WInterop.DirectX/DirectWrite/IFont.cs b/src/WInterop.DirectX/DirectWrite/IFont.cs deleted file mode 100644 index e934cc1c..00000000 --- a/src/WInterop.DirectX/DirectWrite/IFont.cs +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright (c) Jeremy W. Kuhne. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Runtime.InteropServices; - -namespace WInterop.DirectWrite -{ - /// - /// The interface represents a physical font in a font collection. - /// [IDWriteFont] - /// - [ComImport, - Guid(InterfaceIds.IID_IDWriteFont), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IFont - { - /// - /// Gets the font family to which the specified font belongs. - /// - IFontFamily GetFontFamily(); - - /// - /// Gets the weight of the specified font. - /// - [PreserveSig] - FontWeight GetWeight(); - - /// - /// Gets the stretch (aka. width) of the specified font. - /// - [PreserveSig] - FontStretch GetStretch(); - - /// - /// Gets the style (aka. slope) of the specified font. - /// - [PreserveSig] - FontStyle GetStyle(); - - /// - /// Returns TRUE if the font is a symbol font or FALSE if not. - /// - [PreserveSig] - IntBoolean IsSymbolFont(); - - /// - /// Gets a localized strings collection containing the face names for the font (e.g., Regular or Bold), indexed by locale name. - /// - /// - /// A pointer to the newly created localized strings object. - /// - ILocalizedStrings GetFaceNames(); - - /// - /// Gets a localized strings collection containing the specified informational strings, indexed by locale name. - /// - /// Identifies the string to get. - /// Receives a pointer to the newly created localized strings object. - /// Receives the value TRUE if the font contains the specified string ID or FALSE if not. - /// - /// Standard HRESULT error code. If the font does not contain the specified string, the return value is S_OK but - /// informationalStrings receives a NULL pointer and exists receives the value FALSE. - /// - IntBoolean GetInformationalStrings( - InformationalStringId informationalStringID, - out ILocalizedStrings informationalStrings); - - /// - /// Gets a value that indicates what simulation are applied to the specified font. - /// - [PreserveSig] - FontSimulations GetSimulations(); - - /// - /// Gets the metrics for the font. - /// - /// Receives the font metrics. - [PreserveSig] - void GetMetrics(out FontMetrics fontMetrics); - - /// - /// Determines whether the font supports the specified character. - /// - /// Unicode (UCS-4) character value. - /// Receives the value TRUE if the font supports the specified character or FALSE if not. - IntBoolean HasCharacter(uint unicodeValue); - - /// - /// Creates a font face object for the font. - /// - /// - /// S pointer to the newly created font face object. - /// - IFontFace CreateFontFace(); - } -} diff --git a/src/WInterop.DirectX/DirectWrite/IFontCollection.cs b/src/WInterop.DirectX/DirectWrite/IFontCollection.cs deleted file mode 100644 index 39f93bc2..00000000 --- a/src/WInterop.DirectX/DirectWrite/IFontCollection.cs +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) Jeremy W. Kuhne. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Runtime.InteropServices; - -namespace WInterop.DirectWrite -{ - /// - /// The IDWriteFontCollection encapsulates a collection of font families. [IDWriteFontCollection] - /// - [ComImport, - Guid(InterfaceIds.IID_IDWriteFontCollection), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IFontCollection - { - /// - /// Gets the number of font families in the collection. - /// - [PreserveSig] - uint GetFontFamilyCount(); - - /// - /// Creates a font family object given a zero-based font family index. - /// - /// Zero-based index of the font family. - IFontFamily GetFontFamily(uint index); - - /// - /// Finds the font family with the specified family name. - /// - /// Name of the font family. The name is not case-sensitive but must otherwise exactly match a family name in the collection. - /// Receives the zero-based index of the matching font family if the family name was found or UINT_MAX otherwise. - IntBoolean FindFamilyName( - [MarshalAs(UnmanagedType.LPWStr)] - string familyName, - out uint index); - - /// - /// Gets the font object that corresponds to the same physical font as the specified font face object. The specified physical font must belong - /// to the font collection. - /// - /// Font face object that specifies the physical font. - IFont GetFontFromFontFace(IFontFace fontFace); - } -} diff --git a/src/WInterop.DirectX/DirectWrite/IFontFace.cs b/src/WInterop.DirectX/DirectWrite/IFontFace.cs deleted file mode 100644 index 0a38ebba..00000000 --- a/src/WInterop.DirectX/DirectWrite/IFontFace.cs +++ /dev/null @@ -1,260 +0,0 @@ -// Copyright (c) Jeremy W. Kuhne. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Numerics; -using System.Runtime.InteropServices; -using WInterop.Direct2d; - -namespace WInterop.DirectWrite -{ - /// - /// This interface exposes various font data such as metrics, names, and glyph outlines. - /// It contains font face type, appropriate file references and face identification data. - /// [IDWriteFontFace] - /// - [ComImport, - Guid(InterfaceIds.IID_IDWriteFontFace), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IFontFace - { - /// - /// Obtains the file format type of a font face. - /// - [PreserveSig] - FontFaceType GetType(); - - /// - /// Obtains the font files representing a font face. - /// - /// The number of files representing the font face. - /// User provided array that stores pointers to font files representing the font face. - /// This parameter can be NULL if the user is only interested in the number of files representing the font face. - /// This API increments reference count of the font file pointers returned according to COM conventions, and the client - /// should release them when finished. - /// - /// Standard HRESULT error code. - /// - void GetFilesSTUB(); - //STDMETHOD(GetFiles)( - // _Inout_ UINT32* numberOfFiles, - // _Out_writes_opt_(*numberOfFiles) IDWriteFontFile** fontFiles - //) PURE; - - /// - /// Obtains the zero-based index of the font face in its font file or files. If the font files contain a single face, - /// the return value is zero. - /// - [PreserveSig] - uint GetIndex(); - - /// - /// Obtains the algorithmic style simulation flags of a font face. - /// - [PreserveSig] - FontSimulations GetSimulations(); - - /// - /// Determines whether the font is a symbol font. - /// - [PreserveSig] - IntBoolean IsSymbolFont(); - - /// - /// Obtains design units and common metrics for the font face. - /// These metrics are applicable to all the glyphs within a fontface and are used by applications for layout calculations. - /// - /// Points to a DWRITE_FONT_METRICS structure to fill in. - /// The metrics returned by this function are in font design units. - [PreserveSig] - void GetMetrics(out FontMetrics fontFaceMetrics); - - /// - /// Obtains the number of glyphs in the font face. - /// - [PreserveSig] - ushort GetGlyphCount(); - - ///// An array of glyph indices to compute the metrics for. - ///// The number of elements in the glyphIndices array. - ///// Array of DWRITE_GLYPH_METRICS structures filled by this function. - ///// The metrics returned by this function are in font design units. - ///// Indicates whether the font is being used in a sideways run. - ///// This can affect the glyph metrics if the font has oblique simulation - ///// because sideways oblique simulation differs from non-sideways oblique simulation. - /// - /// Obtains ideal glyph metrics in font design units. Design glyphs metrics are used for glyph positioning. - /// - /// - /// Standard HRESULT error code. If any of the input glyph indices are outside of the valid glyph index range - /// for the current font face, E_INVALIDARG will be returned. - /// - void GetDesignGlyphMetricsSTUB(); - //STDMETHOD(GetDesignGlyphMetrics)( - // _In_reads_(glyphCount) UINT16 const* glyphIndices, - // UINT32 glyphCount, - //_Out_writes_(glyphCount) DWRITE_GLYPH_METRICS* glyphMetrics, - //BOOL isSideways = FALSE - //) PURE; - - /// - /// Returns the nominal mapping of UTF-32 Unicode code points to glyph indices as defined by the font 'cmap' - /// table. Note that this mapping is primarily provided for line layout engines built on top of the physical - /// font API. Because of OpenType glyph substitution and line layout character substitution, the nominal - /// conversion does not always correspond to how a Unicode string will map to glyph indices when rendering - /// using a particular font face. Also, note that Unicode Variation Selectors provide for alternate mappings - /// for character to glyph. This call will always return the default variant. - /// - /// An array of UTF-32 code points to obtain nominal glyph indices from. - /// The number of elements in the codePoints array. - /// Array of nominal glyph indices filled by this function. - /// - /// Standard HRESULT error code. - /// - unsafe void GetGlyphIndices( - uint* codePoints, - uint codePointCount, - ushort* glyphIndices); - - /// - /// Finds the specified OpenType font table if it exists and returns a pointer to it. - /// The function accesses the underlying font data via the IDWriteFontFileStream interface - /// implemented by the font file loader. - /// - /// Four character tag of table to find. - /// Use the DWRITE_MAKE_OPENTYPE_TAG() macro to create it. - /// Unlike GDI, it does not support the special TTCF and null tags to access the whole font. - /// - /// Pointer to base of table in memory. - /// The pointer is only valid so long as the FontFace used to get the font table still exists - /// (not any other FontFace, even if it actually refers to the same physical font). - /// - /// Byte size of table. - /// - /// Opaque context which must be freed by calling ReleaseFontTable. - /// The context actually comes from the lower level IDWriteFontFileStream, - /// which may be implemented by the application or DWrite itself. - /// It is possible for a NULL tableContext to be returned, especially if - /// the implementation directly memory maps the whole file. - /// Nevertheless, always release it later, and do not use it as a test for function success. - /// The same table can be queried multiple times, - /// but each returned context can be different, so release each separately. - /// - /// True if table exists. - /// - /// Standard HRESULT error code. - /// If a table can not be found, the function will not return an error, but the size will be 0, table NULL, and exists = FALSE. - /// The context does not need to be freed if the table was not found. - /// - /// - /// The context for the same tag may be different for each call, - /// so each one must be held and released separately. - /// - unsafe IntBoolean TryGetFontTable( - uint openTypeTableTag, - void** tableData, - out uint tableSize, - out IntPtr tableContext, - out IntBoolean exists); - - /// - /// Releases the table obtained earlier from TryGetFontTable. - /// - /// Opaque context from TryGetFontTable. - [PreserveSig] - void ReleaseFontTable(IntPtr tableContext); - - /// - /// Computes the outline of a run of glyphs by calling back to the outline sink interface. - /// - /// Logical size of the font in DIP units. A DIP ("device-independent pixel") equals 1/96 inch. - /// Array of glyph indices. - /// Optional array of glyph advances in DIPs. - /// Optional array of glyph offsets. - /// Number of glyphs. - /// If true, specifies that glyphs are rotated 90 degrees to the left and vertical metrics are used. - /// A client can render a vertical run by specifying isSideways = true and rotating the resulting geometry 90 degrees to the - /// right using a transform. - /// If true, specifies that the advance direction is right to left. By default, the advance direction - /// is left to right. - /// Interface the function calls back to draw each element of the geometry. - unsafe void GetGlyphRunOutline( - float emSize, - ushort* glyphIndices, - float* glyphAdvances, - GlyphOffset* glyphOffsets, - uint glyphCount, - IntBoolean isSideways, - IntBoolean isRightToLeft, - IGeometrySink geometrySink); - - /// - /// Determines the recommended rendering mode for the font given the specified size and rendering parameters. - /// - /// Logical size of the font in DIP units. A DIP ("device-independent pixel") equals 1/96 inch. - /// Number of physical pixels per DIP. For example, if the DPI of the rendering surface is 96 this - /// value is 1.0f. If the DPI is 120, this value is 120.0f/96. - /// Specifies measuring mode that will be used for glyphs in the font. - /// Renderer implementations may choose different rendering modes for given measuring modes, but - /// best results are seen when the corresponding modes match: - /// for - /// for - /// for - /// - /// Rendering parameters object. This parameter is necessary in case the rendering parameters - /// object overrides the rendering mode. - /// - /// The recommended rendering mode to use. - /// - RenderingMode GetRecommendedRenderingMode( - float emSize, - float pixelsPerDip, - MeasuringMode measuringMode, - IRenderingParams renderingParams); - - /// - /// Obtains design units and common metrics for the font face. - /// These metrics are applicable to all the glyphs within a fontface and are used by applications for layout calculations. - /// - /// Logical size of the font in DIP units. A DIP ("device-independent pixel") equals 1/96 inch. - /// Number of physical pixels per DIP. For example, if the DPI of the rendering surface is 96 this - /// value is 1.0f. If the DPI is 120, this value is 120.0f/96. - /// Optional transform applied to the glyphs and their positions. This transform is applied after the - /// scaling specified by the font size and pixelsPerDip. - unsafe FontMetrics GetGdiCompatibleMetrics( - float emSize, - float pixelsPerDip, - Matrix3x2* transform); - - /// - /// Obtains glyph metrics in font design units with the return values compatible with what GDI would produce. - /// Glyphs metrics are used for positioning of individual glyphs. - /// - /// Logical size of the font in DIP units. A DIP ("device-independent pixel") equals 1/96 inch. - /// Number of physical pixels per DIP. For example, if the DPI of the rendering surface is 96 this - /// value is 1.0f. If the DPI is 120, this value is 120.0f/96. - /// Optional transform applied to the glyphs and their positions. This transform is applied after the - /// scaling specified by the font size and pixelsPerDip. - /// - /// When set to FALSE, the metrics are the same as the metrics of GDI aliased text. - /// When set to TRUE, the metrics are the same as the metrics of text measured by GDI using a font - /// created with CLEARTYPE_NATURAL_QUALITY. - /// - /// An array of glyph indices to compute the metrics for. - /// The number of elements in the glyphIndices array. - /// Array of DWRITE_GLYPH_METRICS structures filled by this function. - /// The metrics returned by this function are in font design units. - /// Indicates whether the font is being used in a sideways run. - /// This can affect the glyph metrics if the font has oblique simulation - /// because sideways oblique simulation differs from non-sideways oblique simulation. - unsafe void GetGdiCompatibleGlyphMetrics( - float emSize, - float pixelsPerDip, - Matrix3x2* transform, - IntBoolean useGdiNatural, - in ushort glyphIndices, - uint glyphCount, - out GlyphMetrics glyphMetrics, - IntBoolean isSideways); - } -} diff --git a/src/WInterop.DirectX/DirectWrite/IFontFamily.cs b/src/WInterop.DirectX/DirectWrite/IFontFamily.cs deleted file mode 100644 index 244b87cc..00000000 --- a/src/WInterop.DirectX/DirectWrite/IFontFamily.cs +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) Jeremy W. Kuhne. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Runtime.InteropServices; - -namespace WInterop.DirectWrite -{ - /// - /// The IDWriteFontFamily interface represents a set of fonts that share the same design but are differentiated - /// by weight, stretch, and style. [IDWriteFontFamily] - /// - [ComImport, - Guid(InterfaceIds.IID_IDWriteFontFamily), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IFontFamily : IFontList - { - #region IDWriteFontList - /// - /// Gets the font collection that contains the fonts. - /// - new IFontCollection GetFontCollection(); - - /// - /// Gets the number of fonts in the font list. - /// - [PreserveSig] - new uint GetFontCount(); - - /// - /// Gets a font given its zero-based index. - /// - /// Zero-based index of the font in the font list. - new IFont GetFont(uint index); - #endregion - - /// - /// Creates a localized strings object that contains the family names for the font family, indexed by locale name. - /// - ILocalizedStrings GetFamilyNames(); - - /// - /// Gets the font that best matches the specified properties. - /// - /// Requested font weight. - /// Requested font stretch. - /// Requested font style. - IFont GetFirstMatchingFont( - FontWeight weight, - FontStretch stretch, - FontStyle style); - - /// - /// Gets a list of fonts in the font family ranked in order of how well they match the specified properties. - /// - /// Requested font weight. - /// Requested font stretch. - /// Requested font style. - IFontList GetMatchingFonts( - FontWeight weight, - FontStretch stretch, - FontStyle style); - } -} diff --git a/src/WInterop.DirectX/DirectWrite/IFontList.cs b/src/WInterop.DirectX/DirectWrite/IFontList.cs deleted file mode 100644 index 7876fe9d..00000000 --- a/src/WInterop.DirectX/DirectWrite/IFontList.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) Jeremy W. Kuhne. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Runtime.InteropServices; - -namespace WInterop.DirectWrite -{ - /// - /// The interface represents an ordered set of fonts that are part of an . - /// [IDWriteFontList] - /// - [ComImport, - Guid(InterfaceIds.IID_IDWriteFontList), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IFontList - { - /// - /// Gets the font collection that contains the fonts. - /// - IFontCollection GetFontCollection(); - - /// - /// Gets the number of fonts in the font list. - /// - [PreserveSig] - uint GetFontCount(); - - /// - /// Gets a font given its zero-based index. - /// - /// Zero-based index of the font in the font list. - IFont GetFont(uint index); - } -} diff --git a/src/WInterop.DirectX/DirectWrite/IInlineObject.cs b/src/WInterop.DirectX/DirectWrite/IInlineObject.cs deleted file mode 100644 index 31995a2f..00000000 --- a/src/WInterop.DirectX/DirectWrite/IInlineObject.cs +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) Jeremy W. Kuhne. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Runtime.InteropServices; - -namespace WInterop.DirectWrite -{ - [ComImport, - Guid(InterfaceIds.IID_IDWriteInlineObject), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IInlineObject - { - /// - /// The application implemented rendering callback (IDWriteTextRenderer::DrawInlineObject) - /// can use this to draw the inline object without needing to cast or query the object - /// type. The text layout does not call this method directly. - /// - /// The context passed to IDWriteTextLayout::Draw. - /// The renderer passed to IDWriteTextLayout::Draw as the object's containing parent. - /// X-coordinate at the top-left corner of the inline object. - /// Y-coordinate at the top-left corner of the inline object. - /// The object should be drawn on its side. - /// The object is in an right-to-left context and should be drawn flipped. - /// The drawing effect set in IDWriteTextLayout::SetDrawingEffect. - void Draw( - IntPtr clientDrawingContext, - [MarshalAs(UnmanagedType.IUnknown)] - object renderer, // TODO: IDWriteTextRenderer - float originX, - float originY, - IntBoolean isSideways, - IntBoolean isRightToLeft, - [MarshalAs(UnmanagedType.IUnknown)] - object clientDrawingEffect); - - /// - /// TextLayout calls this callback function to get the measurement of the inline object. - /// - InlineObjectMetrics GetMetrics(); - - /// - /// TextLayout calls this callback function to get the visible extents (in DIPs) of the inline object. - /// In the case of a simple bitmap, with no padding and no overhang, all the overhangs will simply be zeroes. - /// - /// Overshoot of visible extents (in DIPs) outside the object. - /// - /// The overhangs should be returned relative to the reported size of the object (DWRITE_INLINE_OBJECT_METRICS - /// ::width/height), and should not be baseline adjusted. If you have an image that is actually 100x100 DIPs, - /// but you want it slightly inset (perhaps it has a glow) by 20 DIPs on each side, you would return a - /// width/height of 60x60 and four overhangs of 20 DIPs. - /// - OverhangMetrics GetOverhangMetrics(); - - /// - /// Layout uses this to determine the line breaking behavior of the inline object amidst the text. - /// - /// - /// Line-breaking condition between the object and the content immediately preceding it. - /// - /// - /// Line-breaking condition between the object and the content immediately following it. - /// - void GetBreakConditions( - out BreakCondition breakConditionBefore, - out BreakCondition breakConditionAfter); - } -} diff --git a/src/WInterop.DirectX/DirectWrite/ILocalizedStrings.cs b/src/WInterop.DirectX/DirectWrite/ILocalizedStrings.cs deleted file mode 100644 index d23c4893..00000000 --- a/src/WInterop.DirectX/DirectWrite/ILocalizedStrings.cs +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) Jeremy W. Kuhne. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Runtime.InteropServices; - -namespace WInterop.DirectWrite -{ - /// - /// Represents a collection of strings indexed by locale name. [IDWriteLocalizedStrings] - /// - [ComImport, - Guid(InterfaceIds.IID_IDWriteLocalizedStrings), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface ILocalizedStrings - { - /// - /// Gets the number of language/string pairs. - /// - [PreserveSig] - uint GetCount(); - - /// - /// Gets the index of the item with the specified locale name. - /// - /// Locale name to look for. - /// Receives the zero-based index of the locale name/string pair. - /// TRUE if the locale name exists or FALSE if not. - IntBoolean FindLocaleName( - [MarshalAs(UnmanagedType.LPWStr)] - string localeName, - out uint index); - - /// - /// Gets the length in characters (not including the null terminator) of the locale name with the specified index. - /// - /// Zero-based index of the locale name. - /// Receives the length in characters, not including the null terminator. - uint GetLocaleNameLength(uint index); - - /// - /// Copies the locale name with the specified index to the specified array. - /// - /// Zero-based index of the locale name. - /// Character array that receives the locale name. - /// Size of the array in characters. The size must include space for the terminating - /// null character. - unsafe void GetLocaleName( - uint index, - char* localeName, - uint size); - - /// - /// Gets the length in characters (not including the null terminator) of the string with the specified index. - /// - /// Zero-based index of the string. - /// - /// The length in characters, not including the null terminator. - /// - uint GetStringLength(uint index); - - /// - /// Copies the string with the specified index to the specified array. - /// - /// Zero-based index of the string. - /// Character array that receives the string. - /// Size of the array in characters. The size must include space for the terminating - /// null character. - /// - /// Standard HRESULT error code. - /// - unsafe void GetString( - uint index, - char* stringBuffer, - uint size); - } -} diff --git a/src/WInterop.DirectX/DirectWrite/IPixelSnapping.cs b/src/WInterop.DirectX/DirectWrite/IPixelSnapping.cs deleted file mode 100644 index 2f81be6a..00000000 --- a/src/WInterop.DirectX/DirectWrite/IPixelSnapping.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) Jeremy W. Kuhne. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Numerics; -using System.Runtime.InteropServices; - -namespace WInterop.DirectWrite -{ - /// - /// The interface defines the pixel snapping properties of a text renderer. - /// [IDWritePixelSnapping] - /// - [ComImport, - Guid(InterfaceIds.IID_IDWritePixelSnapping), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IPixelSnapping - { - /// - /// Determines whether pixel snapping is disabled. The recommended default is FALSE, - /// unless doing animation that requires subpixel vertical placement. - /// - /// The context passed to IDWriteTextLayout::Draw. - IntBoolean IsPixelSnappingDisabled(IntPtr clientDrawingContext); - - /// - /// Gets the current transform that maps abstract coordinates to DIPs, - /// which may disable pixel snapping upon any rotation or shear. - /// - /// The context passed to IDWriteTextLayout::Draw. - Matrix3x2 GetCurrentTransform(IntPtr clientDrawingContext); - - /// - /// Gets the number of physical pixels per DIP. A DIP (device-independent pixel) is 1/96 inch, - /// so the pixelsPerDip value is the number of logical pixels per inch divided by 96 (yielding - /// a value of 1 for 96 DPI and 1.25 for 120). - /// - /// The context passed to IDWriteTextLayout::Draw. - /// Receives the number of physical pixels per DIP. - float GetPixelsPerDip(IntPtr clientDrawingContext); - } -} diff --git a/src/WInterop.DirectX/DirectWrite/IRenderingParams.cs b/src/WInterop.DirectX/DirectWrite/IRenderingParams.cs deleted file mode 100644 index 51f41ff5..00000000 --- a/src/WInterop.DirectX/DirectWrite/IRenderingParams.cs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) Jeremy W. Kuhne. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Runtime.InteropServices; - -namespace WInterop.DirectWrite -{ - /// - /// The interface that represents text rendering settings for glyph rasterization and filtering. - /// [IDWriteRenderingParams] - /// - [ComImport, - Guid(InterfaceIds.IID_IDWriteRenderingParams), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IRenderingParams - { - /// - /// Gets the gamma value used for gamma correction. Valid values must be - /// greater than zero and cannot exceed 256. - /// - [PreserveSig] - float GetGamma(); - - /// - /// Gets the amount of contrast enhancement. Valid values are greater than - /// or equal to zero. - /// - [PreserveSig] - float GetEnhancedContrast(); - - /// - /// Gets the ClearType level. Valid values range from 0.0f (no ClearType) - /// to 1.0f (full ClearType). - /// - [PreserveSig] - float GetClearTypeLevel(); - - /// - /// Gets the pixel geometry. - /// - [PreserveSig] - PixelGeometry GetPixelGeometry(); - - /// - /// Gets the rendering mode. - /// - [PreserveSig] - RenderingMode GetRenderingMode(); - } -} diff --git a/src/WInterop.DirectX/DirectWrite/ITextFormat.cs b/src/WInterop.DirectX/DirectWrite/ITextFormat.cs deleted file mode 100644 index a9c05449..00000000 --- a/src/WInterop.DirectX/DirectWrite/ITextFormat.cs +++ /dev/null @@ -1,210 +0,0 @@ -// Copyright (c) Jeremy W. Kuhne. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Runtime.InteropServices; - -namespace WInterop.DirectWrite -{ - /// - /// The format of text used for text layout. [IDWriteTextFormat] - /// - /// - /// This object may not be thread-safe and it may carry the state of text format change. - /// - [ComImport, - Guid(InterfaceIds.IID_IDWriteTextFormat), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface ITextFormat - { - /// - /// Set alignment option of text relative to layout box's leading and trailing edge. - /// - /// Text alignment option - /// - /// Standard HRESULT error code. - /// - void SetTextAlignment(TextAlignment textAlignment); - - /// - /// Set alignment option of paragraph relative to layout box's top and bottom edge. - /// - /// Paragraph alignment option - void SetParagraphAlignment(ParagraphAlignment paragraphAlignment); - - /// - /// Set word wrapping option. - /// - /// Word wrapping option - void SetWordWrapping(WordWrapping wordWrapping); - - /// - /// Set paragraph reading direction. - /// - /// Text reading direction - /// - /// The flow direction must be perpendicular to the reading direction. Setting both to a vertical direction - /// or both to horizontal yields DWRITE_E_FLOWDIRECTIONCONFLICTS when calling GetMetrics or Draw. - /// - void SetReadingDirection(ReadingDirection readingDirection); - - /// - /// Set paragraph flow direction. - /// - /// Paragraph flow direction - /// - /// The flow direction must be perpendicular to the reading direction. Setting both to a vertical direction - /// or both to horizontal yields DWRITE_E_FLOWDIRECTIONCONFLICTS when calling GetMetrics or Draw. - /// - void SetFlowDirection(FlowDirection flowDirection); - - /// - /// Set incremental tab stop position. - /// - /// The incremental tab stop value - void SetIncrementalTabStop(float incrementalTabStop); - - /// - /// Set trimming options for any trailing text exceeding the layout width or for any far text exceeding the - /// layout height. - /// - /// Text trimming options. - /// - /// Application-defined omission sign. This parameter may be NULL if no trimming sign is desired. - /// - /// - /// Any inline object can be used for the trimming sign, but CreateEllipsisTrimmingSign provides a typical - /// ellipsis symbol. Trimming is also useful vertically for hiding partial lines. - /// - void SetTrimming( - in Trimming trimmingOptions, - IInlineObject trimmingSign); - - /// - /// Set line spacing. - /// - /// How to determine line height. - /// The line height, or rather distance between one baseline to another. - /// Distance from top of line to baseline. A reasonable ratio to lineSpacing is 80%. - /// - /// For the default method, spacing depends solely on the content. For uniform spacing, the given line height - /// will override the content. - /// - void SetLineSpacing( - LineSpacingMethod lineSpacingMethod, - float lineSpacing, - float baseline); - - /// - /// Get alignment option of text relative to layout box's leading and trailing edge. - /// - [PreserveSig] - TextAlignment GetTextAlignment(); - - /// - /// Get alignment option of paragraph relative to layout box's top and bottom edge. - /// - [PreserveSig] - ParagraphAlignment GetParagraphAlignment(); - - /// - /// Get word wrapping option. - /// - [PreserveSig] - WordWrapping GetWordWrapping(); - - /// - /// Get paragraph reading direction. - /// - [PreserveSig] - ReadingDirection GetReadingDirection(); - - /// - /// Get paragraph flow direction. - /// - [PreserveSig] - FlowDirection GetFlowDirection(); - - /// - /// Get incremental tab stop position. - /// - [PreserveSig] - float GetIncrementalTabStop(); - - /// - /// Get trimming options for text overflowing the layout width. - /// - /// Text trimming options. - IInlineObject GetTrimming(out Trimming trimmingOptions); - - /// - /// Get line spacing. - /// - /// How line height is determined. - /// The line height, or rather distance between one baseline to another. - /// Distance from top of line to baseline. - void GetLineSpacing( - out LineSpacingMethod lineSpacingMethod, - out float lineSpacing, - out float baseline); - - /// - /// Get the font collection. - /// - IFontCollection GetFontCollection(); - - /// - /// Get the length of the font family name, in characters, not including the terminating NULL character. - /// - [PreserveSig] - uint GetFontFamilyNameLength(); - - /// - /// Get a copy of the font family name. - /// - /// Character array that receives the current font family name - /// Size of the character array in character count including the terminated NULL character. - unsafe void GetFontFamilyName( - char* fontFamilyName, - uint nameSize); - - /// - /// Get the font weight. - /// - [PreserveSig] - FontWeight GetFontWeight(); - - /// - /// Get the font style. - /// - [PreserveSig] - FontStyle GetFontStyle(); - - /// - /// Get the font stretch. - /// - [PreserveSig] - FontStretch GetFontStretch(); - - /// - /// Get the font em height. - /// - [PreserveSig] - float GetFontSize(); - - /// - /// Get the length of the locale name, in characters, not including the terminating NULL character. - /// - [PreserveSig] - uint GetLocaleNameLength(); - - /// - /// Get a copy of the locale name. - /// - /// Character array that receives the current locale name - /// Size of the character array in character count including the terminated NULL character. - unsafe void GetLocaleName( - char* localeName, - uint nameSize); - } -} diff --git a/src/WInterop.DirectX/DirectWrite/ITextLayout.cs b/src/WInterop.DirectX/DirectWrite/ITextLayout.cs deleted file mode 100644 index 67eaf80d..00000000 --- a/src/WInterop.DirectX/DirectWrite/ITextLayout.cs +++ /dev/null @@ -1,710 +0,0 @@ -// Copyright (c) Jeremy W. Kuhne. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Drawing; -using System.Runtime.InteropServices; - -namespace WInterop.DirectWrite -{ - /// - /// The IDWriteTextLayout interface represents a block of text after it has - /// been fully analyzed and formatted. [IDWriteTextLayout] - /// - /// All coordinates are in device independent pixels (DIPs). - /// - [ComImport, - Guid(InterfaceIds.IID_IDWriteTextLayout), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface ITextLayout : ITextFormat - { - #region IID_IDWriteTextFormat - /// - /// Set alignment option of text relative to layout box's leading and trailing edge. - /// - /// Text alignment option - /// - /// Standard HRESULT error code. - /// - new void SetTextAlignment(TextAlignment textAlignment); - - /// - /// Set alignment option of paragraph relative to layout box's top and bottom edge. - /// - /// Paragraph alignment option - new void SetParagraphAlignment(ParagraphAlignment paragraphAlignment); - - /// - /// Set word wrapping option. - /// - /// Word wrapping option - new void SetWordWrapping(WordWrapping wordWrapping); - - /// - /// Set paragraph reading direction. - /// - /// Text reading direction - /// - /// The flow direction must be perpendicular to the reading direction. Setting both to a vertical direction - /// or both to horizontal yields DWRITE_E_FLOWDIRECTIONCONFLICTS when calling GetMetrics or Draw. - /// - new void SetReadingDirection(ReadingDirection readingDirection); - - /// - /// Set paragraph flow direction. - /// - /// Paragraph flow direction - /// - /// The flow direction must be perpendicular to the reading direction. Setting both to a vertical direction - /// or both to horizontal yields DWRITE_E_FLOWDIRECTIONCONFLICTS when calling GetMetrics or Draw. - /// - new void SetFlowDirection(FlowDirection flowDirection); - - /// - /// Set incremental tab stop position. - /// - /// The incremental tab stop value - new void SetIncrementalTabStop(float incrementalTabStop); - - /// - /// Set trimming options for any trailing text exceeding the layout width or for any far text exceeding the - /// layout height. - /// - /// Text trimming options. - /// - /// Application-defined omission sign. This parameter may be NULL if no trimming sign is desired. - /// - /// - /// Any inline object can be used for the trimming sign, but CreateEllipsisTrimmingSign provides a typical - /// ellipsis symbol. Trimming is also useful vertically for hiding - /// partial lines. - /// - new void SetTrimming( - in Trimming trimmingOptions, - IInlineObject trimmingSign); - - /// - /// Set line spacing. - /// - /// How to determine line height. - /// The line height, or rather distance between one baseline to another. - /// Distance from top of line to baseline. A reasonable ratio to lineSpacing is 80%. - /// - /// For the default method, spacing depends solely on the content. - /// For uniform spacing, the given line height will override the content. - /// - new void SetLineSpacing( - LineSpacingMethod lineSpacingMethod, - float lineSpacing, - float baseline); - - /// - /// Get alignment option of text relative to layout box's leading and trailing edge. - /// - [PreserveSig] - new TextAlignment GetTextAlignment(); - - /// - /// Get alignment option of paragraph relative to layout box's top and bottom edge. - /// - [PreserveSig] - new ParagraphAlignment GetParagraphAlignment(); - - /// - /// Get word wrapping option. - /// - [PreserveSig] - new WordWrapping GetWordWrapping(); - - /// - /// Get paragraph reading direction. - /// - [PreserveSig] - new ReadingDirection GetReadingDirection(); - - /// - /// Get paragraph flow direction. - /// - [PreserveSig] - new FlowDirection GetFlowDirection(); - - /// - /// Get incremental tab stop position. - /// - [PreserveSig] - new float GetIncrementalTabStop(); - - /// - /// Get trimming options for text overflowing the layout width. - /// - /// Text trimming options. - new IInlineObject GetTrimming(out Trimming trimmingOptions); - - /// - /// Get line spacing. - /// - /// How line height is determined. - /// The line height, or rather distance between one baseline to another. - /// Distance from top of line to baseline. - new void GetLineSpacing( - out LineSpacingMethod lineSpacingMethod, - out float lineSpacing, - out float baseline); - - /// - /// Get the font collection. - /// - new IFontCollection GetFontCollection(); - - /// - /// Get the length of the font family name, in characters, not including the terminating NULL character. - /// - [PreserveSig] - new uint GetFontFamilyNameLength(); - - /// - /// Get a copy of the font family name. - /// - /// Character array that receives the current font family name - /// Size of the character array in character count including the terminated NULL character. - new unsafe void GetFontFamilyName( - char* fontFamilyName, - uint nameSize); - - /// - /// Get the font weight. - /// - [PreserveSig] - new FontWeight GetFontWeight(); - - /// - /// Get the font style. - /// - [PreserveSig] - new FontStyle GetFontStyle(); - - /// - /// Get the font stretch. - /// - [PreserveSig] - new FontStretch GetFontStretch(); - - /// - /// Get the font em height. - /// - [PreserveSig] - new float GetFontSize(); - - /// - /// Get the length of the locale name, in characters, not including the terminating NULL character. - /// - [PreserveSig] - new uint GetLocaleNameLength(); - - /// - /// Get a copy of the locale name. - /// - /// Character array that receives the current locale name - /// Size of the character array in character count including the terminated NULL character. - new unsafe void GetLocaleName( - char* localeName, - uint nameSize); - #endregion - - /// - /// Set layout maximum width - /// - /// Layout maximum width - void SetMaxWidth(float maxWidth); - - /// - /// Set layout maximum height - /// - /// Layout maximum height - void SetMaxHeight(float maxHeight); - - /// - /// Set the font collection. - /// - /// The font collection to set - /// Text range to which this change applies. - void SetFontCollection( - IFontCollection fontCollection, - TextRange textRange); - - /// - /// Set null-terminated font family name. - /// - /// Font family name - /// Text range to which this change applies. - void SetFontFamilyName( - [MarshalAs(UnmanagedType.LPWStr)] - string fontFamilyName, - TextRange textRange); - - /// - /// Set font weight. - /// - /// Font weight - /// Text range to which this change applies. - void SetFontWeight( - FontWeight fontWeight, - TextRange textRange); - - /// - /// Set font style. - /// - /// Font style - /// Text range to which this change applies. - void SetFontStyle( - FontStyle fontStyle, - TextRange textRange); - - /// - /// Set font stretch. - /// - /// font stretch - /// Text range to which this change applies. - void SetFontStretch( - FontStretch fontStretch, - TextRange textRange); - - /// - /// Set font em height. - /// - /// Font em height - /// Text range to which this change applies. - void SetFontSize( - float fontSize, - TextRange textRange); - - /// - /// Set underline. - /// - /// The Boolean flag indicates whether underline takes place - /// Text range to which this change applies. - void SetUnderline( - IntBoolean hasUnderline, - TextRange textRange); - - /// - /// Set strikethrough. - /// - /// The Boolean flag indicates whether strikethrough takes place - /// Text range to which this change applies. - void SetStrikethrough( - IntBoolean hasStrikethrough, - TextRange textRange); - - /// - /// Set application-defined drawing effect. - /// - /// Pointer to an application-defined drawing effect. - /// Text range to which this change applies. - /// - /// This drawing effect is associated with the specified range and will be passed back - /// to the application via the callback when the range is drawn at drawing time. - /// - void SetDrawingEffect( - [MarshalAs(UnmanagedType.IUnknown)] - object drawingEffect, - TextRange textRange); - - /// - /// Set inline object. - /// - /// Pointer to an application-implemented inline object. - /// Text range to which this change applies. - /// - /// This inline object applies to the specified range and will be passed back - /// to the application via the DrawInlineObject callback when the range is drawn. - /// Any text in that range will be suppressed. - /// - void SetInlineObject( - IInlineObject inlineObject, - TextRange textRange); - - /// - /// Set font typography features. - /// - /// Pointer to font typography setting. - /// Text range to which this change applies. - void SetTypography( - ITypography typography, - TextRange textRange); - - /// - /// Set locale name. - /// - /// Locale name - /// Text range to which this change applies. - void SetLocaleName( - [MarshalAs(UnmanagedType.LPWStr)] - string localeName, - TextRange textRange); - - /// - /// Get layout maximum width - /// - [PreserveSig] - float GetMaxWidth(); - - /// - /// Get layout maximum height - /// - [PreserveSig] - float GetMaxHeight(); - - /// - /// Get the font collection where the current position is at. - /// - /// The current text position. - /// The current font collection - /// Text range to which this change applies. - unsafe void GetFontCollection( - uint currentPosition, - out IFontCollection fontCollection, - TextRange* textRange); - - /// - /// Get the length of the font family name where the current position is at. - /// - /// The current text position. - /// Size of the character array in character count not including the terminated NULL character. - /// The position range of the current format. - unsafe void GetFontFamilyNameLength( - uint currentPosition, - out uint nameLength, - TextRange* textRange); - - /// - /// Copy the font family name where the current position is at. - /// - /// The current text position. - /// Character array that receives the current font family name - /// Size of the character array in character count including the terminated NULL character. - /// The position range of the current format. - unsafe void GetFontFamilyName( - uint currentPosition, - char* fontFamilyName, - uint nameSize, - TextRange* textRange); - - /// - /// Get the font weight where the current position is at. - /// - /// The current text position. - /// The current font weight - /// The position range of the current format. - unsafe void GetFontWeight( - uint currentPosition, - out FontWeight fontWeight, - TextRange* textRange); - - /// - /// Get the font style where the current position is at. - /// - /// The current text position. - /// The current font style - /// The position range of the current format. - /// - /// Standard HRESULT error code. - /// - unsafe void GetFontStyle( - uint currentPosition, - out FontStyle fontStyle, - TextRange* textRange); - - /// - /// Get the font stretch where the current position is at. - /// - /// The current text position. - /// The current font stretch - /// The position range of the current format. - unsafe void GetFontStretch( - uint currentPosition, - out FontStretch fontStretch, - TextRange* textRange); - - /// - /// Get the font em height where the current position is at. - /// - /// The current text position. - /// The current font em height - /// The position range of the current format. - unsafe void GetFontSize( - uint currentPosition, - out float fontSize, - TextRange* textRange); - - /// - /// Get the underline presence where the current position is at. - /// - /// The current text position. - /// The Boolean flag indicates whether text is underlined. - /// The position range of the current format. - - unsafe void GetUnderline( - uint currentPosition, - out IntBoolean hasUnderline, - TextRange* textRange); - - /// - /// Get the strikethrough presence where the current position is at. - /// - /// The current text position. - /// The Boolean flag indicates whether text has strikethrough. - /// The position range of the current format. - unsafe void GetStrikethrough( - uint currentPosition, - out IntBoolean hasStrikethrough, - TextRange* textRange); - - /// - /// Get the application-defined drawing effect where the current position is at. - /// - /// The current text position. - /// The current application-defined drawing effect. - /// The position range of the current format. - unsafe void GetDrawingEffect( - uint currentPosition, - [MarshalAs(UnmanagedType.IUnknown)] - out object drawingEffect, - TextRange* textRange); - - /// - /// Get the inline object at the given position. - /// - /// The given text position. - /// The inline object. - /// The position range of the current format. - unsafe void GetInlineObject( - uint currentPosition, - out IInlineObject inlineObject, - TextRange* textRange); - - /// - /// Get the typography setting where the current position is at. - /// - /// The current text position. - /// The current typography setting. - /// The position range of the current format. - unsafe void GetTypography( - uint currentPosition, - out ITypography typography, - TextRange* textRange); - - /// - /// Get the length of the locale name where the current position is at. - /// - /// The current text position. - /// Size of the character array in character count not including the terminated NULL character. - /// The position range of the current format. - unsafe void GetLocaleNameLength( - uint currentPosition, - out uint nameLength, - TextRange* textRange); - - /// - /// Get the locale name where the current position is at. - /// - /// The current text position. - /// Character array that receives the current locale name - /// Size of the character array in character count including the terminated NULL character. - /// The position range of the current format. - unsafe void GetLocaleName( - uint currentPosition, - char* localeName, - uint nameSize, - TextRange* textRange); - - /// - /// Initiate drawing of the text. - /// - /// An application defined value - /// included in rendering callbacks. - /// The set of application-defined callbacks that do - /// the actual rendering. - /// X-coordinate of the layout's left side. - /// Y-coordinate of the layout's top side. - void Draw( - IntPtr clientDrawingContext, - ITextRenderer renderer, - float originX, - float originY); - - /// - /// GetLineMetrics returns properties of each line. - /// - /// The array to fill with line information. - /// The maximum size of the lineMetrics array. - /// The actual size of the lineMetrics - /// array that is needed. - /// - /// If maxLineCount is not large enough E_NOT_SUFFICIENT_BUFFER, - /// which is equivalent to HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), - /// is returned and *actualLineCount is set to the number of lines - /// needed. - /// - unsafe void GetLineMetrics( - LineMetrics* lineMetrics, - uint maxLineCount, - out uint actualLineCount); - - /// - /// GetMetrics retrieves overall metrics for the formatted string. - /// - /// - /// Drawing effects like underline and strikethrough do not contribute to the text size, which is essentially - /// the sum of advance widths and line heights. Additionally, visible swashes and other graphic adornments - /// may extend outside the returned width and height. - /// - TextMetrics GetMetrics(); - - /// - /// GetOverhangMetrics returns the overhangs (in DIPs) of the layout and all objects contained in it, - /// including text glyphs and inline objects. - /// - /// Overshoots of visible extents (in DIPs) outside the layout. - /// - /// Any underline and strikethrough do not contribute to the black box determination, since these are - /// actually drawn by the renderer, which is allowed to draw them in any variety of styles. - /// - OverhangMetrics GetOverhangMetrics(); - - /// - /// Retrieve logical properties and measurement of each cluster. - /// - /// The array to fill with cluster information. - /// The maximum size of the clusterMetrics array. - /// The actual size of the clusterMetrics array that is needed. - /// - /// If maxClusterCount is not large enough E_NOT_SUFFICIENT_BUFFER, - /// which is equivalent to HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), - /// is returned and *actualClusterCount is set to the number of clusters - /// needed. - /// - unsafe void GetClusterMetrics( - ClusterMetrics* clusterMetrics, - uint maxClusterCount, - out uint actualClusterCount); - - /// - /// Determines the minimum possible width the layout can be set to without emergency breaking between - /// the characters of whole words. - /// - float DetermineMinWidth(); - - /// - /// Given a coordinate (in DIPs) relative to the top-left of the layout box, this returns the corresponding - /// hit-test metrics of the text string where the hit-test has occurred. This is useful for mapping mouse - /// clicks to caret positions. When the given coordinate is outside the text string, the function sets the - /// output value *isInside to false but returns the nearest character position. - /// - /// X coordinate to hit-test, relative to the top-left location of the layout box. - /// Y coordinate to hit-test, relative to the top-left location of the layout box. - /// - /// Output flag indicating whether the hit-test location is at the leading or the trailing side of the - /// character. When is set to false, this value is set according to the output - /// *position value to represent the edge closest to the hit-test location. - /// - /// - /// Output flag indicating whether the hit-test location is inside the text string. When false, the position - /// nearest the text's edge is returned. - /// - /// Output geometry fully enclosing the hit-test location. When the output value - /// is set to false, this structure represents the geometry enclosing the edge closest to the hit-test - /// location. - /// - HitTestMetrics HitTestPoint( - float pointX, - float pointY, - out IntBoolean isTrailingHit, - out IntBoolean isInside); - - /// - /// Given a text position and whether the caret is on the leading or trailing - /// edge of that position, this returns the corresponding coordinate (in DIPs) - /// relative to the top-left of the layout box. This is most useful for drawing - /// the caret's current position, but it could also be used to anchor an IME to the - /// typed text or attach a floating menu near the point of interest. It may also be - /// used to programmatically obtain the geometry of a particular text position - /// for UI automation. - /// - /// Text position to get the coordinate of. - /// Flag indicating whether the location is of the leading or the trailing side of the specified text position. - /// Output caret X, relative to the top-left of the layout box. - /// Output caret Y, relative to the top-left of the layout box. - /// Output geometry fully enclosing the specified text position. - /// - /// When drawing a caret at the returned X,Y, it should be centered on X - /// and drawn from the Y coordinate down. The height will be the size of the - /// hit-tested text (which can vary in size within a line). - /// Reading direction also affects which side of the character the caret is drawn. - /// However, the returned X coordinate will be correct for either case. - /// You can get a text length back that is larger than a single character. - /// This happens for complex scripts when multiple characters form a single cluster, - /// when diacritics join their base character, or when you test a surrogate pair. - /// - HitTestMetrics HitTestTextPosition( - uint textPosition, - IntBoolean isTrailingHit, - out float pointX, - out float pointY); - - /// - /// The application calls this function to get a set of hit-test metrics - /// corresponding to a range of text positions. The main usage for this - /// is to draw highlighted selection of the text string. - /// - /// The function returns E_NOT_SUFFICIENT_BUFFER, which is equivalent to - /// HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), when the buffer size of - /// hitTestMetrics is too small to hold all the regions calculated by the - /// function. In such situation, the function sets the output value - /// *actualHitTestMetricsCount to the number of geometries calculated. - /// The application is responsible to allocate a new buffer of greater - /// size and call the function again. - /// - /// A good value to use as an initial value for maxHitTestMetricsCount may - /// be calculated from the following equation: - /// maxHitTestMetricsCount = lineCount * maxBidiReorderingDepth - /// - /// where lineCount is obtained from the value of the output argument - /// *actualLineCount from the function IDWriteTextLayout::GetLineMetrics, - /// and the maxBidiReorderingDepth value from the DWRITE_TEXT_METRICS - /// structure of the output argument *textMetrics from the function - /// . - /// - /// First text position of the specified range. - /// Number of positions of the specified range. - /// Offset of the X origin (left of the layout box) which is added to each of the hit-test metrics returned. - /// Offset of the Y origin (top of the layout box) which is added to each of the hit-test metrics returned. - /// Pointer to a buffer of the output geometry fully enclosing the specified position range. - /// Maximum number of distinct metrics it could hold in its buffer memory. - /// Actual number of metrics returned or needed. - /// - /// There are no gaps in the returned metrics. While there could be visual gaps, - /// depending on bidi ordering, each range is contiguous and reports all the text, - /// including any hidden characters and trimmed text. - /// The height of each returned range will be the same within each line, regardless - /// of how the font sizes vary. - /// - unsafe void HitTestTextRange( - uint textPosition, - uint textLength, - float originX, - float originY, - HitTestMetrics* hitTestMetrics, - uint maxHitTestMetricsCount, - out uint actualHitTestMetricsCount); - } - - public static class TextLayoutExtensions - { - public static void SetMaxSize(this ITextLayout textLayout, SizeF maxSize) - { - textLayout.SetMaxHeight(maxSize.Height); - textLayout.SetMaxWidth(maxSize.Width); - } - } -} diff --git a/src/WInterop.DirectX/DirectWrite/ITextRenderer.cs b/src/WInterop.DirectX/DirectWrite/ITextRenderer.cs deleted file mode 100644 index 1538d0a3..00000000 --- a/src/WInterop.DirectX/DirectWrite/ITextRenderer.cs +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright (c) Jeremy W. Kuhne. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Numerics; -using System.Runtime.InteropServices; - -namespace WInterop.DirectWrite -{ - /// - /// The interface represents a set of application-defined - /// callbacks that perform rendering of text, inline objects, and decorations - /// such as underlines. [IDWriteTextRenderer] - /// - [ComImport, - Guid(InterfaceIds.IID_IDWriteTextRenderer), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface ITextRenderer : IPixelSnapping - { - #region IDWritePixelSnapping - /// - /// Determines whether pixel snapping is disabled. The recommended default is FALSE, - /// unless doing animation that requires subpixel vertical placement. - /// - /// The context passed to IDWriteTextLayout::Draw. - new IntBoolean IsPixelSnappingDisabled(IntPtr clientDrawingContext); - - /// - /// Gets the current transform that maps abstract coordinates to DIPs, - /// which may disable pixel snapping upon any rotation or shear. - /// - /// The context passed to IDWriteTextLayout::Draw. - new Matrix3x2 GetCurrentTransform(IntPtr clientDrawingContext); - - /// - /// Gets the number of physical pixels per DIP. A DIP (device-independent pixel) is 1/96 inch, - /// so the pixelsPerDip value is the number of logical pixels per inch divided by 96 (yielding - /// a value of 1 for 96 DPI and 1.25 for 120). - /// - /// The context passed to IDWriteTextLayout::Draw. - /// Receives the number of physical pixels per DIP. - new float GetPixelsPerDip(IntPtr clientDrawingContext); - #endregion - - /// - /// IDWriteTextLayout::Draw calls this function to instruct the client to - /// render a run of glyphs. - /// - /// The context passed to - /// IDWriteTextLayout::Draw. - /// X-coordinate of the baseline. - /// Y-coordinate of the baseline. - /// Specifies measuring mode for glyphs in the run. - /// Renderer implementations may choose different rendering modes for given measuring modes, - /// but best results are seen when the rendering mode matches the corresponding measuring mode: - /// DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL for DWRITE_MEASURING_MODE_NATURAL - /// DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC for DWRITE_MEASURING_MODE_GDI_CLASSIC - /// DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL for DWRITE_MEASURING_MODE_GDI_NATURAL - /// - /// The glyph run to draw. - /// Properties of the characters associated with this run. - /// The drawing effect set in - void DrawGlyphRun( - IntPtr clientDrawingContext, - float baselineOriginX, - float baselineOriginY, - MeasuringMode measuringMode, - in GlyphRun glyphRun, - in GlyphRunDescription glyphRunDescription, - [MarshalAs(UnmanagedType.IUnknown)] - object clientDrawingEffect); - - /// - /// IDWriteTextLayout::Draw calls this function to instruct the client to draw - /// an underline. - /// - /// The context passed to - /// IDWriteTextLayout::Draw. - /// X-coordinate of the baseline. - /// Y-coordinate of the baseline. - /// Underline logical information. - /// The drawing effect set in - /// IDWriteTextLayout::SetDrawingEffect. - /// - /// A single underline can be broken into multiple calls, depending on - /// how the formatting changes attributes. If font sizes/styles change - /// within an underline, the thickness and offset will be averaged - /// weighted according to characters. - /// To get the correct top coordinate of the underline rect, add underline::offset - /// to the baseline's Y. Otherwise the underline will be immediately under the text. - /// The x coordinate will always be passed as the left side, regardless - /// of text directionality. This simplifies drawing and reduces the - /// problem of round-off that could potentially cause gaps or a double - /// stamped alpha blend. To avoid alpha overlap, round the end points - /// to the nearest device pixel. - /// - void DrawUnderline( - IntPtr clientDrawingContext, - float baselineOriginX, - float baselineOriginY, - in Underline underline, - [MarshalAs(UnmanagedType.IUnknown)] - object clientDrawingEffect); - - /// - /// IDWriteTextLayout::Draw calls this function to instruct the client to draw - /// a strikethrough. - /// - /// The context passed to - /// IDWriteTextLayout::Draw. - /// X-coordinate of the baseline. - /// Y-coordinate of the baseline. - /// Strikethrough logical information. - /// The drawing effect set in - /// IDWriteTextLayout::SetDrawingEffect. - /// - /// A single strikethrough can be broken into multiple calls, depending on - /// how the formatting changes attributes. Strikethrough is not averaged - /// across font sizes/styles changes. - /// To get the correct top coordinate of the strikethrough rect, - /// add strikethrough::offset to the baseline's Y. - /// Like underlines, the x coordinate will always be passed as the left side, - /// regardless of text directionality. - /// - void DrawStrikethrough( - IntPtr clientDrawingContext, - float baselineOriginX, - float baselineOriginY, - in Strikethrough strikethrough, - [MarshalAs(UnmanagedType.IUnknown)] - object clientDrawingEffect); - - /// - /// IDWriteTextLayout::Draw calls this application callback when it needs to - /// draw an inline object. - /// - /// The context passed to IDWriteTextLayout::Draw. - /// X-coordinate at the top-left corner of the inline object. - /// Y-coordinate at the top-left corner of the inline object. - /// The object set using IDWriteTextLayout::SetInlineObject. - /// The object should be drawn on its side. - /// The object is in an right-to-left context and should be drawn flipped. - /// The drawing effect set in - /// IDWriteTextLayout::SetDrawingEffect. - /// - /// The right-to-left flag is a hint for those cases where it would look - /// strange for the image to be shown normally (like an arrow pointing to - /// right to indicate a submenu). - /// - void DrawInlineObject( - IntPtr clientDrawingContext, - float originX, - float originY, - IInlineObject inlineObject, - IntBoolean isSideways, - IntBoolean isRightToLeft, - [MarshalAs(UnmanagedType.IUnknown)] - object clientDrawingEffect); - } -} diff --git a/src/WInterop.DirectX/DirectWrite/ITypography.cs b/src/WInterop.DirectX/DirectWrite/ITypography.cs deleted file mode 100644 index b36e23fa..00000000 --- a/src/WInterop.DirectX/DirectWrite/ITypography.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) Jeremy W. Kuhne. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Runtime.InteropServices; - -namespace WInterop.DirectWrite -{ - /// - /// Font typography setting. [IDWriteTypography] - /// - [ComImport, - Guid(InterfaceIds.IID_IDWriteTypography), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface ITypography - { - /// - /// Add font feature. - /// - /// The font feature to add. - void AddFontFeature(FontFeature fontFeature); - - /// - /// Get the number of font features. - /// - [PreserveSig] - uint GetFontFeatureCount(); - - /// - /// Get the font feature at the specified index. - /// - /// The zero-based index of the font feature to get. - /// The font feature. - void GetFontFeature( - uint fontFeatureIndex, - out FontFeature fontFeature); - } -} diff --git a/src/WInterop.DirectX/DirectWrite/InformationalStringId.cs b/src/WInterop.DirectX/DirectWrite/InformationalStringId.cs index b49c1c22..372e9778 100644 --- a/src/WInterop.DirectX/DirectWrite/InformationalStringId.cs +++ b/src/WInterop.DirectX/DirectWrite/InformationalStringId.cs @@ -11,116 +11,116 @@ public enum InformationalStringId : uint /// /// Unspecified name ID. /// - None, + None = DWRITE_INFORMATIONAL_STRING_ID.DWRITE_INFORMATIONAL_STRING_NONE, /// /// Copyright notice provided by the font. /// - CopyrightNotice, + CopyrightNotice = DWRITE_INFORMATIONAL_STRING_ID.DWRITE_INFORMATIONAL_STRING_COPYRIGHT_NOTICE, /// /// String containing a version number. /// - VersionStrings, + VersionStrings = DWRITE_INFORMATIONAL_STRING_ID.DWRITE_INFORMATIONAL_STRING_VERSION_STRINGS, /// /// Trademark information provided by the font. /// - Trademark, + Trademark = DWRITE_INFORMATIONAL_STRING_ID.DWRITE_INFORMATIONAL_STRING_TRADEMARK, /// /// Name of the font manufacturer. /// - Manufacturer, + Manufacturer = DWRITE_INFORMATIONAL_STRING_ID.DWRITE_INFORMATIONAL_STRING_MANUFACTURER, /// /// Name of the font designer. /// - Designer, + Designer = DWRITE_INFORMATIONAL_STRING_ID.DWRITE_INFORMATIONAL_STRING_DESIGNER, /// /// URL of font designer (with protocol, e.g., http://, ftp://). /// - DesignerUrl, + DesignerUrl = DWRITE_INFORMATIONAL_STRING_ID.DWRITE_INFORMATIONAL_STRING_DESIGNER_URL, /// /// Description of the font. Can contain revision information, usage recommendations, history, features, etc. /// - Description, + Description = DWRITE_INFORMATIONAL_STRING_ID.DWRITE_INFORMATIONAL_STRING_DESCRIPTION, /// /// URL of font vendor (with protocol, e.g., http://, ftp://). If a unique serial number is embedded in the URL, it can be used to register the font. /// - VendorUrl, + VendorUrl = DWRITE_INFORMATIONAL_STRING_ID.DWRITE_INFORMATIONAL_STRING_FONT_VENDOR_URL, /// /// Description of how the font may be legally used, or different example scenarios for licensed use. This field should be written in plain language, not legalese. /// - LicenseDescription, + LicenseDescription = DWRITE_INFORMATIONAL_STRING_ID.DWRITE_INFORMATIONAL_STRING_LICENSE_DESCRIPTION, /// /// URL where additional licensing information can be found. /// - LicenseInfoUrl, + LicenseInfoUrl = DWRITE_INFORMATIONAL_STRING_ID.DWRITE_INFORMATIONAL_STRING_LICENSE_INFO_URL, /// /// GDI-compatible family name. Because GDI allows a maximum of four fonts per family, fonts in the same family may have different GDI-compatible family names /// (e.g., "Arial", "Arial Narrow", "Arial Black"). /// - Win32FamilyNames, + Win32FamilyNames = DWRITE_INFORMATIONAL_STRING_ID.DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, /// /// GDI-compatible subfamily name. /// - Win32SubfamilyName, + Win32SubfamilyNames = DWRITE_INFORMATIONAL_STRING_ID.DWRITE_INFORMATIONAL_STRING_WIN32_SUBFAMILY_NAMES, /// /// Typographic family name preferred by the designer. This enables font designers to group more than four fonts in a single family without losing compatibility with /// GDI. This name is typically only present if it differs from the GDI-compatible family name. /// - TypographicFamilyNames, + TypographicFamilyNames = DWRITE_INFORMATIONAL_STRING_ID.DWRITE_INFORMATIONAL_STRING_TYPOGRAPHIC_FAMILY_NAMES, /// /// Typographic subfamily name preferred by the designer. This name is typically only present if it differs from the GDI-compatible subfamily name. /// - TypographicSubfamilyNames, + TypographicSubfamilyNames = DWRITE_INFORMATIONAL_STRING_ID.DWRITE_INFORMATIONAL_STRING_TYPOGRAPHIC_SUBFAMILY_NAMES, /// /// Sample text. This can be the font name or any other text that the designer thinks is the best example to display the font in. /// - SampleText, + SampleText = DWRITE_INFORMATIONAL_STRING_ID.DWRITE_INFORMATIONAL_STRING_SAMPLE_TEXT, /// /// The full name of the font, e.g. "Arial Bold", from name id 4 in the name table. /// - FullName, + FullName = DWRITE_INFORMATIONAL_STRING_ID.DWRITE_INFORMATIONAL_STRING_FULL_NAME, /// /// The postscript name of the font, e.g. "GillSans-Bold" from name id 6 in the name table. /// - PostscriptName, + PostscriptName = DWRITE_INFORMATIONAL_STRING_ID.DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_NAME, /// /// The postscript CID findfont name, from name id 20 in the name table. /// - PostscriptCidName, + PostscriptCidName = DWRITE_INFORMATIONAL_STRING_ID.DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME, /// /// Family name for the weight-stretch-style model. /// - WeightStretchStyleFamilyName, + WeightStretchStyleFamilyName = DWRITE_INFORMATIONAL_STRING_ID.DWRITE_INFORMATIONAL_STRING_WEIGHT_STRETCH_STYLE_FAMILY_NAME, /// /// Script/language tag to identify the scripts or languages that the font was /// primarily designed to support. See DWRITE_FONT_PROPERTY_ID_DESIGN_SCRIPT_LANGUAGE_TAG /// for a longer description. /// - DesignScriptLanguageTag, + DesignScriptLanguageTag = DWRITE_INFORMATIONAL_STRING_ID.DWRITE_INFORMATIONAL_STRING_DESIGN_SCRIPT_LANGUAGE_TAG, /// /// Script/language tag to identify the scripts or languages that the font declares /// it is able to support. /// - SupportedScriptLanguageTag + SupportedScriptLanguageTag = DWRITE_INFORMATIONAL_STRING_ID.DWRITE_INFORMATIONAL_STRING_SUPPORTED_SCRIPT_LANGUAGE_TAG } } diff --git a/src/WInterop.DirectX/DirectWrite/InlineObject.cs b/src/WInterop.DirectX/DirectWrite/InlineObject.cs new file mode 100644 index 00000000..f0cd2a75 --- /dev/null +++ b/src/WInterop.DirectX/DirectWrite/InlineObject.cs @@ -0,0 +1,115 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Drawing; +using System.Runtime.InteropServices; +using TerraFX.Interop.Windows; +using WInterop.Direct2d; + +namespace WInterop.DirectWrite +{ + [Guid(InterfaceIds.IID_IDWriteInlineObject)] + public readonly unsafe struct InlineObject : InlineObject.Interface, IDisposable + { + internal IDWriteInlineObject* Handle { get; } + + internal InlineObject(IDWriteInlineObject* handle) => Handle = handle; + + public void Dispose() => Handle->Release(); + + public void Draw( + IntPtr clientDrawingContext, + TextRenderer renderer, + PointF origin, + bool isSideways, + bool isRightToLeft, + IntPtr clientDrawingEffect) + { + Handle->Draw( + (void*)clientDrawingContext, + renderer.Handle, + origin.X, + origin.Y, + isSideways, + isRightToLeft, + (IUnknown*)(void*)clientDrawingEffect).ThrowIfFailed(); + } + + public void GetBreakConditions(out BreakCondition breakConditionBefore, out BreakCondition breakConditionAfter) + { + BreakCondition before; + BreakCondition after; + Handle->GetBreakConditions((DWRITE_BREAK_CONDITION*)&before, (DWRITE_BREAK_CONDITION*)&after); + breakConditionBefore = before; + breakConditionAfter = after; + } + + public InlineObjectMetrics GetMetrics() + { + InlineObjectMetrics metrics; + Handle->GetMetrics((DWRITE_INLINE_OBJECT_METRICS*)&metrics); + return metrics; + } + + public OverhangMetrics GetOverhangMetrics() + { + OverhangMetrics metrics; + Handle->GetOverhangMetrics((DWRITE_OVERHANG_METRICS*)&metrics); + return metrics; + } + + internal interface Interface + { + /// + /// The application implemented rendering callback (IDWriteTextRenderer::DrawInlineObject) + /// can use this to draw the inline object without needing to cast or query the object + /// type. The text layout does not call this method directly. + /// + /// The context passed to IDWriteTextLayout::Draw. + /// The renderer passed to IDWriteTextLayout::Draw as the object's containing parent. + /// Top-left corner of the inline object. + /// The object should be drawn on its side. + /// The object is in an right-to-left context and should be drawn flipped. + /// The drawing effect set in IDWriteTextLayout::SetDrawingEffect. + void Draw( + IntPtr clientDrawingContext, + TextRenderer renderer, + PointF origin, + bool isSideways, + bool isRightToLeft, + IntPtr clientDrawingEffect); + + /// + /// TextLayout calls this callback function to get the measurement of the inline object. + /// + InlineObjectMetrics GetMetrics(); + + /// + /// TextLayout calls this callback function to get the visible extents (in DIPs) of the inline object. + /// In the case of a simple bitmap, with no padding and no overhang, all the overhangs will simply be zeroes. + /// + /// Overshoot of visible extents (in DIPs) outside the object. + /// + /// The overhangs should be returned relative to the reported size of the object (DWRITE_INLINE_OBJECT_METRICS + /// ::width/height), and should not be baseline adjusted. If you have an image that is actually 100x100 DIPs, + /// but you want it slightly inset (perhaps it has a glow) by 20 DIPs on each side, you would return a + /// width/height of 60x60 and four overhangs of 20 DIPs. + /// + OverhangMetrics GetOverhangMetrics(); + + /// + /// Layout uses this to determine the line breaking behavior of the inline object amidst the text. + /// + /// + /// Line-breaking condition between the object and the content immediately preceding it. + /// + /// + /// Line-breaking condition between the object and the content immediately following it. + /// + void GetBreakConditions( + out BreakCondition breakConditionBefore, + out BreakCondition breakConditionAfter); + } + } +} diff --git a/src/WInterop.DirectX/DirectWrite/LineSpacingMethod.cs b/src/WInterop.DirectX/DirectWrite/LineSpacingMethod.cs index 25733b10..e5a9e366 100644 --- a/src/WInterop.DirectX/DirectWrite/LineSpacingMethod.cs +++ b/src/WInterop.DirectX/DirectWrite/LineSpacingMethod.cs @@ -11,17 +11,17 @@ public enum LineSpacingMethod : uint /// /// Line spacing depends solely on the content, growing to accommodate the size of fonts and inline objects. /// - Default, + Default = DWRITE_LINE_SPACING_METHOD.DWRITE_LINE_SPACING_METHOD_DEFAULT, /// /// Lines are explicitly set to uniform spacing, regardless of contained font sizes. /// This can be useful to avoid the uneven appearance that can occur from font fallback. /// - Uniform, + Uniform = DWRITE_LINE_SPACING_METHOD.DWRITE_LINE_SPACING_METHOD_UNIFORM, /// /// Line spacing and baseline distances are proportional to the computed values based on the content, the size of the fonts and inline objects. /// - Proportional + Proportional = DWRITE_LINE_SPACING_METHOD.DWRITE_LINE_SPACING_METHOD_PROPORTIONAL } } diff --git a/src/WInterop.DirectX/DirectWrite/LocalizedStrings.cs b/src/WInterop.DirectX/DirectWrite/LocalizedStrings.cs new file mode 100644 index 00000000..db09d325 --- /dev/null +++ b/src/WInterop.DirectX/DirectWrite/LocalizedStrings.cs @@ -0,0 +1,100 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Runtime.InteropServices; +using WInterop.Direct2d; + +namespace WInterop.DirectWrite +{ + /// + /// Represents a collection of strings indexed by locale name. [IDWriteLocalizedStrings] + /// + [Guid(InterfaceIds.IID_IDWriteLocalizedStrings)] + public unsafe readonly struct LocalizedStrings : LocalizedStrings.Interface, IDisposable + { + private readonly IDWriteLocalizedStrings* _handle; + + internal LocalizedStrings(IDWriteLocalizedStrings* handle) => _handle = handle; + + public uint Count => throw new NotImplementedException(); + + public void Dispose() + { + if (_handle is not null) + { + _handle->Release(); + } + } + + public bool FindLocaleName(string localeName, out uint index) + { + TerraFX.Interop.Windows.BOOL exists; + fixed (void* l = localeName) + fixed (uint* i = &index) + { + _handle->FindLocaleName((ushort*)l, i, &exists).ThrowIfFailed(); + } + + return exists; + } + + public string GetLocaleName(uint index) + { + uint length; + _handle->GetLocaleNameLength(index, &length).ThrowIfFailed(); + Span name = stackalloc char[(int)length + 1]; + fixed (void* n = name) + { + _handle->GetLocaleName(index, (ushort*)n, length + 1); + } + + return name[..(int)length].ToString(); + } + + public string GetString(uint index) + { + uint length; + _handle->GetStringLength(index, &length).ThrowIfFailed(); + Span name = stackalloc char[(int)length + 1]; + fixed (void* n = name) + { + _handle->GetString(index, (ushort*)n, length + 1); + } + + return name[..(int)length].ToString(); + } + + internal interface Interface + { + /// + /// Gets the number of language/string pairs. + /// + uint Count { get; } + + /// + /// Gets the index of the item with the specified locale name. + /// + /// Locale name to look for. + /// Receives the zero-based index of the locale name/string pair. + /// if the locale name exists or if not. + bool FindLocaleName( + string localeName, + out uint index); + + /// + /// Gets the locale name with the specified index. + /// + /// Zero-based index of the locale name. + string GetLocaleName( + uint index); + + /// + /// Gets the string with the specified index. + /// + /// Zero-based index of the string. + string GetString( + uint index); + } + } +} diff --git a/src/WInterop.DirectX/DirectWrite/ManagedTextRenderer.cs b/src/WInterop.DirectX/DirectWrite/ManagedTextRenderer.cs new file mode 100644 index 00000000..f551ca9c --- /dev/null +++ b/src/WInterop.DirectX/DirectWrite/ManagedTextRenderer.cs @@ -0,0 +1,246 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Drawing; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using TerraFX.Interop.Windows; +using WInterop.Com.Native; + +namespace WInterop.DirectWrite +{ + public unsafe abstract class ManagedTextRenderer : IDisposable + { + private readonly IDWriteTextRenderer* _ccw; + private bool _disposedValue; + + public ManagedTextRenderer() + { + _ccw = CCW.CreateInstance(this); + } + + public virtual bool IsPixelSnappingDisabled(IntPtr clientDrawingContext) => false; + + public virtual Matrix3x2 GetCurrentTransform(IntPtr clientDrawingContext) => Matrix3x2.Identity; + + public virtual float GetPixelsPerDip(IntPtr clientDrawingContext) => 1.0f; + + + public virtual void DrawGlyphRun( + IntPtr clientDrawingContext, + PointF baselineOrigin, + MeasuringMode measuringMode, + GlyphRun glyphRun, + GlyphRunDescription glyphRunDescription, + IntPtr clientDrawingEffect) + { + } + + public virtual void DrawUnderline( + IntPtr clientDrawingContext, + PointF baselineOrigin, + Underline underline, + IntPtr clientDrawingEffect) + { + } + + public virtual void DrawStrikethrough( + IntPtr clientDrawingContext, + PointF baselineOrigin, + Strikethrough strikethrough, + IntPtr clientDrawingEffect) + { + } + + public virtual void DrawInlineObject( + IntPtr clientDrawingContext, + PointF origin, + InlineObject inlineObject, + bool isSideways, + bool isRightToLeft, + IntPtr clientDrawingEffect) + { + } + + public static implicit operator TextRenderer(ManagedTextRenderer renderer) => new(renderer._ccw); + + private unsafe static class CCW + { + private static readonly IDWriteTextRenderer.Vtbl* s_vtable = AllocateVTable(); + + private static IDWriteTextRenderer.Vtbl* AllocateVTable() + { + // Allocate and create a singular VTable for this type projection. + var vtable = (IDWriteTextRenderer.Vtbl*)RuntimeHelpers.AllocateTypeAssociatedMemory(typeof(CCW), sizeof(IDWriteTextRenderer.Vtbl)); + + // IUnknown + vtable->QueryInterface = &QueryInterface; + vtable->AddRef = &AddRef; + vtable->Release = &Release; + vtable->GetPixelsPerDip = &GetPixelsPerDip; + vtable->GetCurrentTransform = &GetCurrentTransform; + vtable->IsPixelSnappingDisabled = &IsPixelSnappingDisabled; + vtable->DrawGlyphRun = &DrawGlyphRun; + vtable->DrawInlineObject = &DrawInlineObject; + vtable->DrawStrikethrough = &DrawStrikethrough; + vtable->DrawUnderline = &DrawUnderline; + return vtable; + } + + public static IDWriteTextRenderer* CreateInstance(ManagedTextRenderer renderer) + => (IDWriteTextRenderer*)Lifetime.Allocate(renderer, s_vtable); + + [UnmanagedCallersOnly] + private static int QueryInterface(void* @this, Guid* iid, void* ppObject) + { + if (*iid == Com.Native.IUnknown.IID_IUnknown + || *iid == typeof(PixelSnapping).GUID + || *iid == typeof(TextRenderer).GUID) + { + ppObject = @this; + } + else + { + ppObject = null; + return (int)Errors.HResult.E_NOINTERFACE; + } + + Lifetime.AddRef(@this); + return (int)Errors.HResult.S_OK; + } + + [UnmanagedCallersOnly] + private static uint AddRef(void* @this) => Lifetime.AddRef(@this); + + [UnmanagedCallersOnly] + private static uint Release(void* @this) => Lifetime.Release(@this); + + [UnmanagedCallersOnly] + private static int IsPixelSnappingDisabled(void* @this, void* clientDrawingContext, TerraFX.Interop.Windows.BOOL* isDisabled) + { + *isDisabled = Lifetime.GetObject(@this) + .IsPixelSnappingDisabled((IntPtr)clientDrawingContext); + return (int)Errors.HResult.S_OK; + } + + [UnmanagedCallersOnly] + private static int GetCurrentTransform(void* @this, void* clientDrawingContext, DWRITE_MATRIX* transform) + { + Matrix3x2 matrix = Lifetime.GetObject(@this) + .GetCurrentTransform((IntPtr)clientDrawingContext); + *transform = *(DWRITE_MATRIX*)&matrix; + return (int)Errors.HResult.S_OK; + } + + [UnmanagedCallersOnly] + private static unsafe int GetPixelsPerDip(void* @this, void* clientDrawingContext, float* pixelsPerDip) + { + *pixelsPerDip = Lifetime.GetObject(@this) + .GetPixelsPerDip((IntPtr)clientDrawingContext); + return (int)Errors.HResult.S_OK; + } + + [UnmanagedCallersOnly] + private static unsafe int DrawGlyphRun( + void* @this, + void* clientDrawingContext, + float baselineOriginX, + float baselineOriginY, + DWRITE_MEASURING_MODE measuringMode, + DWRITE_GLYPH_RUN* glyphRun, + DWRITE_GLYPH_RUN_DESCRIPTION* glyphRunDescription, + TerraFX.Interop.Windows.IUnknown* clientDrawingEffect) + { + Lifetime.GetObject(@this).DrawGlyphRun( + (IntPtr)clientDrawingContext, + new(baselineOriginX, baselineOriginY), + (MeasuringMode)measuringMode, + *(GlyphRun*)glyphRun, + *(GlyphRunDescription*)glyphRunDescription, + (IntPtr)clientDrawingEffect); + + return (int)Errors.HResult.S_OK; + } + + [UnmanagedCallersOnly] + private static unsafe int DrawUnderline( + void* @this, + void* clientDrawingContext, + float baselineOriginX, + float baselineOriginY, + DWRITE_UNDERLINE* underline, + TerraFX.Interop.Windows.IUnknown* clientDrawingEffect) + { + Lifetime.GetObject(@this).DrawUnderline( + (IntPtr)clientDrawingContext, + new(baselineOriginX, baselineOriginY), + *(Underline*)underline, + (IntPtr)clientDrawingEffect); + + return (int)Errors.HResult.S_OK; + } + + [UnmanagedCallersOnly] + private static unsafe int DrawStrikethrough( + void* @this, + void* clientDrawingContext, + float baselineOriginX, + float baselineOriginY, + DWRITE_STRIKETHROUGH* strikethrough, + TerraFX.Interop.Windows.IUnknown* clientDrawingEffect) + { + Lifetime.GetObject(@this).DrawStrikethrough( + (IntPtr)clientDrawingContext, + new(baselineOriginX, baselineOriginY), + *(Strikethrough*)strikethrough, + (IntPtr)clientDrawingEffect); + + return (int)Errors.HResult.S_OK; + } + + [UnmanagedCallersOnly] + private static unsafe int DrawInlineObject( + void* @this, + void* clientDrawingContext, + float originX, + float originY, + IDWriteInlineObject* inlineObject, + TerraFX.Interop.Windows.BOOL isSideways, + TerraFX.Interop.Windows.BOOL isRightToLeft, + TerraFX.Interop.Windows.IUnknown* clientDrawingEffect) + { + Lifetime.GetObject(@this).DrawInlineObject( + (IntPtr)clientDrawingContext, + new(originX, originY), + new(inlineObject), + isSideways, + isRightToLeft, + (IntPtr)clientDrawingEffect); + + return (int)Errors.HResult.S_OK; + } + } + + protected virtual void Dispose(bool disposing) + { + if (!_disposedValue) + { + _ccw->Release(); + _disposedValue = true; + } + } + + ~ManagedTextRenderer() + { + Dispose(disposing: false); + } + + public void Dispose() + { + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + } +} diff --git a/src/WInterop.DirectX/DirectWrite/Native/Imports.cs b/src/WInterop.DirectX/DirectWrite/Native/Imports.cs index a43d5f16..e5081f7c 100644 --- a/src/WInterop.DirectX/DirectWrite/Native/Imports.cs +++ b/src/WInterop.DirectX/DirectWrite/Native/Imports.cs @@ -17,6 +17,6 @@ public static partial class Imports public static extern HResult DWriteCreateFactory( FactoryType factoryType, in Guid riid, - out IFactory ppIFactory); + out WriteFactory ppIFactory); } } diff --git a/src/WInterop.DirectX/DirectWrite/ParagraphAlignment.cs b/src/WInterop.DirectX/DirectWrite/ParagraphAlignment.cs index 4e5fe197..62780a95 100644 --- a/src/WInterop.DirectX/DirectWrite/ParagraphAlignment.cs +++ b/src/WInterop.DirectX/DirectWrite/ParagraphAlignment.cs @@ -12,16 +12,16 @@ public enum ParagraphAlignment : uint /// /// The first line of paragraph is aligned to the flow's beginning edge of the layout box. /// - Near, + Near = DWRITE_PARAGRAPH_ALIGNMENT.DWRITE_PARAGRAPH_ALIGNMENT_NEAR, /// /// The last line of paragraph is aligned to the flow's ending edge of the layout box. /// - Far, + Far = DWRITE_PARAGRAPH_ALIGNMENT.DWRITE_PARAGRAPH_ALIGNMENT_FAR, /// /// The center of the paragraph is aligned to the center of the flow of the layout box. /// - Center + Center = DWRITE_PARAGRAPH_ALIGNMENT.DWRITE_PARAGRAPH_ALIGNMENT_CENTER } } diff --git a/src/WInterop.DirectX/DirectWrite/PixelGeometry.cs b/src/WInterop.DirectX/DirectWrite/PixelGeometry.cs index b4c33760..77bd161e 100644 --- a/src/WInterop.DirectX/DirectWrite/PixelGeometry.cs +++ b/src/WInterop.DirectX/DirectWrite/PixelGeometry.cs @@ -14,19 +14,19 @@ public enum PixelGeometry /// The red, green, and blue color components of each pixel are assumed to occupy the same point. /// [DWRITE_PIXEL_GEOMETRY_FLAT] /// - Flat, + Flat = DWRITE_PIXEL_GEOMETRY.DWRITE_PIXEL_GEOMETRY_FLAT, /// /// Each pixel comprises three vertical stripes, with red on the left, green in the center, and /// blue on the right. This is the most common pixel geometry for LCD monitors. /// [DWRITE_PIXEL_GEOMETRY_RGB] /// - Rgb, + Rgb = DWRITE_PIXEL_GEOMETRY.DWRITE_PIXEL_GEOMETRY_RGB, /// /// Each pixel comprises three vertical stripes, with blue on the left, green in the center, and /// red on the right. [DWRITE_PIXEL_GEOMETRY_BGR] /// - Bgr + Bgr = DWRITE_PIXEL_GEOMETRY.DWRITE_PIXEL_GEOMETRY_BGR }; } diff --git a/src/WInterop.DirectX/DirectWrite/PixelSnapping.cs b/src/WInterop.DirectX/DirectWrite/PixelSnapping.cs new file mode 100644 index 00000000..dd83cc18 --- /dev/null +++ b/src/WInterop.DirectX/DirectWrite/PixelSnapping.cs @@ -0,0 +1,74 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace WInterop.DirectWrite +{ + /// + /// The interface defines the pixel snapping properties of a text renderer. + /// [IDWritePixelSnapping] + /// + [Guid(InterfaceIds.IID_IDWritePixelSnapping)] + public unsafe readonly struct PixelSnapping : PixelSnapping.Interface, IDisposable + { + private readonly IDWritePixelSnapping* _handle; + + internal PixelSnapping(IDWritePixelSnapping* handle) => _handle = handle; + + public Matrix3x2 GetCurrentTransform(IntPtr clientDrawingContext) + { + Matrix3x2 matrix; + _handle->GetCurrentTransform((void*)clientDrawingContext, (DWRITE_MATRIX*)&matrix).ThrowIfFailed(); + return matrix; + } + + public float GetPixelsPerDip(IntPtr clientDrawingContext) + { + float pixels; + _handle->GetPixelsPerDip((void*)clientDrawingContext, &pixels).ThrowIfFailed(); + return pixels; + } + + public bool IsPixelSnappingDisabled(IntPtr clientDrawingContext) + { + TerraFX.Interop.Windows.BOOL result; + _handle->IsPixelSnappingDisabled((void*)clientDrawingContext, &result).ThrowIfFailed(); + return result; + } + + internal static ref PixelSnapping From(in TFrom from) + where TFrom : unmanaged, Interface + => ref Unsafe.AsRef(Unsafe.AsPointer(ref Unsafe.AsRef(from))); + + public void Dispose() => _handle->Release(); + + internal interface Interface + { + /// + /// Determines whether pixel snapping is disabled. The recommended default is FALSE, + /// unless doing animation that requires subpixel vertical placement. + /// + /// The context passed to IDWriteTextLayout::Draw. + bool IsPixelSnappingDisabled(IntPtr clientDrawingContext); + + /// + /// Gets the current transform that maps abstract coordinates to DIPs, + /// which may disable pixel snapping upon any rotation or shear. + /// + /// The context passed to IDWriteTextLayout::Draw. + Matrix3x2 GetCurrentTransform(IntPtr clientDrawingContext); + + /// + /// Gets the number of physical pixels per DIP. A DIP (device-independent pixel) is 1/96 inch, + /// so the pixelsPerDip value is the number of logical pixels per inch divided by 96 (yielding + /// a value of 1 for 96 DPI and 1.25 for 120). + /// + /// The context passed to IDWriteTextLayout::Draw. + float GetPixelsPerDip(IntPtr clientDrawingContext); + } + } +} diff --git a/src/WInterop.DirectX/DirectWrite/RenderingMode.cs b/src/WInterop.DirectX/DirectWrite/RenderingMode.cs index 98627f8e..f45b9a54 100644 --- a/src/WInterop.DirectX/DirectWrite/RenderingMode.cs +++ b/src/WInterop.DirectX/DirectWrite/RenderingMode.cs @@ -12,13 +12,13 @@ public enum RenderingMode /// Specifies that the rendering mode is determined automatically based on the font and size. /// [DWRITE_RENDERING_MODE_DEFAULT] /// - Default, + Default = DWRITE_RENDERING_MODE.DWRITE_RENDERING_MODE_DEFAULT, /// /// Specifies that no antialiasing is performed. Each pixel is either set to the foreground /// color of the text or retains the color of the background. [DWRITE_RENDERING_MODE_ALIASED] /// - Aliased, + Aliased = DWRITE_RENDERING_MODE.DWRITE_RENDERING_MODE_ALIASED, /// /// Specifies that antialiasing is performed in the horizontal direction and the appearance @@ -26,7 +26,7 @@ public enum RenderingMode /// to get glyph advances. The antialiasing may be either ClearType or grayscale depending on /// the text antialiasing mode. [DWRITE_RENDERING_MODE_GDI_CLASSIC] /// - GdiClassic, + GdiClassic = DWRITE_RENDERING_MODE.DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC, /// /// Specifies that antialiasing is performed in the horizontal direction and the appearance @@ -35,7 +35,7 @@ public enum RenderingMode /// DWRITE_MEASURING_MODE_GDI_NATURAL to get glyph advances. The antialiasing may be either /// ClearType or grayscale depending on the text antialiasing mode. [DWRITE_RENDERING_MODE_GDI_NATURAL] /// - GdiNatural, + GdiNatural = DWRITE_RENDERING_MODE.DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL, /// /// Specifies that antialiasing is performed in the horizontal direction. This rendering @@ -43,7 +43,7 @@ public enum RenderingMode /// for natural (i.e., resolution-independent) layout. The antialiasing may be either /// ClearType or grayscale depending on the text antialiasing mode. [DWRITE_RENDERING_MODE_NATURAL] /// - Natural, + Natural = DWRITE_RENDERING_MODE.DWRITE_RENDERING_MODE_NATURAL, /// /// Similar to natural mode except that antialiasing is performed in both the horizontal @@ -51,12 +51,12 @@ public enum RenderingMode /// diagonal lines look smoother. The antialiasing may be either ClearType or grayscale /// depending on the text antialiasing mode. [DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC] /// - NaturalSymmetric, + NaturalSymmetric = DWRITE_RENDERING_MODE.DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC, /// /// Specifies that rendering should bypass the rasterizer and use the outlines directly. /// This is typically used at very large sizes. [DWRITE_RENDERING_MODE_OUTLINE] /// - Outline, + Outline = DWRITE_RENDERING_MODE.DWRITE_RENDERING_MODE_OUTLINE, }; } diff --git a/src/WInterop.DirectX/DirectWrite/RenderingParams.cs b/src/WInterop.DirectX/DirectWrite/RenderingParams.cs new file mode 100644 index 00000000..2ea388fe --- /dev/null +++ b/src/WInterop.DirectX/DirectWrite/RenderingParams.cs @@ -0,0 +1,63 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Runtime.InteropServices; + +namespace WInterop.DirectWrite +{ + /// + /// The interface that represents text rendering settings for glyph rasterization and filtering. + /// [IDWriteRenderingParams] + /// + [Guid(InterfaceIds.IID_IDWriteRenderingParams)] + public unsafe readonly struct RenderingParams : RenderingParams.Interface, IDisposable + { + internal IDWriteRenderingParams* Handle { get; } + + internal RenderingParams(IDWriteRenderingParams* handle) => Handle = handle; + + public float Gamma => Handle->GetGamma(); + + public float EnhancedContrast => Handle->GetEnhancedContrast(); + + public float ClearTypeLevel => Handle->GetClearTypeLevel(); + + public PixelGeometry PixelGeometry => (PixelGeometry)Handle->GetPixelGeometry(); + + public RenderingMode RenderingMode => (RenderingMode)Handle->GetRenderingMode(); + + public void Dispose() => Handle->Release(); + + internal interface Interface + { + /// + /// Gets the gamma value used for gamma correction. Valid values must be + /// greater than zero and cannot exceed 256. + /// + float Gamma { get; } + + /// + /// Gets the amount of contrast enhancement. Valid values are greater than + /// or equal to zero. + /// + float EnhancedContrast { get; } + + /// + /// Gets the ClearType level. Valid values range from 0.0f (no ClearType) + /// to 1.0f (full ClearType). + /// + float ClearTypeLevel { get; } + + /// + /// Gets the pixel geometry. + /// + PixelGeometry PixelGeometry { get; } + + /// + /// Gets the rendering mode. + /// + RenderingMode RenderingMode { get; } + } + } +} diff --git a/src/WInterop.DirectX/DirectWrite/TextAlignment.cs b/src/WInterop.DirectX/DirectWrite/TextAlignment.cs index 1bfd54cf..477ce5d6 100644 --- a/src/WInterop.DirectX/DirectWrite/TextAlignment.cs +++ b/src/WInterop.DirectX/DirectWrite/TextAlignment.cs @@ -12,21 +12,21 @@ public enum TextAlignment : uint /// /// The leading edge of the paragraph text is aligned to the layout box's leading edge. /// - Leading, + Leading = DWRITE_TEXT_ALIGNMENT.DWRITE_TEXT_ALIGNMENT_LEADING, /// /// The trailing edge of the paragraph text is aligned to the layout box's trailing edge. /// - Trailing, + Trailing = DWRITE_TEXT_ALIGNMENT.DWRITE_TEXT_ALIGNMENT_TRAILING, /// /// The center of the paragraph text is aligned to the center of the layout box. /// - Center, + Center = DWRITE_TEXT_ALIGNMENT.DWRITE_TEXT_ALIGNMENT_CENTER, /// /// Align text to the leading side, and also justify text to fill the lines. /// - Justified + Justified = DWRITE_TEXT_ALIGNMENT.DWRITE_TEXT_ALIGNMENT_JUSTIFIED } } diff --git a/src/WInterop.DirectX/DirectWrite/TextFormat.cs b/src/WInterop.DirectX/DirectWrite/TextFormat.cs new file mode 100644 index 00000000..f5cd0502 --- /dev/null +++ b/src/WInterop.DirectX/DirectWrite/TextFormat.cs @@ -0,0 +1,238 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace WInterop.DirectWrite +{ + /// + /// The format of text used for text layout. [IDWriteTextFormat] + /// + /// + /// This object may not be thread-safe and it may carry the state of text format change. + /// + [Guid(InterfaceIds.IID_IDWriteTextFormat)] + public readonly unsafe struct TextFormat : TextFormat.Interface, IDisposable + { + internal IDWriteTextFormat* Handle { get; } + + internal TextFormat(IDWriteTextFormat* handle) => Handle = handle; + + internal static ref TextFormat From(in TFrom from) + where TFrom : unmanaged, Interface + => ref Unsafe.AsRef(Unsafe.AsPointer(ref Unsafe.AsRef(from))); + + public TextAlignment TextAlignment + { + get => (TextAlignment)Handle->GetTextAlignment(); + set => Handle->SetTextAlignment((DWRITE_TEXT_ALIGNMENT)value).ThrowIfFailed(); + } + + public ParagraphAlignment ParagraphAlignment + { + get => (ParagraphAlignment)Handle->GetParagraphAlignment(); + set => Handle->SetParagraphAlignment((DWRITE_PARAGRAPH_ALIGNMENT)value).ThrowIfFailed(); + } + + public WordWrapping WordWrapping + { + get => (WordWrapping)Handle->GetWordWrapping(); + set => Handle->SetWordWrapping((DWRITE_WORD_WRAPPING)value).ThrowIfFailed(); + } + + public ReadingDirection ReadingDirection + { + get => (ReadingDirection)Handle->GetReadingDirection(); + set => Handle->SetReadingDirection((DWRITE_READING_DIRECTION)value).ThrowIfFailed(); + } + + public FlowDirection FlowDirection + { + get => (FlowDirection)Handle->GetFlowDirection(); + set => Handle->SetFlowDirection((DWRITE_FLOW_DIRECTION)value).ThrowIfFailed(); + } + + public float IncrementalTabStop + { + get => Handle->GetIncrementalTabStop(); + set => Handle->SetIncrementalTabStop(value).ThrowIfFailed(); + } + + public Trimming Trimming + { + get + { + Trimming trimming; + Handle->GetTrimming((DWRITE_TRIMMING*)&trimming, null).ThrowIfFailed(); + return trimming; + } + set => Handle->SetTrimming((DWRITE_TRIMMING*)&value, null).ThrowIfFailed(); + } + + public FontWeight FontWeight => (FontWeight)Handle->GetFontWeight(); + + public FontStyle FontStyle => (FontStyle)Handle->GetFontStyle(); + + public FontStretch FontStretch => (FontStretch)Handle->GetFontStretch(); + + public float FontSize => Handle->GetFontSize(); + + public void Dispose() => Handle->Release(); + + public FontCollection GetFontCollection() + { + IDWriteFontCollection* collection; + Handle->GetFontCollection(&collection).ThrowIfFailed(); + return new(collection); + } + + public string GetFontFamilyName() + { + uint length = Handle->GetFontFamilyNameLength(); + Span name = stackalloc char[(int)length + 1]; + fixed (void* n = name) + { + Handle->GetFontFamilyName((ushort*)n, length + 1).ThrowIfFailed(); + } + return name[..(int)length].ToString(); + } + + public void GetLineSpacing(out LineSpacingMethod lineSpacingMethod, out float lineSpacing, out float baseline) + { + fixed (void* lsm = &lineSpacingMethod) + fixed (float* ls = &lineSpacing) + fixed (float* bl = &baseline) + { + Handle->GetLineSpacing((DWRITE_LINE_SPACING_METHOD*)lsm, ls, bl).ThrowIfFailed(); + } + } + + public string GetLocaleName() + { + uint length = Handle->GetLocaleNameLength(); + Span name = stackalloc char[(int)length + 1]; + fixed (void* n = name) + { + Handle->GetLocaleName((ushort*)n, length + 1).ThrowIfFailed(); + } + return name[..(int)length].ToString(); + } + + public void SetLineSpacing(LineSpacingMethod lineSpacingMethod, float lineSpacing, float baseline) + => Handle->SetLineSpacing((DWRITE_LINE_SPACING_METHOD)lineSpacingMethod, lineSpacing, baseline).ThrowIfFailed(); + + /// + /// https://docs.microsoft.com/windows/win32/api/dwrite/nn-dwrite-idwritetextformat + /// + internal interface Interface + { + /// + /// Gets/sets alignment option of text relative to layout box's leading and trailing edge. + /// + TextAlignment TextAlignment { get; set; } + + /// + /// Gets/sets alignment option of paragraphs relative to layout box's top and bottom edge. + /// + ParagraphAlignment ParagraphAlignment { get; set; } + + /// + /// Gets/sets the style of word wrapping. + /// + WordWrapping WordWrapping { get; set; } + + /// + /// Gets/sets paragraph reading direction. + /// + /// + /// must be perpendicular to . + /// + ReadingDirection ReadingDirection { get; set; } + + /// + /// Gets/sets paragraph flow direction. + /// + /// Paragraph flow direction + /// + /// must be perpendicular to . + /// + FlowDirection FlowDirection { get; set; } + + /// + /// Gets/sets incremental tab stop position. + /// + float IncrementalTabStop { get; set; } + + /// + /// Set trimming options for any trailing text exceeding the layout width or for any far text exceeding the + /// layout height. + /// + Trimming Trimming { get; set; } + + // (Trimming options, InlineObject sign) TrimmingWithSign { get; set; } + + /// + /// Set line spacing. + /// + /// How to determine line height. + /// The line height, or rather distance between one baseline to another. + /// Distance from top of line to baseline. A reasonable ratio to lineSpacing is 80%. + /// + /// For the default method, spacing depends solely on the content. For uniform spacing, the given line height + /// will override the content. + /// + void SetLineSpacing( + LineSpacingMethod lineSpacingMethod, + float lineSpacing, + float baseline); + + /// + /// Get line spacing. + /// + /// How line height is determined. + /// The line height, or rather distance between one baseline to another. + /// Distance from top of line to baseline. + void GetLineSpacing( + out LineSpacingMethod lineSpacingMethod, + out float lineSpacing, + out float baseline); + + /// + /// Get the font collection. + /// + FontCollection GetFontCollection(); + + /// + /// Get a copy of the font family name. + /// + string GetFontFamilyName(); + + /// + /// Get the font weight. + /// + FontWeight FontWeight { get; } + + /// + /// Get the font style. + /// + FontStyle FontStyle { get; } + + /// + /// Get the font stretch. + /// + FontStretch FontStretch { get; } + + /// + /// Get the font em height. + /// + float FontSize { get; } + + /// + /// Get the locale name. + /// + string GetLocaleName(); + } + } +} diff --git a/src/WInterop.DirectX/DirectWrite/TextLayout.cs b/src/WInterop.DirectX/DirectWrite/TextLayout.cs new file mode 100644 index 00000000..3885829b --- /dev/null +++ b/src/WInterop.DirectX/DirectWrite/TextLayout.cs @@ -0,0 +1,718 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Drawing; +using System.Runtime.InteropServices; +using TerraFX.Interop.Windows; + +namespace WInterop.DirectWrite +{ + /// + /// The IDWriteTextLayout interface represents a block of text after it has + /// been fully analyzed and formatted. [IDWriteTextLayout] + /// + /// All coordinates are in device independent pixels (DIPs). + /// + [Guid(InterfaceIds.IID_IDWriteTextLayout)] + public readonly unsafe struct TextLayout : TextLayout.Interface, IDisposable + { + internal readonly IDWriteTextLayout* Handle { get; } + + internal TextLayout(IDWriteTextLayout* handle) => Handle = handle; + + public float MaxWidth + { + get => Handle->GetMaxWidth(); + set => Handle->SetMaxWidth(value).ThrowIfFailed(); + } + + public float MaxHeight + { + get => Handle->GetMaxHeight(); + set => Handle->SetMaxHeight(value).ThrowIfFailed(); + } + + public TextAlignment TextAlignment + { + get => TextFormat.From(this).TextAlignment; + set => TextFormat.From(this).TextAlignment = value; + } + + public ParagraphAlignment ParagraphAlignment + { + get => TextFormat.From(this).ParagraphAlignment; + set => TextFormat.From(this).ParagraphAlignment = value; + } + + public WordWrapping WordWrapping + { + get => TextFormat.From(this).WordWrapping; + set => TextFormat.From(this).WordWrapping = value; + } + + public ReadingDirection ReadingDirection + { + get => TextFormat.From(this).ReadingDirection; + set => TextFormat.From(this).ReadingDirection = value; + } + + public FlowDirection FlowDirection + { + get => TextFormat.From(this).FlowDirection; + set => TextFormat.From(this).FlowDirection = value; + } + + public float IncrementalTabStop + { + get => TextFormat.From(this).IncrementalTabStop; + set => TextFormat.From(this).IncrementalTabStop = value; + } + + public Trimming Trimming + { + get => TextFormat.From(this).Trimming; + set => TextFormat.From(this).Trimming = value; + } + + public FontWeight FontWeight => TextFormat.From(this).FontWeight; + + public FontStyle FontStyle => TextFormat.From(this).FontStyle; + + public FontStretch FontStretch => TextFormat.From(this).FontStretch; + + public float FontSize => TextFormat.From(this).FontSize; + + public float DetermineMinWidth() + { + float minWidth; + Handle->DetermineMinWidth(&minWidth).ThrowIfFailed(); + return minWidth; + } + + public void Dispose() => Handle->Release(); + + public void Draw(IntPtr clientDrawingContext, TextRenderer renderer, PointF origin) + { + Handle->Draw( + (void*)clientDrawingContext, + renderer.Handle, + origin.X, + origin.Y).ThrowIfFailed(); + } + + public ClusterMetrics[] GetClusterMetrics() + { + uint count; + var result = Handle->GetClusterMetrics(null, 0, &count); + + if (count == 0) + { + return Array.Empty(); + } + + ClusterMetrics[] metrics = new ClusterMetrics[(int)count]; + fixed (void* m = metrics) + { + Handle->GetClusterMetrics((DWRITE_CLUSTER_METRICS*)m, count, &count).ThrowIfFailed(); + } + return metrics; + } + + public IntPtr GetDrawingEffect(uint currentPosition) + { + IUnknown* effect; + Handle->GetDrawingEffect(currentPosition, &effect).ThrowIfFailed(); + return (IntPtr)effect; + } + + public FontCollection GetFontCollection(uint currentPosition) + { + IDWriteFontCollection* collection; + Handle->GetFontCollection(currentPosition, &collection).ThrowIfFailed(); + return new(collection); + } + + public FontCollection GetFontCollection() => TextFormat.From(this).GetFontCollection(); + + public string GetFontFamilyName(uint currentPosition) + { + uint length; + Handle->GetFontFamilyNameLength(currentPosition, &length).ThrowIfFailed(); + Span name = stackalloc char[(int)length + 1]; + fixed (void* n = name) + { + Handle->GetFontFamilyName(currentPosition, (ushort*)n, length + 1).ThrowIfFailed(); + } + return name[..(int)length].ToString(); + } + + public string GetFontFamilyName() => TextFormat.From(this).GetFontFamilyName(); + + public float GetFontSize(uint currentPosition) + { + float size; + Handle->GetFontSize(currentPosition, &size).ThrowIfFailed(); + return size; + } + + public FontStretch GetFontStretch(uint currentPosition) + { + FontStretch stretch; + Handle->GetFontStretch(currentPosition, (DWRITE_FONT_STRETCH*)&stretch).ThrowIfFailed(); + return stretch; + } + + public FontStyle GetFontStyle(uint currentPosition) + { + FontStyle style; + Handle->GetFontStyle(currentPosition, (DWRITE_FONT_STYLE*)&style).ThrowIfFailed(); + return style; + } + + public FontWeight GetFontWeight(uint currentPosition) + { + FontWeight weight; + Handle->GetFontWeight(currentPosition, (DWRITE_FONT_WEIGHT*)&weight).ThrowIfFailed(); + return weight; + } + + public InlineObject GetInlineObject(uint currentPosition) + { + IDWriteInlineObject* inlineObject; + Handle->GetInlineObject(currentPosition, &inlineObject).ThrowIfFailed(); + return new(inlineObject); + } + + public LineMetrics[] GetLineMetrics() + { + uint count; + var result = Handle->GetLineMetrics(null, 0, &count); + if (count == 0) + { + return Array.Empty(); + } + + LineMetrics[] metrics = new LineMetrics[count]; + fixed (void* m = metrics) + { + Handle->GetLineMetrics((DWRITE_LINE_METRICS*)m, count, &count).ThrowIfFailed(); + } + + return metrics; + } + + public void GetLineSpacing(out LineSpacingMethod lineSpacingMethod, out float lineSpacing, out float baseline) + => TextFormat.From(this).GetLineSpacing(out lineSpacingMethod, out lineSpacing, out baseline); + + public string GetLocaleName(uint currentPosition) + { + uint length; + Handle->GetLocaleNameLength(currentPosition, &length).ThrowIfFailed(); + Span name = stackalloc char[(int)length + 1]; + fixed (void* n = name) + { + Handle->GetLocaleName(currentPosition, (ushort*)n, length + 1).ThrowIfFailed(); + } + return name[..(int)length].ToString(); + } + + public string GetLocaleName() => TextFormat.From(this).GetLocaleName(); + + public TextMetrics GetMetrics() + { + TextMetrics metrics; + Handle->GetMetrics((DWRITE_TEXT_METRICS*)&metrics).ThrowIfFailed(); + return metrics; + } + + public OverhangMetrics GetOverhangMetrics() + { + OverhangMetrics metrics; + Handle->GetOverhangMetrics((DWRITE_OVERHANG_METRICS*)&metrics).ThrowIfFailed(); + return metrics; + } + + public bool GetStrikethrough(uint currentPosition) + { + TerraFX.Interop.Windows.BOOL strikeThrough; + Handle->GetStrikethrough(currentPosition, &strikeThrough).ThrowIfFailed(); + return strikeThrough; + } + + public Typography GetTypography(uint currentPosition) + { + IDWriteTypography* typography; + Handle->GetTypography(currentPosition, &typography).ThrowIfFailed(); + return new(typography); + } + + public bool GetUnderline(uint currentPosition) + { + TerraFX.Interop.Windows.BOOL underline; + Handle->GetUnderline(currentPosition, &underline).ThrowIfFailed(); + return underline; + } + + public void HitTestPoint(PointF point, out bool isTrailingHit, out bool isInside, out HitTestMetrics hitTestMetrics) + { + TerraFX.Interop.Windows.BOOL ith; + TerraFX.Interop.Windows.BOOL ii; + fixed (void* htm = &hitTestMetrics) + { + Handle->HitTestPoint(point.X, point.Y, &ith, &ii, (DWRITE_HIT_TEST_METRICS*)htm).ThrowIfFailed(); + } + + isTrailingHit = ith; + isInside = ii; + } + + public void HitTestTextPosition(uint textPosition, bool isTrailingHit, out PointF point, out HitTestMetrics hitTestMetrics) + { + float x; + float y; + fixed (void* htm = &hitTestMetrics) + { + Handle->HitTestTextPosition(textPosition, isTrailingHit, &x, &y, (DWRITE_HIT_TEST_METRICS*)htm).ThrowIfFailed(); + } + + point = new(x, y); + } + + public void SetDrawingEffect(IntPtr drawingEffect, TextRange textRange) + => Handle->SetDrawingEffect((IUnknown*)(void*)drawingEffect, textRange.ToD2D()).ThrowIfFailed(); + + public void SetFontCollection(FontCollection fontCollection, TextRange textRange) + => Handle->SetFontCollection(fontCollection.Handle, textRange.ToD2D()).ThrowIfFailed(); + + public void SetFontFamilyName(string fontFamilyName, TextRange textRange) + { + fixed (void* n = fontFamilyName) + { + Handle->SetFontFamilyName((ushort*)n, textRange.ToD2D()).ThrowIfFailed(); ; + } + } + + public void SetFontSize(float fontSize, TextRange textRange) + => Handle->SetFontSize(fontSize, textRange.ToD2D()).ThrowIfFailed(); + + public void SetFontStretch(FontStretch fontStretch, TextRange textRange) + => Handle->SetFontStretch((DWRITE_FONT_STRETCH)fontStretch, textRange.ToD2D()).ThrowIfFailed(); + + public void SetFontStyle(FontStyle fontStyle, TextRange textRange) + => Handle->SetFontStyle((DWRITE_FONT_STYLE)fontStyle, textRange.ToD2D()).ThrowIfFailed(); + + public void SetFontWeight(FontWeight fontWeight, TextRange textRange) + => Handle->SetFontWeight((DWRITE_FONT_WEIGHT)fontWeight, textRange.ToD2D()).ThrowIfFailed(); + + public void SetInlineObject(InlineObject inlineObject, TextRange textRange) + => Handle->SetInlineObject(inlineObject.Handle, textRange.ToD2D()).ThrowIfFailed(); + + public void SetLineSpacing(LineSpacingMethod lineSpacingMethod, float lineSpacing, float baseline) + => Handle->SetLineSpacing((DWRITE_LINE_SPACING_METHOD)lineSpacingMethod, lineSpacing, baseline).ThrowIfFailed(); + + public void SetLocaleName(string localeName, TextRange textRange) + { + fixed (void* n = localeName) + { + Handle->SetLocaleName((ushort*)n, textRange.ToD2D()).ThrowIfFailed(); + } + } + + public void SetStrikethrough(bool hasStrikethrough, TextRange textRange) + => Handle->SetStrikethrough(hasStrikethrough, textRange.ToD2D()).ThrowIfFailed(); + + public void SetTypography(Typography typography, TextRange textRange) + => Handle->SetTypography(typography.Handle, textRange.ToD2D()).ThrowIfFailed(); + + public void SetUnderline(bool hasUnderline, TextRange textRange) + => Handle->SetUnderline(hasUnderline, textRange.ToD2D()).ThrowIfFailed(); + + /// + /// https://docs.microsoft.com/windows/win32/api/dwrite/nn-dwrite-idwritetextlayout + /// + internal interface Interface : TextFormat.Interface + { + /// + /// Get/set layout maximum width. + /// + float MaxWidth { get; set; } + + /// + /// Get/set layout maximum height + /// + float MaxHeight { get; set; } + + /// + /// Set the font collection. + /// + /// The font collection to set + /// Text range to which this change applies. + void SetFontCollection( + FontCollection fontCollection, + TextRange textRange); + + /// + /// Set null-terminated font family name. + /// + /// Font family name + /// Text range to which this change applies. + void SetFontFamilyName( + string fontFamilyName, + TextRange textRange); + + /// + /// Set font weight. + /// + /// Font weight + /// Text range to which this change applies. + void SetFontWeight( + FontWeight fontWeight, + TextRange textRange); + + /// + /// Set font style. + /// + /// Font style + /// Text range to which this change applies. + void SetFontStyle( + FontStyle fontStyle, + TextRange textRange); + + /// + /// Set font stretch. + /// + /// font stretch + /// Text range to which this change applies. + void SetFontStretch( + FontStretch fontStretch, + TextRange textRange); + + /// + /// Set font em height. + /// + /// Font em height + /// Text range to which this change applies. + void SetFontSize( + float fontSize, + TextRange textRange); + + /// + /// Set underline. + /// + /// The Boolean flag indicates whether underline takes place + /// Text range to which this change applies. + void SetUnderline( + bool hasUnderline, + TextRange textRange); + + /// + /// Set strikethrough. + /// + /// The Boolean flag indicates whether strikethrough takes place + /// Text range to which this change applies. + void SetStrikethrough( + bool hasStrikethrough, + TextRange textRange); + + /// + /// Set application-defined drawing effect. + /// + /// Pointer to an application-defined drawing effect. + /// Text range to which this change applies. + /// + /// This drawing effect is associated with the specified range and will be passed back + /// to the application via the callback when the range is drawn at drawing time. + /// + void SetDrawingEffect( + IntPtr drawingEffect, + TextRange textRange); + + /// + /// Set inline object. + /// + /// Pointer to an application-implemented inline object. + /// Text range to which this change applies. + /// + /// This inline object applies to the specified range and will be passed back + /// to the application via the DrawInlineObject callback when the range is drawn. + /// Any text in that range will be suppressed. + /// + void SetInlineObject( + InlineObject inlineObject, + TextRange textRange); + + /// + /// Set font typography features. + /// + /// Pointer to font typography setting. + /// Text range to which this change applies. + void SetTypography( + Typography typography, + TextRange textRange); + + /// + /// Set locale name. + /// + /// Locale name + /// Text range to which this change applies. + void SetLocaleName( + string localeName, + TextRange textRange); + + // TODO: Add overloads that out the TextRange for getters. Presumption is + // there is extra overhead in calculating the TextRange. + + /// + /// Get the font collection where the current position is at. + /// + /// The current text position. + FontCollection GetFontCollection(uint currentPosition); + + /// + /// Copy the font family name where the current position is at. + /// + /// The current text position. + string GetFontFamilyName(uint currentPosition); + + /// + /// Get the font weight where the current position is at. + /// + /// The current text position. + FontWeight GetFontWeight(uint currentPosition); + + /// + /// Get the font style where the current position is at. + /// + /// The current text position. + FontStyle GetFontStyle(uint currentPosition); + + /// + /// Get the font stretch where the current position is at. + /// + /// The current text position. + FontStretch GetFontStretch(uint currentPosition); + + /// + /// Get the font em height where the current position is at. + /// + /// The current text position. + float GetFontSize(uint currentPosition); + + /// + /// Get the underline presence where the current position is at. + /// + /// The current text position. + bool GetUnderline(uint currentPosition); + + /// + /// Get the strikethrough presence where the current position is at. + /// + /// The current text position. + bool GetStrikethrough(uint currentPosition); + + /// + /// Get the application-defined drawing effect where the current position is at. + /// + /// The current text position. + IntPtr GetDrawingEffect(uint currentPosition); + + /// + /// Get the inline object at the given position. + /// + /// The given text position. + InlineObject GetInlineObject(uint currentPosition); + + /// + /// Get the typography setting where the current position is at. + /// + /// The current text position. + Typography GetTypography(uint currentPosition); + + /// + /// Get the locale name where the current position is at. + /// + /// The current text position. + string GetLocaleName(uint currentPosition); + + /// + /// Initiate drawing of the text. + /// + /// An application defined value + /// included in rendering callbacks. + /// The set of application-defined callbacks that do + /// the actual rendering. + /// The layout's top-left side. + void Draw( + IntPtr clientDrawingContext, + TextRenderer renderer, + PointF origin); + + /// + /// GetLineMetrics returns properties of each line. + /// + /// The array to fill with line information. + /// The maximum size of the lineMetrics array. + /// The actual size of the lineMetrics + /// array that is needed. + /// + /// If maxLineCount is not large enough E_NOT_SUFFICIENT_BUFFER, + /// which is equivalent to HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), + /// is returned and *actualLineCount is set to the number of lines + /// needed. + /// + LineMetrics[] GetLineMetrics(); + + /// + /// GetMetrics retrieves overall metrics for the formatted string. + /// + /// + /// Drawing effects like underline and strikethrough do not contribute to the text size, which is essentially + /// the sum of advance widths and line heights. Additionally, visible swashes and other graphic adornments + /// may extend outside the returned width and height. + /// + TextMetrics GetMetrics(); + + /// + /// GetOverhangMetrics returns the overhangs (in DIPs) of the layout and all objects contained in it, + /// including text glyphs and inline objects. + /// + /// Overshoots of visible extents (in DIPs) outside the layout. + /// + /// Any underline and strikethrough do not contribute to the black box determination, since these are + /// actually drawn by the renderer, which is allowed to draw them in any variety of styles. + /// + OverhangMetrics GetOverhangMetrics(); + + /// + /// Retrieve logical properties and measurement of each cluster. + /// + /// The array to fill with cluster information. + /// The maximum size of the clusterMetrics array. + /// The actual size of the clusterMetrics array that is needed. + /// + /// If maxClusterCount is not large enough E_NOT_SUFFICIENT_BUFFER, + /// which is equivalent to HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), + /// is returned and *actualClusterCount is set to the number of clusters + /// needed. + /// + ClusterMetrics[] GetClusterMetrics(); + + /// + /// Determines the minimum possible width the layout can be set to without emergency breaking between + /// the characters of whole words. + /// + float DetermineMinWidth(); + + /// + /// Given a coordinate (in DIPs) relative to the top-left of the layout box, this returns the corresponding + /// hit-test metrics of the text string where the hit-test has occurred. This is useful for mapping mouse + /// clicks to caret positions. When the given coordinate is outside the text string, the function sets the + /// output value *isInside to false but returns the nearest character position. + /// + /// Point to hit-test, relative to the top-left location of the layout box. + /// + /// Output flag indicating whether the hit-test location is at the leading or the trailing side of the + /// character. When is set to false, this value is set according to the output + /// *position value to represent the edge closest to the hit-test location. + /// + /// + /// Output flag indicating whether the hit-test location is inside the text string. When false, the position + /// nearest the text's edge is returned. + /// + /// Output geometry fully enclosing the hit-test location. When the output value + /// is set to false, this structure represents the geometry enclosing the edge closest to the hit-test + /// location. + /// + void HitTestPoint( + PointF point, + out bool isTrailingHit, + out bool isInside, + out HitTestMetrics hitTestMetrics); + + /// + /// Given a text position and whether the caret is on the leading or trailing + /// edge of that position, this returns the corresponding coordinate (in DIPs) + /// relative to the top-left of the layout box. This is most useful for drawing + /// the caret's current position, but it could also be used to anchor an IME to the + /// typed text or attach a floating menu near the point of interest. It may also be + /// used to programmatically obtain the geometry of a particular text position + /// for UI automation. + /// + /// Text position to get the coordinate of. + /// Flag indicating whether the location is of the leading or the trailing side of the specified text position. + /// Output caret point, relative to the top-left of the layout box. + /// Output geometry fully enclosing the specified text position. + /// + /// When drawing a caret at the returned X,Y, it should be centered on X + /// and drawn from the Y coordinate down. The height will be the size of the + /// hit-tested text (which can vary in size within a line). + /// Reading direction also affects which side of the character the caret is drawn. + /// However, the returned X coordinate will be correct for either case. + /// You can get a text length back that is larger than a single character. + /// This happens for complex scripts when multiple characters form a single cluster, + /// when diacritics join their base character, or when you test a surrogate pair. + /// + void HitTestTextPosition( + uint textPosition, + bool isTrailingHit, + out PointF point, + out HitTestMetrics hitTestMetrics); + +/* + /// + /// The application calls this function to get a set of hit-test metrics + /// corresponding to a range of text positions. The main usage for this + /// is to draw highlighted selection of the text string. + /// + /// The function returns E_NOT_SUFFICIENT_BUFFER, which is equivalent to + /// HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), when the buffer size of + /// hitTestMetrics is too small to hold all the regions calculated by the + /// function. In such situation, the function sets the output value + /// *actualHitTestMetricsCount to the number of geometries calculated. + /// The application is responsible to allocate a new buffer of greater + /// size and call the function again. + /// + /// A good value to use as an initial value for maxHitTestMetricsCount may + /// be calculated from the following equation: + /// maxHitTestMetricsCount = lineCount * maxBidiReorderingDepth + /// + /// where lineCount is obtained from the value of the output argument + /// *actualLineCount from the function IDWriteTextLayout::GetLineMetrics, + /// and the maxBidiReorderingDepth value from the DWRITE_TEXT_METRICS + /// structure of the output argument *textMetrics from the function + /// . + /// + /// First text position of the specified range. + /// Number of positions of the specified range. + /// Offset of the origin (left-top of the layout box) which is added to each of the hit-test metrics returned. + /// Pointer to a buffer of the output geometry fully enclosing the specified position range. + /// Maximum number of distinct metrics it could hold in its buffer memory. + /// Actual number of metrics returned or needed. + /// + /// There are no gaps in the returned metrics. While there could be visual gaps, + /// depending on bidi ordering, each range is contiguous and reports all the text, + /// including any hidden characters and trimmed text. + /// The height of each returned range will be the same within each line, regardless + /// of how the font sizes vary. + /// + unsafe void HitTestTextRange( + uint textPosition, + uint textLength, + PointF origin, + out HitTestMetrics hitTestMetrics, + uint maxHitTestMetricsCount, + out uint actualHitTestMetricsCount); + */ + } + } + + public static class TextLayoutExtensions + { + public static void SetMaxSize(this TextLayout textLayout, SizeF maxSize) + { + textLayout.MaxHeight = maxSize.Height; + textLayout.MaxWidth = maxSize.Width; + } + } +} diff --git a/src/WInterop.DirectX/DirectWrite/TextRange.cs b/src/WInterop.DirectX/DirectWrite/TextRange.cs index 8e544bc7..f93a63b0 100644 --- a/src/WInterop.DirectX/DirectWrite/TextRange.cs +++ b/src/WInterop.DirectX/DirectWrite/TextRange.cs @@ -1,6 +1,8 @@ // Copyright (c) Jeremy W. Kuhne. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using System.Runtime.CompilerServices; + namespace WInterop.DirectWrite { /// @@ -26,6 +28,12 @@ public TextRange(uint startPosition, uint length) } public static implicit operator TextRange((int StartPosition, int Length) tuple) - => new TextRange((uint)tuple.StartPosition, (uint)tuple.Length); + => new((uint)tuple.StartPosition, (uint)tuple.Length); + + internal unsafe DWRITE_TEXT_RANGE ToD2D() + { + fixed(void* p = &this) + return *(DWRITE_TEXT_RANGE*)p; + } } } diff --git a/src/WInterop.DirectX/DirectWrite/TextRenderer.cs b/src/WInterop.DirectX/DirectWrite/TextRenderer.cs new file mode 100644 index 00000000..8c8b93e1 --- /dev/null +++ b/src/WInterop.DirectX/DirectWrite/TextRenderer.cs @@ -0,0 +1,207 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Drawing; +using System.Numerics; +using System.Runtime.InteropServices; +using TerraFX.Interop.Windows; + +namespace WInterop.DirectWrite +{ + + /// + /// The interface represents a set of application-defined + /// callbacks that perform rendering of text, inline objects, and decorations + /// such as underlines. [IDWriteTextRenderer] + /// + [Guid(InterfaceIds.IID_IDWriteTextRenderer)] + public unsafe readonly struct TextRenderer : TextRenderer.Interface, IDisposable + { + internal IDWriteTextRenderer* Handle { get; } + + internal TextRenderer(IDWriteTextRenderer* handle) => Handle = handle; + + public void DrawGlyphRun( + IntPtr clientDrawingContext, + PointF baselineOrigin, + MeasuringMode measuringMode, + GlyphRun glyphRun, + GlyphRunDescription glyphRunDescription, + IntPtr clientDrawingEffect) + { + Handle->DrawGlyphRun( + (void*)clientDrawingContext, + baselineOrigin.X, + baselineOrigin.Y, + (DWRITE_MEASURING_MODE)measuringMode, + (DWRITE_GLYPH_RUN*)&glyphRun, + (DWRITE_GLYPH_RUN_DESCRIPTION*)&glyphRunDescription, + (IUnknown*)(void*)clientDrawingEffect).ThrowIfFailed(); + } + + public void DrawInlineObject( + IntPtr clientDrawingContext, + PointF origin, + InlineObject inlineObject, + bool isSideways, + bool isRightToLeft, + IntPtr clientDrawingEffect) + { + Handle->DrawInlineObject( + (void*)clientDrawingContext, + origin.X, + origin.Y, + inlineObject.Handle, + isSideways, + isRightToLeft, + (IUnknown*)(void*)clientDrawingEffect).ThrowIfFailed(); + } + + public void DrawStrikethrough( + IntPtr clientDrawingContext, + PointF baselineOrigin, + Strikethrough strikethrough, + IntPtr clientDrawingEffect) + { + Handle->DrawStrikethrough( + (void*)clientDrawingContext, + baselineOrigin.X, + baselineOrigin.Y, + (DWRITE_STRIKETHROUGH*)&strikethrough, + (IUnknown*)(void*)clientDrawingEffect).ThrowIfFailed(); + } + + public void DrawUnderline( + IntPtr clientDrawingContext, + PointF baselineOrigin, + Underline underline, + IntPtr clientDrawingEffect) + { + Handle->DrawUnderline( + (void*)clientDrawingContext, + baselineOrigin.X, + baselineOrigin.Y, + (DWRITE_UNDERLINE*)&underline, + (IUnknown*)(void*)clientDrawingEffect).ThrowIfFailed(); + } + + public Matrix3x2 GetCurrentTransform(IntPtr clientDrawingContext) + => PixelSnapping.From(this).GetCurrentTransform(clientDrawingContext); + + public float GetPixelsPerDip(IntPtr clientDrawingContext) + => PixelSnapping.From(this).GetPixelsPerDip(clientDrawingContext); + + public bool IsPixelSnappingDisabled(IntPtr clientDrawingContext) + => PixelSnapping.From(this).IsPixelSnappingDisabled(clientDrawingContext); + + public void Dispose() => Handle->Release(); + + internal interface Interface : PixelSnapping.Interface + { + /// + /// IDWriteTextLayout::Draw calls this function to instruct the client to + /// render a run of glyphs. + /// + /// The context passed to + /// IDWriteTextLayout::Draw. + /// Origin of the baseline. + /// Specifies measuring mode for glyphs in the run. + /// Renderer implementations may choose different rendering modes for given measuring modes, + /// but best results are seen when the rendering mode matches the corresponding measuring mode: + /// DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL for DWRITE_MEASURING_MODE_NATURAL + /// DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC for DWRITE_MEASURING_MODE_GDI_CLASSIC + /// DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL for DWRITE_MEASURING_MODE_GDI_NATURAL + /// + /// The glyph run to draw. + /// Properties of the characters associated with this run. + /// The drawing effect set in SetDrawingEffect. + void DrawGlyphRun( + IntPtr clientDrawingContext, + PointF baselineOrigin, + MeasuringMode measuringMode, + GlyphRun glyphRun, + GlyphRunDescription glyphRunDescription, + IntPtr clientDrawingEffect); + + /// + /// IDWriteTextLayout::Draw calls this function to instruct the client to draw + /// an underline. + /// + /// The context passed to + /// IDWriteTextLayout::Draw. + /// Origin of the baseline. + /// Underline logical information. + /// The drawing effect set in + /// IDWriteTextLayout::SetDrawingEffect. + /// + /// A single underline can be broken into multiple calls, depending on + /// how the formatting changes attributes. If font sizes/styles change + /// within an underline, the thickness and offset will be averaged + /// weighted according to characters. + /// To get the correct top coordinate of the underline rect, add underline::offset + /// to the baseline's Y. Otherwise the underline will be immediately under the text. + /// The x coordinate will always be passed as the left side, regardless + /// of text directionality. This simplifies drawing and reduces the + /// problem of round-off that could potentially cause gaps or a double + /// stamped alpha blend. To avoid alpha overlap, round the end points + /// to the nearest device pixel. + /// + void DrawUnderline( + IntPtr clientDrawingContext, + PointF baselineOrigin, + Underline underline, + IntPtr clientDrawingEffect); + + /// + /// IDWriteTextLayout::Draw calls this function to instruct the client to draw + /// a strikethrough. + /// + /// The context passed to + /// IDWriteTextLayout::Draw. + /// X-coordinate of the baseline. + /// Y-coordinate of the baseline. + /// Strikethrough logical information. + /// The drawing effect set in + /// IDWriteTextLayout::SetDrawingEffect. + /// + /// A single strikethrough can be broken into multiple calls, depending on + /// how the formatting changes attributes. Strikethrough is not averaged + /// across font sizes/styles changes. + /// To get the correct top coordinate of the strikethrough rect, + /// add strikethrough::offset to the baseline's Y. + /// Like underlines, the x coordinate will always be passed as the left side, + /// regardless of text directionality. + /// + void DrawStrikethrough( + IntPtr clientDrawingContext, + PointF baselineOrigin, + Strikethrough strikethrough, + IntPtr clientDrawingEffect); + + /// + /// IDWriteTextLayout::Draw calls this application callback when it needs to + /// draw an inline object. + /// + /// The context passed to IDWriteTextLayout::Draw. + /// The top-left corner of the inline object. + /// The object set using IDWriteTextLayout::SetInlineObject. + /// The object should be drawn on its side. + /// The object is in an right-to-left context and should be drawn flipped. + /// The drawing effect set in + /// IDWriteTextLayout::SetDrawingEffect. + /// + /// The right-to-left flag is a hint for those cases where it would look + /// strange for the image to be shown normally (like an arrow pointing to + /// right to indicate a submenu). + /// + void DrawInlineObject( + IntPtr clientDrawingContext, + PointF origin, + InlineObject inlineObject, + bool isSideways, + bool isRightToLeft, + IntPtr clientDrawingEffect); + } + } +} diff --git a/src/WInterop.DirectX/DirectWrite/TrimmingGranularity.cs b/src/WInterop.DirectX/DirectWrite/TrimmingGranularity.cs index 8ded52ec..d390875c 100644 --- a/src/WInterop.DirectX/DirectWrite/TrimmingGranularity.cs +++ b/src/WInterop.DirectX/DirectWrite/TrimmingGranularity.cs @@ -11,16 +11,16 @@ public enum TrimmingGranularity : uint /// /// No trimming occurs. Text flows beyond the layout width. /// - None, + None = DWRITE_TRIMMING_GRANULARITY.DWRITE_TRIMMING_GRANULARITY_NONE, /// /// Trimming occurs at character cluster boundary. /// - Character, + Character = DWRITE_TRIMMING_GRANULARITY.DWRITE_TRIMMING_GRANULARITY_CHARACTER, /// /// Trimming occurs at word boundary. /// - Word + Word = DWRITE_TRIMMING_GRANULARITY.DWRITE_TRIMMING_GRANULARITY_WORD } } diff --git a/src/WInterop.DirectX/DirectWrite/Typography.cs b/src/WInterop.DirectX/DirectWrite/Typography.cs new file mode 100644 index 00000000..24bd705f --- /dev/null +++ b/src/WInterop.DirectX/DirectWrite/Typography.cs @@ -0,0 +1,60 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace WInterop.DirectWrite +{ + /// + /// Font typography setting. [IDWriteTypography] + /// + [Guid(InterfaceIds.IID_IDWriteTypography)] + public readonly unsafe struct Typography : Typography.Interface, IDisposable + { + internal IDWriteTypography* Handle { get; } + + internal Typography(IDWriteTypography* handle) => Handle = handle; + + public void AddFontFeature(FontFeature fontFeature) + { + Handle->AddFontFeature(Unsafe.As(ref fontFeature)).ThrowIfFailed(); + } + + public void Dispose() => Handle->Release(); + + public void GetFontFeature(uint fontFeatureIndex, out FontFeature fontFeature) + { + fixed (void* f = &fontFeature) + { + Handle->GetFontFeature(fontFeatureIndex, (DWRITE_FONT_FEATURE*)f); + } + } + + public uint FontFeatureCount => Handle->GetFontFeatureCount(); + + internal interface Interface + { + /// + /// Add font feature. + /// + /// The font feature to add. + void AddFontFeature(FontFeature fontFeature); + + /// + /// Get the number of font features. + /// + uint FontFeatureCount { get; } + + /// + /// Get the font feature at the specified index. + /// + /// The zero-based index of the font feature to get. + /// The font feature. + void GetFontFeature( + uint fontFeatureIndex, + out FontFeature fontFeature); + } + } +} diff --git a/src/WInterop.DirectX/DirectWrite/WordWrapping.cs b/src/WInterop.DirectX/DirectWrite/WordWrapping.cs index 89dc950d..f4f78ef8 100644 --- a/src/WInterop.DirectX/DirectWrite/WordWrapping.cs +++ b/src/WInterop.DirectX/DirectWrite/WordWrapping.cs @@ -11,29 +11,29 @@ public enum WordWrapping : uint /// /// Words are broken across lines to avoid text overflowing the layout box. /// - Wrap = 0, + Wrap = DWRITE_WORD_WRAPPING.DWRITE_WORD_WRAPPING_WRAP, /// /// Words are kept within the same line even when it overflows the layout box. /// This option is often used with scrolling to reveal overflow text. /// - NoWrap = 1, + NoWrap = DWRITE_WORD_WRAPPING.DWRITE_WORD_WRAPPING_NO_WRAP, /// /// Words are broken across lines to avoid text overflowing the layout box. /// Emergency wrapping occurs if the word is larger than the maximum width. /// - EmergencyBreak = 2, + EmergencyBreak = DWRITE_WORD_WRAPPING.DWRITE_WORD_WRAPPING_EMERGENCY_BREAK, /// /// Only wrap whole words, never breaking words (emergency wrapping) when the /// layout width is too small for even a single word. /// - WholeWord = 3, + WholeWord = DWRITE_WORD_WRAPPING.DWRITE_WORD_WRAPPING_WHOLE_WORD, /// /// Wrap between any valid characters clusters. /// - Character = 4, + Character = DWRITE_WORD_WRAPPING.DWRITE_WORD_WRAPPING_CHARACTER, } } diff --git a/src/WInterop.DirectX/DirectWrite/WriteFactory.cs b/src/WInterop.DirectX/DirectWrite/WriteFactory.cs new file mode 100644 index 00000000..99ba0494 --- /dev/null +++ b/src/WInterop.DirectX/DirectWrite/WriteFactory.cs @@ -0,0 +1,484 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Drawing; +using System.Globalization; +using System.Numerics; +using System.Runtime.InteropServices; +using WInterop.Windows.Native; + +namespace WInterop.DirectWrite +{ + /// + /// The root factory interface for all DWrite objects. [IDWriteFactory] + /// + [Guid(InterfaceIds.IID_IDWriteFactory)] + public readonly unsafe struct WriteFactory : WriteFactory.Interface, IDisposable + { + private readonly IDWriteFactory* _handle; + + internal WriteFactory(IDWriteFactory* handle) => _handle = handle; + + public RenderingParams CreateCustomRenderingParams( + float gamma, + float enhancedContrast, + float clearTypeLevel, + PixelGeometry pixelGeometry, + RenderingMode renderingMode) + { + IDWriteRenderingParams* rendering; + + _handle->CreateCustomRenderingParams( + gamma, + enhancedContrast, + clearTypeLevel, + (DWRITE_PIXEL_GEOMETRY)pixelGeometry, + (DWRITE_RENDERING_MODE)renderingMode, + &rendering).ThrowIfFailed(); + + return new(rendering); + } + + public InlineObject CreateEllipsisTrimmingSign(TextFormat textFormat) + { + IDWriteInlineObject* inlineObject; + _handle->CreateEllipsisTrimmingSign(textFormat.Handle, &inlineObject).ThrowIfFailed(); + return new(inlineObject); + } + + public TextLayout CreateGdiCompatibleTextLayout( + ReadOnlySpan @string, + uint stringLength, + TextFormat textFormat, + float layoutWidth, + float layoutHeight, + float pixelsPerDip, + Matrix3x2 transform, + bool useGdiNatural) + { + IDWriteTextLayout* layout; + fixed (void* s = @string) + { + _handle->CreateGdiCompatibleTextLayout( + (ushort*)s, + (uint)@string.Length, + textFormat.Handle, + layoutWidth, + layoutHeight, + pixelsPerDip, + (DWRITE_MATRIX*)&transform, + useGdiNatural, + &layout).ThrowIfFailed(); + } + + return new(layout); + } + + public RenderingParams CreateMonitorRenderingParams(HMONITOR monitor) + { + IDWriteRenderingParams* rendering; + _handle->CreateMonitorRenderingParams((TerraFX.Interop.Windows.HMONITOR)monitor.Value, &rendering).ThrowIfFailed(); + return new(rendering); + } + + public RenderingParams CreateRenderingParams() + { + IDWriteRenderingParams* rendering; + _handle->CreateRenderingParams(&rendering).ThrowIfFailed(); + return new(rendering); + } + + public TextFormat CreateTextFormat( + string fontFamilyName, + FontCollection fontCollection = default, + FontWeight fontWeight = FontWeight.Normal, + FontStyle fontStyle = FontStyle.Normal, + FontStretch fontStretch = FontStretch.Normal, + float fontSize = 12, + string localeName = null) + { + IDWriteTextFormat* format; + localeName ??= CultureInfo.CurrentCulture.Name; + + fixed (void* n = fontFamilyName) + fixed (void* l = localeName) + { + _handle->CreateTextFormat( + (ushort*)n, + fontCollection.Handle, + (DWRITE_FONT_WEIGHT)fontWeight, + (DWRITE_FONT_STYLE)fontStyle, + (DWRITE_FONT_STRETCH)fontStretch, + fontSize, + (ushort*)l, + &format).ThrowIfFailed(); + } + + return new(format); + } + + public TextLayout CreateTextLayout(ReadOnlySpan @string, TextFormat textFormat, SizeF maxSize) + { + IDWriteTextLayout* layout; + + fixed (void* s = @string) + { + _handle->CreateTextLayout( + (ushort*)s, + (uint)@string.Length, + textFormat.Handle, + maxSize.Width, + maxSize.Height, + &layout).ThrowIfFailed(); + } + + return new(layout); + } + + public Typography CreateTypography() + { + IDWriteTypography* typography; + _handle->CreateTypography(&typography).ThrowIfFailed(); + return new(typography); + } + + public void Dispose() => _handle->Release(); + + public FontCollection GetSystemFontCollection(bool checkForUpdates) + { + IDWriteFontCollection* collection; + _handle->GetSystemFontCollection(&collection, checkForUpdates).ThrowIfFailed(); + return new(collection); + } + + internal interface Interface + { + /// + /// Gets a font collection representing the set of installed fonts. + /// + /// + /// If this parameter is true, the function performs an immediate check for changes to the set of installed fonts. + /// If this parameter is false, the function will still detect changes if the font cache service is running, but + /// there may be some latency. For example, an application might specify true if it has itself just installed a font + /// and wants to be sure the font collection contains that font. + /// + FontCollection GetSystemFontCollection(bool checkForUpdates); + + /* + /// + /// Creates a font collection using a custom font collection loader. + /// + /// Application-defined font collection loader, which must have been previously + /// registered using RegisterFontCollectionLoader. + /// Key used by the loader to identify a collection of font files. + /// Size in bytes of the collection key. + /// Receives a pointer to the system font collection object, or NULL in case of failure. + //void CreateCustomFontCollectionSTUB(); + //STDMETHOD(CreateCustomFontCollection)( + // _In_ IDWriteFontCollectionLoader* collectionLoader, + // _In_reads_bytes_(collectionKeySize) void const* collectionKey, + // UINT32 collectionKeySize, + // _COM_Outptr_ IDWriteFontCollection** fontCollection + // ) PURE; + + /// + /// Registers a custom font collection loader with the factory object. + /// + /// Application-defined font collection loader. + void RegisterFontCollectionLoaderSTUB(); + //STDMETHOD(RegisterFontCollectionLoader)( + // _In_ IDWriteFontCollectionLoader* fontCollectionLoader + // ) PURE; + + /// + /// Unregisters a custom font collection loader that was previously registered using RegisterFontCollectionLoader. + /// + /// Application-defined font collection loader. + /// + /// Standard HRESULT error code. + /// + void UnregisterFontCollectionLoaderSTUB(); + //STDMETHOD(UnregisterFontCollectionLoader)( + // _In_ IDWriteFontCollectionLoader* fontCollectionLoader + // ) PURE; + + /// + /// CreateFontFileReference creates a font file reference object from a local font file. + /// + /// Absolute file path. Subsequent operations on the constructed object may fail + /// if the user provided filePath doesn't correspond to a valid file on the disk. + /// Last modified time of the input file path. If the parameter is omitted, + /// the function will access the font file to obtain its last write time, so the clients are encouraged to specify this value + /// to avoid extra disk access. Subsequent operations on the constructed object may fail + /// if the user provided lastWriteTime doesn't match the file on the disk. + /// Contains newly created font file reference object, or NULL in case of failure. + void CreateFontFileReferenceSTUB(); + //STDMETHOD(CreateFontFileReference)( + // _In_z_ WCHAR const* filePath, + // _In_opt_ FILETIME const* lastWriteTime, + // _COM_Outptr_ IDWriteFontFile** fontFile + // ) PURE; + + /// + /// CreateCustomFontFileReference creates a reference to an application specific font file resource. + /// This function enables an application or a document to use a font without having to install it on the system. + /// The fontFileReferenceKey has to be unique only in the scope of the fontFileLoader used in this call. + /// + /// Font file reference key that uniquely identifies the font file resource + /// during the lifetime of fontFileLoader. + /// Size of font file reference key in bytes. + /// Font file loader that will be used by the font system to load data from the file identified by + /// fontFileReferenceKey. + /// Contains the newly created font file object, or NULL in case of failure. + /// + /// Standard HRESULT error code. + /// + /// + /// This function is provided for cases when an application or a document needs to use a font + /// without having to install it on the system. fontFileReferenceKey has to be unique only in the scope + /// of the fontFileLoader used in this call. + /// + void CreateCustomFontFileReferenceSTUB(); + //STDMETHOD(CreateCustomFontFileReference)( + // _In_reads_bytes_(fontFileReferenceKeySize) void const* fontFileReferenceKey, + // UINT32 fontFileReferenceKeySize, + // _In_ IDWriteFontFileLoader* fontFileLoader, + // _COM_Outptr_ IDWriteFontFile** fontFile + // ) PURE; + + /// + /// Creates a font face object. + /// + /// The file format of the font face. + /// The number of font files required to represent the font face. + /// Font files representing the font face. Since IDWriteFontFace maintains its own references + /// to the input font file objects, it's OK to release them after this call. + /// The zero based index of a font face in cases when the font files contain a collection of font faces. + /// If the font files contain a single face, this value should be zero. + /// Font face simulation flags for algorithmic emboldening and italicization. + /// Contains the newly created font face object, or NULL in case of failure. + void CreateFontFaceSTUB(); + //IFontFace CreateFontFace( + // FontFaceType fontFaceType, + // uint numberOfFiles, + // _In_reads_(numberOfFiles) IDWriteFontFile* const* fontFiles, + // uint faceIndex, + // DWRITE_FONT_SIMULATIONS fontFaceSimulationFlags); + */ + + /// + /// Creates a rendering parameters object with default settings for the primary monitor. + /// + RenderingParams CreateRenderingParams(); + + /// + /// Creates a rendering parameters object with default settings for the specified monitor. + /// + /// The monitor to read the default values from. + RenderingParams CreateMonitorRenderingParams(HMONITOR monitor); + + /// + /// Creates a rendering parameters object with the specified properties. + /// + /// The gamma value used for gamma correction, which must be greater than zero and cannot exceed 256. + /// The amount of contrast enhancement, zero or greater. + /// The degree of ClearType level, from 0.0f (no ClearType) to 1.0f (full ClearType). + /// The geometry of a device pixel. + /// Method of rendering glyphs. In most cases, this should be DWRITE_RENDERING_MODE_DEFAULT to automatically use an appropriate mode. + RenderingParams CreateCustomRenderingParams( + float gamma, + float enhancedContrast, + float clearTypeLevel, + PixelGeometry pixelGeometry, + RenderingMode renderingMode); + +/* + /// + /// Registers a font file loader with DirectWrite. + /// + /// Pointer to the implementation of the IDWriteFontFileLoader for a particular file resource type. + /// + /// This function registers a font file loader with DirectWrite. + /// Font file loader interface handles loading font file resources of a particular type from a key. + /// The font file loader interface is recommended to be implemented by a singleton object. + /// A given instance can only be registered once. + /// Succeeding attempts will return an error that it has already been registered. + /// IMPORTANT: font file loader implementations must not register themselves with DirectWrite + /// inside their constructors and must not unregister themselves in their destructors, because + /// registration and unregistration operations increment and decrement the object reference count respectively. + /// Instead, registration and unregistration of font file loaders with DirectWrite should be performed + /// outside of the font file loader implementation as a separate step. + /// + void RegisterFontFileLoaderSTUB(); + //STDMETHOD(RegisterFontFileLoader)( + // _In_ IDWriteFontFileLoader* fontFileLoader + // ) PURE; + + /// + /// Unregisters a font file loader that was previously registered with the DirectWrite font system using RegisterFontFileLoader. + /// + /// Pointer to the file loader that was previously registered with the DirectWrite font system using RegisterFontFileLoader. + /// + /// This function will succeed if the user loader is requested to be removed. + /// It will fail if the pointer to the file loader identifies a standard DirectWrite loader, + /// or a loader that is never registered or has already been unregistered. + /// + /// + /// This function unregisters font file loader callbacks with the DirectWrite font system. + /// The font file loader interface is recommended to be implemented by a singleton object. + /// IMPORTANT: font file loader implementations must not register themselves with DirectWrite + /// inside their constructors and must not unregister themselves in their destructors, because + /// registration and unregistration operations increment and decrement the object reference count respectively. + /// Instead, registration and unregistration of font file loaders with DirectWrite should be performed + /// outside of the font file loader implementation as a separate step. + /// + void UnregisterFontFileLoaderSTUB(); + //STDMETHOD(UnregisterFontFileLoader)( + // _In_ IDWriteFontFileLoader* fontFileLoader + // ) PURE; +*/ + + /// + /// Create a text format object used for text layout. + /// + /// Name of the font family + /// Font collection. 'null' indicates the system font collection. + /// Logical size of the font in DIP units. A DIP ("device-independent pixel") equals 1/96 inch. + /// Locale name + TextFormat CreateTextFormat( + string fontFamilyName, + FontCollection fontCollection = default, + FontWeight fontWeight = FontWeight.Normal, + FontStyle fontStyle = FontStyle.Normal, + FontStretch fontStretch = FontStretch.Normal, + float fontSize = 12.0f, + string localeName = null); + + /// + /// Create a typography object used in conjunction with text format for text layout. + /// + Typography CreateTypography(); + +/* + /// + /// Create an object used for interoperability with GDI. + /// + /// Receives the GDI interop object if successful, or NULL in case of failure. + void GetGdiInteropSTUB(); + //STDMETHOD(GetGdiInterop)( + // _COM_Outptr_ IDWriteGdiInterop** gdiInterop + // ) PURE; +*/ + + /// + /// CreateTextLayout takes a string, format, and associated constraints + /// and produces an object representing the fully analyzed + /// and formatted result. + /// + /// The string to layout. + /// The format to apply to the string. + /// Size of the layout box. + TextLayout CreateTextLayout( + ReadOnlySpan @string, + TextFormat textFormat, + SizeF maxSize); + + /// + /// CreateGdiCompatibleTextLayout takes a string, format, and associated constraints + /// and produces and object representing the result formatted for a particular display resolution + /// and measuring mode. The resulting text layout should only be used for the intended resolution, + /// and for cases where text scalability is desired, CreateTextLayout should be used instead. + /// + /// The string to layout. + /// The length of the string. + /// The format to apply to the string. + /// Width of the layout box. + /// Height of the layout box. + /// Number of physical pixels per DIP. For example, if rendering onto a 96 DPI device then pixelsPerDip + /// is 1. If rendering onto a 120 DPI device then pixelsPerDip is 120/96. + /// Optional transform applied to the glyphs and their positions. This transform is applied after the + /// scaling specified the font size and pixelsPerDip. + /// + /// When set to FALSE, instructs the text layout to use the same metrics as GDI aliased text. + /// When set to TRUE, instructs the text layout to use the same metrics as text measured by GDI using a font + /// created with CLEARTYPE_NATURAL_QUALITY. + /// + TextLayout CreateGdiCompatibleTextLayout( + ReadOnlySpan @string, + uint stringLength, + TextFormat textFormat, + float layoutWidth, + float layoutHeight, + float pixelsPerDip, + Matrix3x2 transform, + bool useGdiNatural); + + /// + /// The application may call this function to create an inline object for trimming, using an ellipsis as the + /// omission sign. The ellipsis will be created using the current settings of the format, including base font, + /// style, and any effects. Alternate omission signs can be created by the application by implementing + /// IDWriteInlineObject. + /// + /// Text format used as a template for the omission sign. + /// Created omission sign. + InlineObject CreateEllipsisTrimmingSign(TextFormat textFormat); + +/* + ///// The resultant object. + /// + /// Return an interface to perform text analysis with. + /// + void CreateTextAnalyzerSTUB(); + //STDMETHOD(CreateTextAnalyzer)( + // _COM_Outptr_ IDWriteTextAnalyzer** textAnalyzer + // ) PURE; + + + ///// Method of number substitution to use. + ///// Which locale to obtain the digits from. + ///// Ignore the user's settings and use the locale defaults + ///// Receives a pointer to the newly created object. + /// + /// Creates a number substitution object using a locale name, + /// substitution method, and whether to ignore user overrides (uses NLS + /// defaults for the given culture instead). + /// + void CreateNumberSubstitutionSTUB(); + //STDMETHOD(CreateNumberSubstitution)( + // _In_ DWRITE_NUMBER_SUBSTITUTION_METHOD substitutionMethod, + // _In_z_ WCHAR const* localeName, + // _In_ BOOL ignoreUserOverride, + // _COM_Outptr_ IDWriteNumberSubstitution** numberSubstitution + // ) PURE; + + /// + /// Creates a glyph run analysis object, which encapsulates information + /// used to render a glyph run. + /// + /// Structure specifying the properties of the glyph run. + /// Number of physical pixels per DIP. For example, if rendering onto a 96 DPI bitmap then pixelsPerDip + /// is 1. If rendering onto a 120 DPI bitmap then pixelsPerDip is 120/96. + /// Optional transform applied to the glyphs and their positions. This transform is applied after the + /// scaling specified by the emSize and pixelsPerDip. + /// Specifies the rendering mode, which must be one of the raster rendering modes (i.e., not default + /// and not outline). + /// Specifies the method to measure glyphs. + /// Horizontal position of the baseline origin, in DIPs. + /// Vertical position of the baseline origin, in DIPs. + /// Receives a pointer to the newly created object. + void CreateGlyphRunAnalysisSTUB(); + //STDMETHOD(CreateGlyphRunAnalysis)( + // _In_ DWRITE_GLYPH_RUN const* glyphRun, + // FLOAT pixelsPerDip, + // _In_opt_ DWRITE_MATRIX const* transform, + // DWRITE_RENDERING_MODE renderingMode, + // DWRITE_MEASURING_MODE measuringMode, + // FLOAT baselineOriginX, + // FLOAT baselineOriginY, + // _COM_Outptr_ IDWriteGlyphRunAnalysis** glyphRunAnalysis + // ) PURE; +*/ + } + } +} diff --git a/src/WInterop.DirectX/DirectX/DirectXWindowClass.cs b/src/WInterop.DirectX/DirectX/DirectXWindowClass.cs index c264d51f..576d3917 100644 --- a/src/WInterop.DirectX/DirectX/DirectXWindowClass.cs +++ b/src/WInterop.DirectX/DirectX/DirectXWindowClass.cs @@ -2,8 +2,6 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using WInterop.Direct2d; -using WInterop.DirectWrite; -using WInterop.Errors; using WInterop.Gdi; using WInterop.Modules; using WInterop.Windows; @@ -13,7 +11,6 @@ namespace WInterop.DirectX public class DirectXWindowClass : WindowClass { private bool _resourcesValid; - private IWindowRenderTarget _renderTarget; public unsafe DirectXWindowClass( string className = default, @@ -30,16 +27,16 @@ public unsafe DirectXWindowClass( { } - protected IRenderTarget RenderTarget => _renderTarget; + protected IWindowRenderTarget RenderTarget { get; private set; } - protected static Direct2d.IFactory Direct2dFactory { get; } = Direct2d.Direct2d.CreateFactory(); - protected static DirectWrite.IFactory DirectWriteFactory { get; } = DirectWrite.DirectWrite.CreateFactory(); + protected static Factory Direct2dFactory { get; } = Direct2d.Direct2d.CreateFactory(); + protected static DirectWrite.WriteFactory DirectWriteFactory { get; } = DirectWrite.DirectWrite.CreateFactory(); private void CreateResourcesInternal(WindowHandle window) { if (!_resourcesValid) { - _renderTarget = Direct2dFactory.CreateWindowRenderTarget( + RenderTarget = Direct2dFactory.CreateWindowRenderTarget( default, new WindowRenderTargetProperties(window, window.GetClientRectangle().Size)); CreateResources(); _resourcesValid = true; @@ -50,14 +47,14 @@ private void CreateResourcesInternal(WindowHandle window, in Message.Size size) { if (!_resourcesValid) { - _renderTarget = Direct2dFactory.CreateWindowRenderTarget( + RenderTarget = Direct2dFactory.CreateWindowRenderTarget( default, new WindowRenderTargetProperties(window, size.NewSize)); CreateResources(); _resourcesValid = true; } else { - _renderTarget.Resize(size.NewSize); + RenderTarget.Resize(size.NewSize); } } @@ -87,19 +84,16 @@ protected sealed override LResult WindowProcedure(WindowHandle window, MessageTy break; case MessageType.Paint: CreateResourcesInternal(window); - _renderTarget.BeginDraw(); + RenderTarget.BeginDraw(); OnPaint(window); - HResult result = _renderTarget.EndDraw(); + RenderTarget.EndDraw(out bool recreateTarget); window.Validate(); - if (result == HResult.D2DERR_RECREATE_TARGET) + if (recreateTarget) { _resourcesValid = false; } - else - { - result.ThrowIfFailed(); - } + break; } @@ -114,9 +108,7 @@ protected virtual LResult Direct2dWindowProcedure(WindowHandle window, MessageTy switch (message) { case MessageType.Size: - return 0; case MessageType.DisplayChange: - return 0; case MessageType.Paint: return 0; } diff --git a/src/WInterop.DirectX/Dxgi/Format.cs b/src/WInterop.DirectX/Dxgi/Format.cs index eb278b78..09dd9ff5 100644 --- a/src/WInterop.DirectX/Dxgi/Format.cs +++ b/src/WInterop.DirectX/Dxgi/Format.cs @@ -8,11 +8,11 @@ namespace WInterop.Dxgi /// public enum Format : uint { - DXGI_FORMAT_UNKNOWN = 0, - DXGI_FORMAT_R32G32B32A32_TYPELESS = 1, - DXGI_FORMAT_R32G32B32A32_FLOAT = 2, - DXGI_FORMAT_R32G32B32A32_UINT = 3, - DXGI_FORMAT_R32G32B32A32_SINT = 4, + Unknown = DXGI_FORMAT.DXGI_FORMAT_UNKNOWN, + TypelessR32G32B32A32 = DXGI_FORMAT.DXGI_FORMAT_R32G32B32A32_TYPELESS, + FloatR32G32B32A32 = DXGI_FORMAT.DXGI_FORMAT_R32G32B32A32_FLOAT, + UIntR32G32B32A32 = DXGI_FORMAT.DXGI_FORMAT_R32G32B32A32_UINT, + SIntR32G32B32A32 = DXGI_FORMAT.DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_R32G32B32_TYPELESS = 5, DXGI_FORMAT_R32G32B32_FLOAT = 6, DXGI_FORMAT_R32G32B32_UINT = 7, diff --git a/src/WInterop.DirectX/GlobalUsings.cs b/src/WInterop.DirectX/GlobalUsings.cs new file mode 100644 index 00000000..d360b7b7 --- /dev/null +++ b/src/WInterop.DirectX/GlobalUsings.cs @@ -0,0 +1 @@ +global using TerraFX.Interop.DirectX; diff --git a/src/WInterop.DirectX/IHandle.cs b/src/WInterop.DirectX/IHandle.cs new file mode 100644 index 00000000..aada67c3 --- /dev/null +++ b/src/WInterop.DirectX/IHandle.cs @@ -0,0 +1,12 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#nullable enable + +namespace WInterop +{ + internal interface IHandle where T : unmanaged + { + unsafe T* Handle { get; } + } +} diff --git a/src/WInterop.DirectX/InteropExtensions.cs b/src/WInterop.DirectX/InteropExtensions.cs new file mode 100644 index 00000000..4852ddfb --- /dev/null +++ b/src/WInterop.DirectX/InteropExtensions.cs @@ -0,0 +1,43 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#nullable enable + +using System; +using System.Drawing; +using System.Runtime.CompilerServices; +using TerraFX.Interop.Windows; +using WInterop.Errors; + +namespace WInterop +{ + internal static class InteropExtensions + { + internal static RectangleF ToRectangleF(this in D2D_RECT_F rect) + => RectangleF.FromLTRB(rect.left, rect.top, rect.right, rect.bottom); + + internal static D2D_RECT_F ToD2D(this in RectangleF rect) + => new(rect.Left, rect.Top, rect.Right, rect.Bottom); + + internal static D2D_RECT_U ToD2D(this in Rectangle rect) + => checked(new((uint)rect.Left, (uint)rect.Top, (uint)rect.Right, (uint)rect.Bottom)); + + internal static PointF ToPointF(this in D2D_POINT_2F point) + => Unsafe.As(ref Unsafe.AsRef(point)); + + internal static D2D_POINT_2F ToD2D(this in PointF point) + => Unsafe.As(ref Unsafe.AsRef(point)); + + internal static SizeF ToSizeF(this in D2D_SIZE_F size) + => Unsafe.As(ref Unsafe.AsRef(size)); + + internal static D2D_SIZE_F ToD2D(this in SizeF size) + => Unsafe.As(ref Unsafe.AsRef(size)); + + internal static HResult ToHResult(this in HRESULT result) + => (HResult)(int)result; + + internal static void ThrowIfFailed(this in HRESULT result, string? detail = null) + => result.ToHResult().ThrowIfFailed(detail); + } +} diff --git a/src/WInterop.DirectX/WInterop.Direct2d.csproj b/src/WInterop.DirectX/WInterop.Direct2d.csproj index cca54b6d..3346fb51 100644 --- a/src/WInterop.DirectX/WInterop.Direct2d.csproj +++ b/src/WInterop.DirectX/WInterop.Direct2d.csproj @@ -6,7 +6,11 @@ False True WInterop + true + + +