From bc3eef5ca51c25a9aca72a40c3413502827415c4 Mon Sep 17 00:00:00 2001 From: Jeremy Kuhne Date: Sun, 28 Nov 2021 17:58:09 -0800 Subject: [PATCH] Move DirectDraw/Write code off of COM Interop Leverage TerraFX interop function pointer definitions to remove all usages of [ComImport] in the DirectX library. To keep overhead low, wrappers are usually presented as structs. "Inheritance" is accomplished via conversion operators and internal interface hierarchies (kept internal to avoid accidental boxing). Existing demos work, including custom text rendering. There is an initial manual CCW for that, which I'll undoubtably iterate on to try and simplify creation of these things. --- src/Performance/FunctionPointers.cs | 4 +- src/Performance/Performance.csproj | 2 +- .../Direct2dDemo/CombineGeometries.cs | 94 +++ .../CoreWindows/Direct2dDemo/Direct2dDemo.cs | 18 +- .../CoreWindows/Direct2dDemo/DrawEllipse.cs | 28 +- .../Direct2dDemo/PathGeometries.cs | 161 ++-- .../CoreWindows/Direct2dDemo/Program.cs | 1 + .../CoreWindows/DirectWriteDemo/CustomText.cs | 10 +- .../DirectWriteDemo/CustomTextRenderer.cs | 122 --- .../CoreWindows/DirectWriteDemo/HelloWorld.cs | 14 +- .../DirectWriteDemo/SampleTextRenderer.cs | 107 +++ src/Tests/WInterop.Tests/Direct2d/Factory.cs | 34 - .../WInterop.Tests/Direct2d/FactoryTests.cs | 30 + .../WInterop.Tests/Direct2d/RenderTarget.cs | 402 +++++----- .../Com/Native/IDataObject.cs | 6 +- .../Com/Native/IDropSource.CCW.cs | 12 +- .../Com/Native/IUnknown.CCW.cs | 8 +- src/WInterop.Desktop/Com/Native/Lifetime.cs | 30 +- .../Windows/Classes/WindowClass.cs | 26 +- src/WInterop.DirectX/Direct2d/AlphaMode.cs | 8 +- .../Direct2d/AntialiasMode.cs | 4 +- src/WInterop.DirectX/Direct2d/ArcSegment.cs | 24 +- src/WInterop.DirectX/Direct2d/ArcSize.cs | 4 +- .../Direct2d/BezierSegment.cs | 12 +- src/WInterop.DirectX/Direct2d/Bitmap.cs | 110 +++ src/WInterop.DirectX/Direct2d/BitmapBrush.cs | 90 +++ .../Direct2d/BitmapBrushProperties.cs | 18 +- .../Direct2d/BitmapRenderTarget.cs | 28 + src/WInterop.DirectX/Direct2d/Brush.cs | 61 ++ .../Direct2d/BrushProperties.cs | 15 +- src/WInterop.DirectX/Direct2d/CapStyle.cs | 8 +- src/WInterop.DirectX/Direct2d/ColorF.cs | 9 +- src/WInterop.DirectX/Direct2d/DashStyle.cs | 12 +- src/WInterop.DirectX/Direct2d/DebugLevel.cs | 8 +- src/WInterop.DirectX/Direct2d/Direct2d.cs | 15 +- src/WInterop.DirectX/Direct2d/Ellipse.cs | 13 +- .../Direct2d/EllipseGeometry.cs | 49 ++ src/WInterop.DirectX/Direct2d/ExtendMode.cs | 6 +- src/WInterop.DirectX/Direct2d/Factory.cs | 164 ++++ src/WInterop.DirectX/Direct2d/FactoryType.cs | 4 +- src/WInterop.DirectX/Direct2d/FigureBegin.cs | 4 +- src/WInterop.DirectX/Direct2d/FigureEnd.cs | 4 +- src/WInterop.DirectX/Direct2d/FillMode.cs | 4 +- src/WInterop.DirectX/Direct2d/Gamma.cs | 4 +- src/WInterop.DirectX/Direct2d/Geometry.cs | 182 +++++ .../Direct2d/GeometryGroup.cs | 58 ++ .../Direct2d/GeometryRelation.cs | 3 +- src/WInterop.DirectX/Direct2d/GeometrySink.cs | 93 +++ .../Direct2d/GradientStopCollection.cs | 61 ++ src/WInterop.DirectX/Direct2d/IBitmap.cs | 64 -- src/WInterop.DirectX/Direct2d/IBitmapBrush.cs | 90 --- .../Direct2d/IBitmapRenderTarget.cs | 442 +---------- src/WInterop.DirectX/Direct2d/IBrush.cs | 46 -- .../Direct2d/IDeviceContextRenderTarget.cs | 430 +---------- .../Direct2d/IDrawingStateBlock.cs | 83 +- .../Direct2d/IEllipseGeometry.cs | 145 ---- src/WInterop.DirectX/Direct2d/IFactory.cs | 125 --- src/WInterop.DirectX/Direct2d/IGeometry.cs | 153 ---- .../Direct2d/IGeometryGroup.cs | 154 ---- .../Direct2d/IGeometrySink.cs | 78 -- .../Direct2d/IGradientStopCollection.cs | 47 -- src/WInterop.DirectX/Direct2d/IImage.cs | 22 - .../Direct2d/IPathGeometry.cs | 158 ---- .../Direct2d/IRadialGradientBrush.cs | 84 -- .../Direct2d/IRectangleGeometry.cs | 142 ---- .../Direct2d/IRenderTarget.cs | 489 +++--------- src/WInterop.DirectX/Direct2d/IResource.cs | 21 - .../Direct2d/IRoundedRectangleGeometry.cs | 146 ---- .../Direct2d/ISimplifiedGeometrySink.cs | 60 -- .../Direct2d/ISolidColorBrush.cs | 55 -- src/WInterop.DirectX/Direct2d/IStrokeStyle.cs | 56 -- .../Direct2d/ITesselationSink.cs | 37 +- .../Direct2d/ITransformedGeometry.cs | 150 ---- .../Direct2d/IWindowRenderTarget.cs | 447 +---------- src/WInterop.DirectX/Direct2d/Image.cs | 25 + src/WInterop.DirectX/Direct2d/LineJoin.cs | 8 +- .../Direct2d/LtrbRectangleF.cs | 20 +- .../Direct2d/Native/Imports.cs | 23 - src/WInterop.DirectX/Direct2d/PathGeometry.cs | 69 ++ src/WInterop.DirectX/Direct2d/PathSegment.cs | 6 +- src/WInterop.DirectX/Direct2d/PixelFormat.cs | 12 +- .../Direct2d/RadialGradientBrush.cs | 98 +++ .../Direct2d/RadialGradientBrushProperties.cs | 10 +- .../Direct2d/RectangleGeometry.cs | 45 ++ src/WInterop.DirectX/Direct2d/RenderTarget.cs | 295 +++++++ .../Direct2d/RenderTargetExtensions.cs | 59 ++ .../Direct2d/RenderTargetProperties.cs | 8 + src/WInterop.DirectX/Direct2d/Resource.cs | 63 ++ .../Direct2d/RoundedRectangle.cs | 8 +- .../Direct2d/RoundedRectangleGeometry.cs | 48 ++ .../Direct2d/SimplifiedGeometrySink.cs | 82 ++ src/WInterop.DirectX/Direct2d/SizeU.cs | 13 +- .../Direct2d/SolidColorBrush.cs | 48 ++ src/WInterop.DirectX/Direct2d/StrokeStyle.cs | 70 ++ .../Direct2d/SweepDirection.cs | 4 +- src/WInterop.DirectX/Direct2d/Tags.cs | 11 + .../Direct2d/TransformedGeometry.cs | 63 ++ .../Direct2d/WindowRenderTarget.cs | 26 + .../Direct2d/WindowRenderTargetProperties.cs | 2 + .../DirectWrite/DirectWrite.cs | 4 +- .../DirectWrite/FlowDirection.cs | 8 +- src/WInterop.DirectX/DirectWrite/Font.cs | 151 ++++ .../DirectWrite/FontCollection.cs | 79 ++ src/WInterop.DirectX/DirectWrite/FontFace.cs | 358 +++++++++ .../DirectWrite/FontFaceType.cs | 16 +- .../DirectWrite/FontFamily.cs | 90 +++ .../DirectWrite/FontFeatureTag.cs | 162 ++-- src/WInterop.DirectX/DirectWrite/FontList.cs | 63 ++ .../DirectWrite/FontSimulations.cs | 6 +- src/WInterop.DirectX/DirectWrite/GlyphRun.cs | 16 +- .../DirectWrite/HitTestMetrics.cs | 8 +- src/WInterop.DirectX/DirectWrite/IFactory.cs | 386 ---------- src/WInterop.DirectX/DirectWrite/IFont.cs | 97 --- .../DirectWrite/IFontCollection.cs | 46 -- src/WInterop.DirectX/DirectWrite/IFontFace.cs | 260 ------- .../DirectWrite/IFontFamily.cs | 64 -- src/WInterop.DirectX/DirectWrite/IFontList.cs | 35 - .../DirectWrite/IInlineObject.cs | 68 -- .../DirectWrite/ILocalizedStrings.cs | 77 -- .../DirectWrite/IPixelSnapping.cs | 42 - .../DirectWrite/IRenderingParams.cs | 51 -- .../DirectWrite/ITextFormat.cs | 210 ----- .../DirectWrite/ITextLayout.cs | 710 ----------------- .../DirectWrite/ITextRenderer.cs | 160 ---- .../DirectWrite/ITypography.cs | 38 - .../DirectWrite/InformationalStringId.cs | 44 +- .../DirectWrite/InlineObject.cs | 115 +++ .../DirectWrite/LineSpacingMethod.cs | 6 +- .../DirectWrite/LocalizedStrings.cs | 100 +++ .../DirectWrite/ManagedTextRenderer.cs | 246 ++++++ .../DirectWrite/Native/Imports.cs | 2 +- .../DirectWrite/ParagraphAlignment.cs | 6 +- .../DirectWrite/PixelGeometry.cs | 6 +- .../DirectWrite/PixelSnapping.cs | 74 ++ .../DirectWrite/RenderingMode.cs | 14 +- .../DirectWrite/RenderingParams.cs | 63 ++ .../DirectWrite/TextAlignment.cs | 8 +- .../DirectWrite/TextFormat.cs | 238 ++++++ .../DirectWrite/TextLayout.cs | 718 ++++++++++++++++++ src/WInterop.DirectX/DirectWrite/TextRange.cs | 10 +- .../DirectWrite/TextRenderer.cs | 207 +++++ .../DirectWrite/TrimmingGranularity.cs | 6 +- .../DirectWrite/Typography.cs | 60 ++ .../DirectWrite/WordWrapping.cs | 10 +- .../DirectWrite/WriteFactory.cs | 484 ++++++++++++ .../DirectX/DirectXWindowClass.cs | 28 +- src/WInterop.DirectX/Dxgi/Format.cs | 10 +- src/WInterop.DirectX/GlobalUsings.cs | 1 + src/WInterop.DirectX/IHandle.cs | 12 + src/WInterop.DirectX/InteropExtensions.cs | 43 ++ src/WInterop.DirectX/WInterop.Direct2d.csproj | 4 + 151 files changed, 6169 insertions(+), 6575 deletions(-) create mode 100644 src/Samples/CoreWindows/Direct2dDemo/CombineGeometries.cs delete mode 100644 src/Samples/CoreWindows/DirectWriteDemo/CustomTextRenderer.cs create mode 100644 src/Samples/CoreWindows/DirectWriteDemo/SampleTextRenderer.cs delete mode 100644 src/Tests/WInterop.Tests/Direct2d/Factory.cs create mode 100644 src/Tests/WInterop.Tests/Direct2d/FactoryTests.cs create mode 100644 src/WInterop.DirectX/Direct2d/Bitmap.cs create mode 100644 src/WInterop.DirectX/Direct2d/BitmapBrush.cs create mode 100644 src/WInterop.DirectX/Direct2d/BitmapRenderTarget.cs create mode 100644 src/WInterop.DirectX/Direct2d/Brush.cs create mode 100644 src/WInterop.DirectX/Direct2d/EllipseGeometry.cs create mode 100644 src/WInterop.DirectX/Direct2d/Factory.cs create mode 100644 src/WInterop.DirectX/Direct2d/Geometry.cs create mode 100644 src/WInterop.DirectX/Direct2d/GeometryGroup.cs create mode 100644 src/WInterop.DirectX/Direct2d/GeometrySink.cs create mode 100644 src/WInterop.DirectX/Direct2d/GradientStopCollection.cs delete mode 100644 src/WInterop.DirectX/Direct2d/IBitmap.cs delete mode 100644 src/WInterop.DirectX/Direct2d/IBitmapBrush.cs delete mode 100644 src/WInterop.DirectX/Direct2d/IBrush.cs delete mode 100644 src/WInterop.DirectX/Direct2d/IEllipseGeometry.cs delete mode 100644 src/WInterop.DirectX/Direct2d/IFactory.cs delete mode 100644 src/WInterop.DirectX/Direct2d/IGeometry.cs delete mode 100644 src/WInterop.DirectX/Direct2d/IGeometryGroup.cs delete mode 100644 src/WInterop.DirectX/Direct2d/IGeometrySink.cs delete mode 100644 src/WInterop.DirectX/Direct2d/IGradientStopCollection.cs delete mode 100644 src/WInterop.DirectX/Direct2d/IImage.cs delete mode 100644 src/WInterop.DirectX/Direct2d/IPathGeometry.cs delete mode 100644 src/WInterop.DirectX/Direct2d/IRadialGradientBrush.cs delete mode 100644 src/WInterop.DirectX/Direct2d/IRectangleGeometry.cs delete mode 100644 src/WInterop.DirectX/Direct2d/IResource.cs delete mode 100644 src/WInterop.DirectX/Direct2d/IRoundedRectangleGeometry.cs delete mode 100644 src/WInterop.DirectX/Direct2d/ISimplifiedGeometrySink.cs delete mode 100644 src/WInterop.DirectX/Direct2d/ISolidColorBrush.cs delete mode 100644 src/WInterop.DirectX/Direct2d/IStrokeStyle.cs delete mode 100644 src/WInterop.DirectX/Direct2d/ITransformedGeometry.cs create mode 100644 src/WInterop.DirectX/Direct2d/Image.cs delete mode 100644 src/WInterop.DirectX/Direct2d/Native/Imports.cs create mode 100644 src/WInterop.DirectX/Direct2d/PathGeometry.cs create mode 100644 src/WInterop.DirectX/Direct2d/RadialGradientBrush.cs create mode 100644 src/WInterop.DirectX/Direct2d/RectangleGeometry.cs create mode 100644 src/WInterop.DirectX/Direct2d/RenderTarget.cs create mode 100644 src/WInterop.DirectX/Direct2d/RenderTargetExtensions.cs create mode 100644 src/WInterop.DirectX/Direct2d/Resource.cs create mode 100644 src/WInterop.DirectX/Direct2d/RoundedRectangleGeometry.cs create mode 100644 src/WInterop.DirectX/Direct2d/SimplifiedGeometrySink.cs create mode 100644 src/WInterop.DirectX/Direct2d/SolidColorBrush.cs create mode 100644 src/WInterop.DirectX/Direct2d/StrokeStyle.cs create mode 100644 src/WInterop.DirectX/Direct2d/Tags.cs create mode 100644 src/WInterop.DirectX/Direct2d/TransformedGeometry.cs create mode 100644 src/WInterop.DirectX/Direct2d/WindowRenderTarget.cs create mode 100644 src/WInterop.DirectX/DirectWrite/Font.cs create mode 100644 src/WInterop.DirectX/DirectWrite/FontCollection.cs create mode 100644 src/WInterop.DirectX/DirectWrite/FontFace.cs create mode 100644 src/WInterop.DirectX/DirectWrite/FontFamily.cs create mode 100644 src/WInterop.DirectX/DirectWrite/FontList.cs delete mode 100644 src/WInterop.DirectX/DirectWrite/IFactory.cs delete mode 100644 src/WInterop.DirectX/DirectWrite/IFont.cs delete mode 100644 src/WInterop.DirectX/DirectWrite/IFontCollection.cs delete mode 100644 src/WInterop.DirectX/DirectWrite/IFontFace.cs delete mode 100644 src/WInterop.DirectX/DirectWrite/IFontFamily.cs delete mode 100644 src/WInterop.DirectX/DirectWrite/IFontList.cs delete mode 100644 src/WInterop.DirectX/DirectWrite/IInlineObject.cs delete mode 100644 src/WInterop.DirectX/DirectWrite/ILocalizedStrings.cs delete mode 100644 src/WInterop.DirectX/DirectWrite/IPixelSnapping.cs delete mode 100644 src/WInterop.DirectX/DirectWrite/IRenderingParams.cs delete mode 100644 src/WInterop.DirectX/DirectWrite/ITextFormat.cs delete mode 100644 src/WInterop.DirectX/DirectWrite/ITextLayout.cs delete mode 100644 src/WInterop.DirectX/DirectWrite/ITextRenderer.cs delete mode 100644 src/WInterop.DirectX/DirectWrite/ITypography.cs create mode 100644 src/WInterop.DirectX/DirectWrite/InlineObject.cs create mode 100644 src/WInterop.DirectX/DirectWrite/LocalizedStrings.cs create mode 100644 src/WInterop.DirectX/DirectWrite/ManagedTextRenderer.cs create mode 100644 src/WInterop.DirectX/DirectWrite/PixelSnapping.cs create mode 100644 src/WInterop.DirectX/DirectWrite/RenderingParams.cs create mode 100644 src/WInterop.DirectX/DirectWrite/TextFormat.cs create mode 100644 src/WInterop.DirectX/DirectWrite/TextLayout.cs create mode 100644 src/WInterop.DirectX/DirectWrite/TextRenderer.cs create mode 100644 src/WInterop.DirectX/DirectWrite/Typography.cs create mode 100644 src/WInterop.DirectX/DirectWrite/WriteFactory.cs create mode 100644 src/WInterop.DirectX/GlobalUsings.cs create mode 100644 src/WInterop.DirectX/IHandle.cs create mode 100644 src/WInterop.DirectX/InteropExtensions.cs 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 + + +